4 * Copyright (C) 2012-2017 Red Hat, Inc.
5 * Copyright IBM, Corp. 2011
8 * Anthony Liguori <aliguori@us.ibm.com>
10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
11 * See the COPYING.LIB file in the top-level directory.
15 #include "qemu/osdep.h"
17 #include "qapi/compat-policy.h"
18 #include "qapi/error.h"
19 #include "qapi/qobject-input-visitor.h"
20 #include "qapi/visitor-impl.h"
21 #include "qemu/queue.h"
22 #include "qapi/qmp/qjson.h"
23 #include "qapi/qmp/qbool.h"
24 #include "qapi/qmp/qdict.h"
25 #include "qapi/qmp/qerror.h"
26 #include "qapi/qmp/qlist.h"
27 #include "qapi/qmp/qnull.h"
28 #include "qapi/qmp/qnum.h"
29 #include "qapi/qmp/qstring.h"
30 #include "qemu/cutils.h"
31 #include "qemu/option.h"
33 typedef struct StackObject
{
34 const char *name
; /* Name of @obj in its parent, if any */
35 QObject
*obj
; /* QDict or QList being visited */
36 void *qapi
; /* sanity check that caller uses same pointer */
38 GHashTable
*h
; /* If @obj is QDict: unvisited keys */
39 const QListEntry
*entry
; /* If @obj is QList: unvisited tail */
40 unsigned index
; /* If @obj is QList: list index of @entry */
42 QSLIST_ENTRY(StackObject
) node
; /* parent */
45 struct QObjectInputVisitor
{
48 /* Root of visit at visitor creation. */
50 bool keyval
; /* Assume @root made with keyval_parse() */
52 /* Stack of objects being visited (all entries will be either
54 QSLIST_HEAD(, StackObject
) stack
;
56 GString
*errname
; /* Accumulator for full_name() */
59 static QObjectInputVisitor
*to_qiv(Visitor
*v
)
61 return container_of(v
, QObjectInputVisitor
, visitor
);
65 * Find the full name of something @qiv is currently visiting.
66 * @qiv is visiting something named @name in the stack of containers
68 * If @n is zero, return its full name.
69 * If @n is positive, return the full name of the @n-th container
70 * counting from the top. The stack of containers must have at least
72 * The returned string is valid until the next full_name_nth(@v) or
75 static const char *full_name_nth(QObjectInputVisitor
*qiv
, const char *name
,
82 g_string_truncate(qiv
->errname
, 0);
84 qiv
->errname
= g_string_new("");
87 QSLIST_FOREACH(so
, &qiv
->stack
, node
) {
90 } else if (qobject_type(so
->obj
) == QTYPE_QDICT
) {
91 g_string_prepend(qiv
->errname
, name
?: "<anonymous>");
92 g_string_prepend_c(qiv
->errname
, '.');
94 snprintf(buf
, sizeof(buf
),
95 qiv
->keyval
? ".%u" : "[%u]",
97 g_string_prepend(qiv
->errname
, buf
);
104 g_string_prepend(qiv
->errname
, name
);
105 } else if (qiv
->errname
->str
[0] == '.') {
106 g_string_erase(qiv
->errname
, 0, 1);
107 } else if (!qiv
->errname
->str
[0]) {
108 return "<anonymous>";
111 return qiv
->errname
->str
;
114 static const char *full_name(QObjectInputVisitor
*qiv
, const char *name
)
116 return full_name_nth(qiv
, name
, 0);
119 static QObject
*qobject_input_try_get_object(QObjectInputVisitor
*qiv
,
127 if (QSLIST_EMPTY(&qiv
->stack
)) {
128 /* Starting at root, name is ignored. */
133 /* We are in a container; find the next element. */
134 tos
= QSLIST_FIRST(&qiv
->stack
);
138 if (qobject_type(qobj
) == QTYPE_QDICT
) {
140 ret
= qdict_get(qobject_to(QDict
, qobj
), name
);
141 if (tos
->h
&& consume
&& ret
) {
142 bool removed
= g_hash_table_remove(tos
->h
, name
);
146 assert(qobject_type(qobj
) == QTYPE_QLIST
);
149 ret
= qlist_entry_obj(tos
->entry
);
151 tos
->entry
= qlist_next(tos
->entry
);
164 static QObject
*qobject_input_get_object(QObjectInputVisitor
*qiv
,
166 bool consume
, Error
**errp
)
168 QObject
*obj
= qobject_input_try_get_object(qiv
, name
, consume
);
171 error_setg(errp
, QERR_MISSING_PARAMETER
, full_name(qiv
, name
));
176 static const char *qobject_input_get_keyval(QObjectInputVisitor
*qiv
,
183 qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
188 qstr
= qobject_to(QString
, qobj
);
190 switch (qobject_type(qobj
)) {
193 error_setg(errp
, "Parameters '%s.*' are unexpected",
194 full_name(qiv
, name
));
197 /* Non-string scalar (should this be an assertion?) */
198 error_setg(errp
, "Internal error: parameter %s invalid",
199 full_name(qiv
, name
));
204 return qstring_get_str(qstr
);
207 static const QListEntry
*qobject_input_push(QObjectInputVisitor
*qiv
,
209 QObject
*obj
, void *qapi
)
212 StackObject
*tos
= g_new0(StackObject
, 1);
213 QDict
*qdict
= qobject_to(QDict
, obj
);
214 QList
*qlist
= qobject_to(QList
, obj
);
215 const QDictEntry
*entry
;
223 h
= g_hash_table_new(g_str_hash
, g_str_equal
);
224 for (entry
= qdict_first(qdict
);
226 entry
= qdict_next(qdict
, entry
)) {
227 g_hash_table_insert(h
, (void *)qdict_entry_key(entry
), NULL
);
232 tos
->entry
= qlist_first(qlist
);
236 QSLIST_INSERT_HEAD(&qiv
->stack
, tos
, node
);
241 static bool qobject_input_check_struct(Visitor
*v
, Error
**errp
)
243 QObjectInputVisitor
*qiv
= to_qiv(v
);
244 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
248 assert(tos
&& !tos
->entry
);
250 g_hash_table_iter_init(&iter
, tos
->h
);
251 if (g_hash_table_iter_next(&iter
, (void **)&key
, NULL
)) {
252 error_setg(errp
, "Parameter '%s' is unexpected",
253 full_name(qiv
, key
));
259 static void qobject_input_stack_object_free(StackObject
*tos
)
262 g_hash_table_unref(tos
->h
);
268 static void qobject_input_pop(Visitor
*v
, void **obj
)
270 QObjectInputVisitor
*qiv
= to_qiv(v
);
271 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
273 assert(tos
&& tos
->qapi
== obj
);
274 QSLIST_REMOVE_HEAD(&qiv
->stack
, node
);
275 qobject_input_stack_object_free(tos
);
278 static bool qobject_input_start_struct(Visitor
*v
, const char *name
, void **obj
,
279 size_t size
, Error
**errp
)
281 QObjectInputVisitor
*qiv
= to_qiv(v
);
282 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
290 if (qobject_type(qobj
) != QTYPE_QDICT
) {
291 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
292 full_name(qiv
, name
), "object");
296 qobject_input_push(qiv
, name
, qobj
, obj
);
299 *obj
= g_malloc0(size
);
304 static void qobject_input_end_struct(Visitor
*v
, void **obj
)
306 QObjectInputVisitor
*qiv
= to_qiv(v
);
307 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
309 assert(qobject_type(tos
->obj
) == QTYPE_QDICT
&& tos
->h
);
310 qobject_input_pop(v
, obj
);
314 static bool qobject_input_start_list(Visitor
*v
, const char *name
,
315 GenericList
**list
, size_t size
,
318 QObjectInputVisitor
*qiv
= to_qiv(v
);
319 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
320 const QListEntry
*entry
;
328 if (qobject_type(qobj
) != QTYPE_QLIST
) {
329 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
330 full_name(qiv
, name
), "array");
334 entry
= qobject_input_push(qiv
, name
, qobj
, list
);
336 *list
= g_malloc0(size
);
341 static GenericList
*qobject_input_next_list(Visitor
*v
, GenericList
*tail
,
344 QObjectInputVisitor
*qiv
= to_qiv(v
);
345 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
347 assert(tos
&& qobject_to(QList
, tos
->obj
));
352 tail
->next
= g_malloc0(size
);
356 static bool qobject_input_check_list(Visitor
*v
, Error
**errp
)
358 QObjectInputVisitor
*qiv
= to_qiv(v
);
359 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
361 assert(tos
&& qobject_to(QList
, tos
->obj
));
364 error_setg(errp
, "Only %u list elements expected in %s",
365 tos
->index
+ 1, full_name_nth(qiv
, NULL
, 1));
371 static void qobject_input_end_list(Visitor
*v
, void **obj
)
373 QObjectInputVisitor
*qiv
= to_qiv(v
);
374 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
376 assert(qobject_type(tos
->obj
) == QTYPE_QLIST
&& !tos
->h
);
377 qobject_input_pop(v
, obj
);
380 static bool qobject_input_start_alternate(Visitor
*v
, const char *name
,
381 GenericAlternate
**obj
, size_t size
,
384 QObjectInputVisitor
*qiv
= to_qiv(v
);
385 QObject
*qobj
= qobject_input_get_object(qiv
, name
, false, errp
);
391 *obj
= g_malloc0(size
);
392 (*obj
)->type
= qobject_type(qobj
);
396 static bool qobject_input_type_int64(Visitor
*v
, const char *name
, int64_t *obj
,
399 QObjectInputVisitor
*qiv
= to_qiv(v
);
400 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
406 qnum
= qobject_to(QNum
, qobj
);
407 if (!qnum
|| !qnum_get_try_int(qnum
, obj
)) {
408 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
409 full_name(qiv
, name
), "integer");
415 static bool qobject_input_type_int64_keyval(Visitor
*v
, const char *name
,
416 int64_t *obj
, Error
**errp
)
418 QObjectInputVisitor
*qiv
= to_qiv(v
);
419 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
425 if (qemu_strtoi64(str
, NULL
, 0, obj
) < 0) {
426 /* TODO report -ERANGE more nicely */
427 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
428 full_name(qiv
, name
), "integer");
434 static bool qobject_input_type_uint64(Visitor
*v
, const char *name
,
435 uint64_t *obj
, Error
**errp
)
437 QObjectInputVisitor
*qiv
= to_qiv(v
);
438 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
445 qnum
= qobject_to(QNum
, qobj
);
450 if (qnum_get_try_uint(qnum
, obj
)) {
454 /* Need to accept negative values for backward compatibility */
455 if (qnum_get_try_int(qnum
, &val
)) {
461 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
462 full_name(qiv
, name
), "uint64");
466 static bool qobject_input_type_uint64_keyval(Visitor
*v
, const char *name
,
467 uint64_t *obj
, Error
**errp
)
469 QObjectInputVisitor
*qiv
= to_qiv(v
);
470 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
476 if (qemu_strtou64(str
, NULL
, 0, obj
) < 0) {
477 /* TODO report -ERANGE more nicely */
478 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
479 full_name(qiv
, name
), "integer");
485 static bool qobject_input_type_bool(Visitor
*v
, const char *name
, bool *obj
,
488 QObjectInputVisitor
*qiv
= to_qiv(v
);
489 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
495 qbool
= qobject_to(QBool
, qobj
);
497 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
498 full_name(qiv
, name
), "boolean");
502 *obj
= qbool_get_bool(qbool
);
506 static bool qobject_input_type_bool_keyval(Visitor
*v
, const char *name
,
507 bool *obj
, Error
**errp
)
509 QObjectInputVisitor
*qiv
= to_qiv(v
);
510 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
516 if (!qapi_bool_parse(name
, str
, obj
, NULL
)) {
517 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
518 full_name(qiv
, name
), "'on' or 'off'");
524 static bool qobject_input_type_str(Visitor
*v
, const char *name
, char **obj
,
527 QObjectInputVisitor
*qiv
= to_qiv(v
);
528 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
535 qstr
= qobject_to(QString
, qobj
);
537 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
538 full_name(qiv
, name
), "string");
542 *obj
= g_strdup(qstring_get_str(qstr
));
546 static bool qobject_input_type_str_keyval(Visitor
*v
, const char *name
,
547 char **obj
, Error
**errp
)
549 QObjectInputVisitor
*qiv
= to_qiv(v
);
550 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
552 *obj
= g_strdup(str
);
556 static bool qobject_input_type_number(Visitor
*v
, const char *name
, double *obj
,
559 QObjectInputVisitor
*qiv
= to_qiv(v
);
560 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
566 qnum
= qobject_to(QNum
, qobj
);
568 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
569 full_name(qiv
, name
), "number");
573 *obj
= qnum_get_double(qnum
);
577 static bool qobject_input_type_number_keyval(Visitor
*v
, const char *name
,
578 double *obj
, Error
**errp
)
580 QObjectInputVisitor
*qiv
= to_qiv(v
);
581 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
588 if (qemu_strtod_finite(str
, NULL
, &val
)) {
589 /* TODO report -ERANGE more nicely */
590 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
591 full_name(qiv
, name
), "number");
599 static bool qobject_input_type_any(Visitor
*v
, const char *name
, QObject
**obj
,
602 QObjectInputVisitor
*qiv
= to_qiv(v
);
603 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
610 *obj
= qobject_ref(qobj
);
614 static bool qobject_input_type_null(Visitor
*v
, const char *name
,
615 QNull
**obj
, Error
**errp
)
617 QObjectInputVisitor
*qiv
= to_qiv(v
);
618 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
625 if (qobject_type(qobj
) != QTYPE_QNULL
) {
626 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
627 full_name(qiv
, name
), "null");
634 static bool qobject_input_type_size_keyval(Visitor
*v
, const char *name
,
635 uint64_t *obj
, Error
**errp
)
637 QObjectInputVisitor
*qiv
= to_qiv(v
);
638 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
644 if (qemu_strtosz(str
, NULL
, obj
) < 0) {
645 /* TODO report -ERANGE more nicely */
646 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
647 full_name(qiv
, name
), "size");
653 static void qobject_input_optional(Visitor
*v
, const char *name
, bool *present
)
655 QObjectInputVisitor
*qiv
= to_qiv(v
);
656 QObject
*qobj
= qobject_input_try_get_object(qiv
, name
, false);
666 static bool qobject_input_policy_reject(Visitor
*v
, const char *name
,
667 unsigned special_features
,
670 return !compat_policy_input_ok(special_features
, &v
->compat_policy
,
671 ERROR_CLASS_GENERIC_ERROR
,
672 "parameter", name
, errp
);
675 static void qobject_input_free(Visitor
*v
)
677 QObjectInputVisitor
*qiv
= to_qiv(v
);
679 while (!QSLIST_EMPTY(&qiv
->stack
)) {
680 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
682 QSLIST_REMOVE_HEAD(&qiv
->stack
, node
);
683 qobject_input_stack_object_free(tos
);
686 qobject_unref(qiv
->root
);
688 g_string_free(qiv
->errname
, TRUE
);
693 static QObjectInputVisitor
*qobject_input_visitor_base_new(QObject
*obj
)
695 QObjectInputVisitor
*v
= g_malloc0(sizeof(*v
));
699 v
->visitor
.type
= VISITOR_INPUT
;
700 v
->visitor
.start_struct
= qobject_input_start_struct
;
701 v
->visitor
.check_struct
= qobject_input_check_struct
;
702 v
->visitor
.end_struct
= qobject_input_end_struct
;
703 v
->visitor
.start_list
= qobject_input_start_list
;
704 v
->visitor
.next_list
= qobject_input_next_list
;
705 v
->visitor
.check_list
= qobject_input_check_list
;
706 v
->visitor
.end_list
= qobject_input_end_list
;
707 v
->visitor
.start_alternate
= qobject_input_start_alternate
;
708 v
->visitor
.optional
= qobject_input_optional
;
709 v
->visitor
.policy_reject
= qobject_input_policy_reject
;
710 v
->visitor
.free
= qobject_input_free
;
712 v
->root
= qobject_ref(obj
);
717 Visitor
*qobject_input_visitor_new(QObject
*obj
)
719 QObjectInputVisitor
*v
= qobject_input_visitor_base_new(obj
);
721 v
->visitor
.type_int64
= qobject_input_type_int64
;
722 v
->visitor
.type_uint64
= qobject_input_type_uint64
;
723 v
->visitor
.type_bool
= qobject_input_type_bool
;
724 v
->visitor
.type_str
= qobject_input_type_str
;
725 v
->visitor
.type_number
= qobject_input_type_number
;
726 v
->visitor
.type_any
= qobject_input_type_any
;
727 v
->visitor
.type_null
= qobject_input_type_null
;
732 Visitor
*qobject_input_visitor_new_keyval(QObject
*obj
)
734 QObjectInputVisitor
*v
= qobject_input_visitor_base_new(obj
);
736 v
->visitor
.type_int64
= qobject_input_type_int64_keyval
;
737 v
->visitor
.type_uint64
= qobject_input_type_uint64_keyval
;
738 v
->visitor
.type_bool
= qobject_input_type_bool_keyval
;
739 v
->visitor
.type_str
= qobject_input_type_str_keyval
;
740 v
->visitor
.type_number
= qobject_input_type_number_keyval
;
741 v
->visitor
.type_any
= qobject_input_type_any
;
742 v
->visitor
.type_null
= qobject_input_type_null
;
743 v
->visitor
.type_size
= qobject_input_type_size_keyval
;
749 Visitor
*qobject_input_visitor_new_str(const char *str
,
750 const char *implied_key
,
753 bool is_json
= str
[0] == '{';
759 obj
= qobject_from_json(str
, errp
);
763 args
= qobject_to(QDict
, obj
);
765 v
= qobject_input_visitor_new(QOBJECT(args
));
767 args
= keyval_parse(str
, implied_key
, NULL
, errp
);
771 v
= qobject_input_visitor_new_keyval(QOBJECT(args
));