]> Git Repo - qemu.git/blame - qapi/qobject-input-visitor.c
qapi: Implement deprecated-input=reject for QMP command arguments
[qemu.git] / qapi / qobject-input-visitor.c
CommitLineData
c40cc0a0
MR
1/*
2 * Input Visitor
3 *
cbd8acf3 4 * Copyright (C) 2012-2017 Red Hat, Inc.
c40cc0a0
MR
5 * Copyright IBM, Corp. 2011
6 *
7 * Authors:
8 * Anthony Liguori <[email protected]>
9 *
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.
12 *
13 */
14
cbf21151 15#include "qemu/osdep.h"
5891c388 16#include <math.h>
db291641 17#include "qapi/compat-policy.h"
da34e65c 18#include "qapi/error.h"
b3db211f 19#include "qapi/qobject-input-visitor.h"
7b1b5d19 20#include "qapi/visitor-impl.h"
1de7afc9 21#include "qemu/queue.h"
9d1eab4b 22#include "qapi/qmp/qjson.h"
6b673957 23#include "qapi/qmp/qbool.h"
452fcdbc 24#include "qapi/qmp/qdict.h"
7b1b5d19 25#include "qapi/qmp/qerror.h"
47e6b297 26#include "qapi/qmp/qlist.h"
15280c36
MA
27#include "qapi/qmp/qnull.h"
28#include "qapi/qmp/qnum.h"
fc81fa1e 29#include "qapi/qmp/qstring.h"
cbd8acf3 30#include "qemu/cutils.h"
9d1eab4b 31#include "qemu/option.h"
c40cc0a0 32
a9fc37f6
MA
33typedef struct StackObject {
34 const char *name; /* Name of @obj in its parent, if any */
35 QObject *obj; /* QDict or QList being visited */
1158bb2a 36 void *qapi; /* sanity check that caller uses same pointer */
b471d012 37
a9fc37f6
MA
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 */
3d344c2a 41
a9fc37f6 42 QSLIST_ENTRY(StackObject) node; /* parent */
c40cc0a0
MR
43} StackObject;
44
a9fc37f6 45struct QObjectInputVisitor {
c40cc0a0 46 Visitor visitor;
db291641 47 CompatPolicyInput deprecated_policy;
b471d012 48
ce140b17
EB
49 /* Root of visit at visitor creation. */
50 QObject *root;
0b2c1bee 51 bool keyval; /* Assume @root made with keyval_parse() */
ce140b17
EB
52
53 /* Stack of objects being visited (all entries will be either
54 * QDict or QList). */
3d344c2a 55 QSLIST_HEAD(, StackObject) stack;
b471d012 56
a9fc37f6 57 GString *errname; /* Accumulator for full_name() */
c40cc0a0
MR
58};
59
09e68369 60static QObjectInputVisitor *to_qiv(Visitor *v)
c40cc0a0 61{
09e68369 62 return container_of(v, QObjectInputVisitor, visitor);
c40cc0a0
MR
63}
64
6c02258e
MA
65/*
66 * Find the full name of something @qiv is currently visiting.
67 * @qiv is visiting something named @name in the stack of containers
68 * @qiv->stack.
69 * If @n is zero, return its full name.
70 * If @n is positive, return the full name of the @n-th container
71 * counting from the top. The stack of containers must have at least
72 * @n elements.
73 * The returned string is valid until the next full_name_nth(@v) or
74 * destruction of @v.
75 */
a4a1c70d
MA
76static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
77 int n)
a9fc37f6
MA
78{
79 StackObject *so;
80 char buf[32];
81
82 if (qiv->errname) {
83 g_string_truncate(qiv->errname, 0);
84 } else {
85 qiv->errname = g_string_new("");
86 }
87
88 QSLIST_FOREACH(so , &qiv->stack, node) {
a4a1c70d
MA
89 if (n) {
90 n--;
91 } else if (qobject_type(so->obj) == QTYPE_QDICT) {
92 g_string_prepend(qiv->errname, name ?: "<anonymous>");
a9fc37f6
MA
93 g_string_prepend_c(qiv->errname, '.');
94 } else {
0b2c1bee
MA
95 snprintf(buf, sizeof(buf),
96 qiv->keyval ? ".%u" : "[%u]",
97 so->index);
a9fc37f6
MA
98 g_string_prepend(qiv->errname, buf);
99 }
100 name = so->name;
101 }
a4a1c70d 102 assert(!n);
a9fc37f6
MA
103
104 if (name) {
105 g_string_prepend(qiv->errname, name);
106 } else if (qiv->errname->str[0] == '.') {
107 g_string_erase(qiv->errname, 0, 1);
a4a1c70d 108 } else if (!qiv->errname->str[0]) {
a9fc37f6
MA
109 return "<anonymous>";
110 }
111
112 return qiv->errname->str;
113}
114
a4a1c70d
MA
115static const char *full_name(QObjectInputVisitor *qiv, const char *name)
116{
117 return full_name_nth(qiv, name, 0);
118}
119
a9fc37f6
MA
120static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
121 const char *name,
122 bool consume)
c40cc0a0 123{
ce140b17
EB
124 StackObject *tos;
125 QObject *qobj;
e5826a2f 126 QObject *ret;
b471d012 127
3d344c2a 128 if (QSLIST_EMPTY(&qiv->stack)) {
ce140b17 129 /* Starting at root, name is ignored. */
5d0cbbcf 130 assert(qiv->root);
ce140b17
EB
131 return qiv->root;
132 }
133
134 /* We are in a container; find the next element. */
3d344c2a 135 tos = QSLIST_FIRST(&qiv->stack);
ce140b17 136 qobj = tos->obj;
b471d012
EB
137 assert(qobj);
138
ce140b17
EB
139 if (qobject_type(qobj) == QTYPE_QDICT) {
140 assert(name);
7dc847eb 141 ret = qdict_get(qobject_to(QDict, qobj), name);
e5826a2f
EB
142 if (tos->h && consume && ret) {
143 bool removed = g_hash_table_remove(tos->h, name);
144 assert(removed);
47c6d3ec 145 }
ce140b17 146 } else {
b471d012 147 assert(qobject_type(qobj) == QTYPE_QLIST);
ce140b17 148 assert(!name);
1f41a645
MA
149 if (tos->entry) {
150 ret = qlist_entry_obj(tos->entry);
151 if (consume) {
152 tos->entry = qlist_next(tos->entry);
153 }
154 } else {
155 ret = NULL;
156 }
fcf3cb21 157 if (consume) {
a9fc37f6 158 tos->index++;
fcf3cb21 159 }
c40cc0a0
MR
160 }
161
ce140b17 162 return ret;
c40cc0a0
MR
163}
164
a9fc37f6
MA
165static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
166 const char *name,
167 bool consume, Error **errp)
168{
169 QObject *obj = qobject_input_try_get_object(qiv, name, consume);
170
171 if (!obj) {
172 error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name));
173 }
174 return obj;
175}
176
e3934b42
MA
177static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv,
178 const char *name,
179 Error **errp)
180{
181 QObject *qobj;
182 QString *qstr;
183
184 qobj = qobject_input_get_object(qiv, name, true, errp);
185 if (!qobj) {
186 return NULL;
187 }
188
7dc847eb 189 qstr = qobject_to(QString, qobj);
e3934b42 190 if (!qstr) {
31478f26
MA
191 switch (qobject_type(qobj)) {
192 case QTYPE_QDICT:
193 case QTYPE_QLIST:
194 error_setg(errp, "Parameters '%s.*' are unexpected",
195 full_name(qiv, name));
196 return NULL;
197 default:
198 /* Non-string scalar (should this be an assertion?) */
199 error_setg(errp, "Internal error: parameter %s invalid",
200 full_name(qiv, name));
201 return NULL;
202 }
e3934b42
MA
203 }
204
205 return qstring_get_str(qstr);
206}
207
09e68369 208static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
a9fc37f6 209 const char *name,
b8874fbf 210 QObject *obj, void *qapi)
c40cc0a0 211{
e38ac962 212 GHashTable *h;
3d344c2a 213 StackObject *tos = g_new0(StackObject, 1);
7b1cd1c6
MA
214 QDict *qdict = qobject_to(QDict, obj);
215 QList *qlist = qobject_to(QList, obj);
216 const QDictEntry *entry;
c40cc0a0 217
b471d012 218 assert(obj);
a9fc37f6 219 tos->name = name;
b471d012 220 tos->obj = obj;
1158bb2a 221 tos->qapi = qapi;
e38ac962 222
7b1cd1c6 223 if (qdict) {
e38ac962 224 h = g_hash_table_new(g_str_hash, g_str_equal);
7b1cd1c6
MA
225 for (entry = qdict_first(qdict);
226 entry;
227 entry = qdict_next(qdict, entry)) {
228 g_hash_table_insert(h, (void *)qdict_entry_key(entry), NULL);
229 }
b471d012 230 tos->h = h;
048abb7b 231 } else {
7b1cd1c6
MA
232 assert(qlist);
233 tos->entry = qlist_first(qlist);
a9fc37f6 234 tos->index = -1;
e38ac962
PB
235 }
236
3d344c2a 237 QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
d9f62dde 238 return tos->entry;
c40cc0a0
MR
239}
240
57a33d89 241
012d4c96 242static bool qobject_input_check_struct(Visitor *v, Error **errp)
c40cc0a0 243{
09e68369 244 QObjectInputVisitor *qiv = to_qiv(v);
3d344c2a 245 StackObject *tos = QSLIST_FIRST(&qiv->stack);
048abb7b
MA
246 GHashTableIter iter;
247 const char *key;
e38ac962 248
3d344c2a 249 assert(tos && !tos->entry);
048abb7b
MA
250
251 g_hash_table_iter_init(&iter, tos->h);
252 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
253 error_setg(errp, "Parameter '%s' is unexpected",
254 full_name(qiv, key));
012d4c96 255 return false;
15c2f669 256 }
012d4c96 257 return true;
15c2f669
EB
258}
259
09e68369 260static void qobject_input_stack_object_free(StackObject *tos)
15c2f669 261{
3d344c2a
PB
262 if (tos->h) {
263 g_hash_table_unref(tos->h);
264 }
15c2f669 265
3d344c2a
PB
266 g_free(tos);
267}
15c2f669 268
09e68369 269static void qobject_input_pop(Visitor *v, void **obj)
3d344c2a 270{
09e68369 271 QObjectInputVisitor *qiv = to_qiv(v);
3d344c2a 272 StackObject *tos = QSLIST_FIRST(&qiv->stack);
e38ac962 273
3d344c2a
PB
274 assert(tos && tos->qapi == obj);
275 QSLIST_REMOVE_HEAD(&qiv->stack, node);
09e68369 276 qobject_input_stack_object_free(tos);
c40cc0a0
MR
277}
278
012d4c96 279static bool qobject_input_start_struct(Visitor *v, const char *name, void **obj,
09e68369 280 size_t size, Error **errp)
c40cc0a0 281{
09e68369
DB
282 QObjectInputVisitor *qiv = to_qiv(v);
283 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
c40cc0a0 284
e58d695e
EB
285 if (obj) {
286 *obj = NULL;
287 }
1382d4ab 288 if (!qobj) {
012d4c96 289 return false;
1382d4ab
MAL
290 }
291 if (qobject_type(qobj) != QTYPE_QDICT) {
a9fc37f6
MA
292 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
293 full_name(qiv, name), "object");
012d4c96 294 return false;
c40cc0a0
MR
295 }
296
a9fc37f6 297 qobject_input_push(qiv, name, qobj, obj);
c40cc0a0
MR
298
299 if (obj) {
7267c094 300 *obj = g_malloc0(size);
c40cc0a0 301 }
012d4c96 302 return true;
c40cc0a0
MR
303}
304
8b2e41d7
MA
305static void qobject_input_end_struct(Visitor *v, void **obj)
306{
307 QObjectInputVisitor *qiv = to_qiv(v);
308 StackObject *tos = QSLIST_FIRST(&qiv->stack);
309
310 assert(qobject_type(tos->obj) == QTYPE_QDICT && tos->h);
311 qobject_input_pop(v, obj);
312}
313
c40cc0a0 314
012d4c96 315static bool qobject_input_start_list(Visitor *v, const char *name,
09e68369
DB
316 GenericList **list, size_t size,
317 Error **errp)
c40cc0a0 318{
09e68369
DB
319 QObjectInputVisitor *qiv = to_qiv(v);
320 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
d9f62dde 321 const QListEntry *entry;
c40cc0a0 322
58561c27
MA
323 if (list) {
324 *list = NULL;
325 }
1382d4ab 326 if (!qobj) {
012d4c96 327 return false;
1382d4ab
MAL
328 }
329 if (qobject_type(qobj) != QTYPE_QLIST) {
a9fc37f6
MA
330 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
331 full_name(qiv, name), "array");
012d4c96 332 return false;
c40cc0a0
MR
333 }
334
a9fc37f6 335 entry = qobject_input_push(qiv, name, qobj, list);
58561c27
MA
336 if (entry && list) {
337 *list = g_malloc0(size);
d9f62dde 338 }
012d4c96 339 return true;
c40cc0a0
MR
340}
341
09e68369
DB
342static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
343 size_t size)
c40cc0a0 344{
09e68369 345 QObjectInputVisitor *qiv = to_qiv(v);
a4a1c70d
MA
346 StackObject *tos = QSLIST_FIRST(&qiv->stack);
347
532fb532 348 assert(tos && qobject_to(QList, tos->obj));
c40cc0a0 349
a4a1c70d 350 if (!tos->entry) {
c40cc0a0
MR
351 return NULL;
352 }
d9f62dde
EB
353 tail->next = g_malloc0(size);
354 return tail->next;
c40cc0a0
MR
355}
356
012d4c96 357static bool qobject_input_check_list(Visitor *v, Error **errp)
a4a1c70d
MA
358{
359 QObjectInputVisitor *qiv = to_qiv(v);
360 StackObject *tos = QSLIST_FIRST(&qiv->stack);
361
532fb532 362 assert(tos && qobject_to(QList, tos->obj));
a4a1c70d
MA
363
364 if (tos->entry) {
365 error_setg(errp, "Only %u list elements expected in %s",
366 tos->index + 1, full_name_nth(qiv, NULL, 1));
012d4c96 367 return false;
a4a1c70d 368 }
012d4c96 369 return true;
a4a1c70d
MA
370}
371
8b2e41d7
MA
372static void qobject_input_end_list(Visitor *v, void **obj)
373{
374 QObjectInputVisitor *qiv = to_qiv(v);
375 StackObject *tos = QSLIST_FIRST(&qiv->stack);
376
377 assert(qobject_type(tos->obj) == QTYPE_QLIST && !tos->h);
378 qobject_input_pop(v, obj);
379}
c40cc0a0 380
012d4c96 381static bool qobject_input_start_alternate(Visitor *v, const char *name,
09e68369 382 GenericAlternate **obj, size_t size,
60390d2d 383 Error **errp)
69dd62df 384{
09e68369
DB
385 QObjectInputVisitor *qiv = to_qiv(v);
386 QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
69dd62df
KW
387
388 if (!qobj) {
dbf11922 389 *obj = NULL;
012d4c96 390 return false;
69dd62df 391 }
dbf11922
EB
392 *obj = g_malloc0(size);
393 (*obj)->type = qobject_type(qobj);
012d4c96 394 return true;
69dd62df
KW
395}
396
012d4c96 397static bool qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
09e68369 398 Error **errp)
c40cc0a0 399{
09e68369
DB
400 QObjectInputVisitor *qiv = to_qiv(v);
401 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
01b2ffce 402 QNum *qnum;
c40cc0a0 403
1382d4ab 404 if (!qobj) {
012d4c96 405 return false;
1382d4ab 406 }
7dc847eb 407 qnum = qobject_to(QNum, qobj);
01b2ffce 408 if (!qnum || !qnum_get_try_int(qnum, obj)) {
a9fc37f6
MA
409 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
410 full_name(qiv, name), "integer");
012d4c96 411 return false;
c40cc0a0 412 }
012d4c96 413 return true;
c40cc0a0
MR
414}
415
012d4c96 416static bool qobject_input_type_int64_keyval(Visitor *v, const char *name,
cbd8acf3
DB
417 int64_t *obj, Error **errp)
418{
419 QObjectInputVisitor *qiv = to_qiv(v);
e3934b42 420 const char *str = qobject_input_get_keyval(qiv, name, errp);
cbd8acf3 421
e3934b42 422 if (!str) {
012d4c96 423 return false;
cbd8acf3
DB
424 }
425
e3934b42 426 if (qemu_strtoi64(str, NULL, 0, obj) < 0) {
cbd8acf3
DB
427 /* TODO report -ERANGE more nicely */
428 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
429 full_name(qiv, name), "integer");
012d4c96 430 return false;
cbd8acf3 431 }
012d4c96 432 return true;
cbd8acf3
DB
433}
434
012d4c96 435static bool qobject_input_type_uint64(Visitor *v, const char *name,
09e68369 436 uint64_t *obj, Error **errp)
f755dea7 437{
09e68369
DB
438 QObjectInputVisitor *qiv = to_qiv(v);
439 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
01b2ffce
MAL
440 QNum *qnum;
441 int64_t val;
f755dea7 442
1382d4ab 443 if (!qobj) {
012d4c96 444 return false;
1382d4ab 445 }
7dc847eb 446 qnum = qobject_to(QNum, qobj);
5923f85f
MAL
447 if (!qnum) {
448 goto err;
449 }
450
451 if (qnum_get_try_uint(qnum, obj)) {
012d4c96 452 return true;
f755dea7 453 }
5923f85f
MAL
454
455 /* Need to accept negative values for backward compatibility */
456 if (qnum_get_try_int(qnum, &val)) {
457 *obj = val;
012d4c96 458 return true;
5923f85f
MAL
459 }
460
461err:
462 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
463 full_name(qiv, name), "uint64");
012d4c96 464 return false;
f755dea7
EB
465}
466
012d4c96 467static bool qobject_input_type_uint64_keyval(Visitor *v, const char *name,
cbd8acf3
DB
468 uint64_t *obj, Error **errp)
469{
470 QObjectInputVisitor *qiv = to_qiv(v);
e3934b42 471 const char *str = qobject_input_get_keyval(qiv, name, errp);
cbd8acf3 472
e3934b42 473 if (!str) {
012d4c96 474 return false;
cbd8acf3
DB
475 }
476
e3934b42 477 if (qemu_strtou64(str, NULL, 0, obj) < 0) {
cbd8acf3
DB
478 /* TODO report -ERANGE more nicely */
479 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
480 full_name(qiv, name), "integer");
012d4c96 481 return false;
cbd8acf3 482 }
012d4c96 483 return true;
cbd8acf3
DB
484}
485
012d4c96 486static bool qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
09e68369 487 Error **errp)
c40cc0a0 488{
09e68369
DB
489 QObjectInputVisitor *qiv = to_qiv(v);
490 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
1382d4ab 491 QBool *qbool;
c40cc0a0 492
1382d4ab 493 if (!qobj) {
012d4c96 494 return false;
1382d4ab 495 }
7dc847eb 496 qbool = qobject_to(QBool, qobj);
14b61600 497 if (!qbool) {
a9fc37f6
MA
498 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
499 full_name(qiv, name), "boolean");
012d4c96 500 return false;
c40cc0a0
MR
501 }
502
14b61600 503 *obj = qbool_get_bool(qbool);
012d4c96 504 return true;
c40cc0a0
MR
505}
506
012d4c96 507static bool qobject_input_type_bool_keyval(Visitor *v, const char *name,
cbd8acf3
DB
508 bool *obj, Error **errp)
509{
510 QObjectInputVisitor *qiv = to_qiv(v);
e3934b42 511 const char *str = qobject_input_get_keyval(qiv, name, errp);
cbd8acf3 512
e3934b42 513 if (!str) {
012d4c96 514 return false;
cbd8acf3
DB
515 }
516
372bcb25 517 if (!qapi_bool_parse(name, str, obj, NULL)) {
cbd8acf3
DB
518 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
519 full_name(qiv, name), "'on' or 'off'");
012d4c96 520 return false;
cbd8acf3 521 }
012d4c96 522 return true;
cbd8acf3
DB
523}
524
012d4c96 525static bool qobject_input_type_str(Visitor *v, const char *name, char **obj,
09e68369 526 Error **errp)
c40cc0a0 527{
09e68369
DB
528 QObjectInputVisitor *qiv = to_qiv(v);
529 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
1382d4ab 530 QString *qstr;
c40cc0a0 531
1382d4ab
MAL
532 *obj = NULL;
533 if (!qobj) {
012d4c96 534 return false;
1382d4ab 535 }
7dc847eb 536 qstr = qobject_to(QString, qobj);
7f027843 537 if (!qstr) {
a9fc37f6
MA
538 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
539 full_name(qiv, name), "string");
012d4c96 540 return false;
c40cc0a0
MR
541 }
542
7f027843 543 *obj = g_strdup(qstring_get_str(qstr));
012d4c96 544 return true;
c40cc0a0
MR
545}
546
012d4c96 547static bool qobject_input_type_str_keyval(Visitor *v, const char *name,
31478f26
MA
548 char **obj, Error **errp)
549{
550 QObjectInputVisitor *qiv = to_qiv(v);
551 const char *str = qobject_input_get_keyval(qiv, name, errp);
552
553 *obj = g_strdup(str);
012d4c96 554 return !!str;
31478f26
MA
555}
556
012d4c96 557static bool qobject_input_type_number(Visitor *v, const char *name, double *obj,
09e68369 558 Error **errp)
c40cc0a0 559{
09e68369
DB
560 QObjectInputVisitor *qiv = to_qiv(v);
561 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
01b2ffce 562 QNum *qnum;
c40cc0a0 563
1382d4ab 564 if (!qobj) {
012d4c96 565 return false;
1382d4ab 566 }
7dc847eb 567 qnum = qobject_to(QNum, qobj);
01b2ffce 568 if (!qnum) {
58634047
MAL
569 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
570 full_name(qiv, name), "number");
012d4c96 571 return false;
1ee51876 572 }
fcf73f66 573
01b2ffce 574 *obj = qnum_get_double(qnum);
012d4c96 575 return true;
c40cc0a0
MR
576}
577
012d4c96 578static bool qobject_input_type_number_keyval(Visitor *v, const char *name,
cbd8acf3
DB
579 double *obj, Error **errp)
580{
581 QObjectInputVisitor *qiv = to_qiv(v);
e3934b42 582 const char *str = qobject_input_get_keyval(qiv, name, errp);
e08a5241 583 double val;
cbd8acf3 584
e3934b42 585 if (!str) {
012d4c96 586 return false;
cbd8acf3
DB
587 }
588
e08a5241 589 if (qemu_strtod_finite(str, NULL, &val)) {
cbd8acf3
DB
590 /* TODO report -ERANGE more nicely */
591 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
592 full_name(qiv, name), "number");
012d4c96 593 return false;
cbd8acf3 594 }
e08a5241
DH
595
596 *obj = val;
012d4c96 597 return true;
cbd8acf3
DB
598}
599
012d4c96 600static bool qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
09e68369 601 Error **errp)
28770e05 602{
09e68369
DB
603 QObjectInputVisitor *qiv = to_qiv(v);
604 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
28770e05 605
1382d4ab 606 *obj = NULL;
c4897802 607 if (!qobj) {
012d4c96 608 return false;
c4897802
MAL
609 }
610
f5a74a5a 611 *obj = qobject_ref(qobj);
012d4c96 612 return true;
28770e05
MA
613}
614
012d4c96 615static bool qobject_input_type_null(Visitor *v, const char *name,
d2f95f4d 616 QNull **obj, Error **errp)
3bc97fd5 617{
09e68369
DB
618 QObjectInputVisitor *qiv = to_qiv(v);
619 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
3df016f1 620
d2f95f4d 621 *obj = NULL;
c4897802 622 if (!qobj) {
012d4c96 623 return false;
c4897802
MAL
624 }
625
3df016f1 626 if (qobject_type(qobj) != QTYPE_QNULL) {
a9fc37f6
MA
627 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
628 full_name(qiv, name), "null");
012d4c96 629 return false;
3df016f1 630 }
d2f95f4d 631 *obj = qnull();
012d4c96 632 return true;
3bc97fd5
EB
633}
634
012d4c96 635static bool qobject_input_type_size_keyval(Visitor *v, const char *name,
cbd8acf3
DB
636 uint64_t *obj, Error **errp)
637{
638 QObjectInputVisitor *qiv = to_qiv(v);
e3934b42 639 const char *str = qobject_input_get_keyval(qiv, name, errp);
cbd8acf3 640
e3934b42 641 if (!str) {
012d4c96 642 return false;
cbd8acf3
DB
643 }
644
e3934b42 645 if (qemu_strtosz(str, NULL, obj) < 0) {
cbd8acf3
DB
646 /* TODO report -ERANGE more nicely */
647 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
648 full_name(qiv, name), "size");
012d4c96 649 return false;
cbd8acf3 650 }
012d4c96 651 return true;
cbd8acf3
DB
652}
653
09e68369 654static void qobject_input_optional(Visitor *v, const char *name, bool *present)
c40cc0a0 655{
09e68369 656 QObjectInputVisitor *qiv = to_qiv(v);
a9fc37f6 657 QObject *qobj = qobject_input_try_get_object(qiv, name, false);
c40cc0a0
MR
658
659 if (!qobj) {
660 *present = false;
661 return;
662 }
663
664 *present = true;
665}
666
db291641
MA
667static bool qobject_input_deprecated_accept(Visitor *v, const char *name,
668 Error **errp)
669{
670 QObjectInputVisitor *qiv = to_qiv(v);
671
672 switch (qiv->deprecated_policy) {
673 case COMPAT_POLICY_INPUT_ACCEPT:
674 return true;
675 case COMPAT_POLICY_INPUT_REJECT:
676 error_setg(errp, "Deprecated parameter '%s' disabled by policy",
677 name);
678 return false;
679 default:
680 abort();
681 }
682}
683
09e68369 684static void qobject_input_free(Visitor *v)
2c0ef9f4 685{
09e68369 686 QObjectInputVisitor *qiv = to_qiv(v);
a9fc37f6 687
3d344c2a
PB
688 while (!QSLIST_EMPTY(&qiv->stack)) {
689 StackObject *tos = QSLIST_FIRST(&qiv->stack);
690
691 QSLIST_REMOVE_HEAD(&qiv->stack, node);
09e68369 692 qobject_input_stack_object_free(tos);
3d344c2a 693 }
2c0ef9f4 694
cb3e7f08 695 qobject_unref(qiv->root);
a9fc37f6
MA
696 if (qiv->errname) {
697 g_string_free(qiv->errname, TRUE);
698 }
b70ce101 699 g_free(qiv);
2c0ef9f4
EB
700}
701
abe81bc2 702static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
c40cc0a0 703{
abe81bc2 704 QObjectInputVisitor *v = g_malloc0(sizeof(*v));
c40cc0a0 705
5d0cbbcf 706 assert(obj);
c40cc0a0 707
983f52d4 708 v->visitor.type = VISITOR_INPUT;
09e68369
DB
709 v->visitor.start_struct = qobject_input_start_struct;
710 v->visitor.check_struct = qobject_input_check_struct;
8b2e41d7 711 v->visitor.end_struct = qobject_input_end_struct;
09e68369
DB
712 v->visitor.start_list = qobject_input_start_list;
713 v->visitor.next_list = qobject_input_next_list;
a4a1c70d 714 v->visitor.check_list = qobject_input_check_list;
8b2e41d7 715 v->visitor.end_list = qobject_input_end_list;
09e68369 716 v->visitor.start_alternate = qobject_input_start_alternate;
abe81bc2 717 v->visitor.optional = qobject_input_optional;
db291641 718 v->visitor.deprecated_accept = qobject_input_deprecated_accept;
abe81bc2
MA
719 v->visitor.free = qobject_input_free;
720
f5a74a5a 721 v->root = qobject_ref(obj);
abe81bc2
MA
722
723 return v;
724}
725
726Visitor *qobject_input_visitor_new(QObject *obj)
727{
728 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
729
09e68369
DB
730 v->visitor.type_int64 = qobject_input_type_int64;
731 v->visitor.type_uint64 = qobject_input_type_uint64;
732 v->visitor.type_bool = qobject_input_type_bool;
733 v->visitor.type_str = qobject_input_type_str;
734 v->visitor.type_number = qobject_input_type_number;
735 v->visitor.type_any = qobject_input_type_any;
736 v->visitor.type_null = qobject_input_type_null;
c40cc0a0 737
b70ce101 738 return &v->visitor;
c40cc0a0 739}
cbd8acf3 740
db291641
MA
741void qobject_input_visitor_set_policy(Visitor *v,
742 CompatPolicyInput deprecated)
743{
744 QObjectInputVisitor *qiv = to_qiv(v);
745
746 qiv->deprecated_policy = deprecated;
747}
748
cbd8acf3
DB
749Visitor *qobject_input_visitor_new_keyval(QObject *obj)
750{
abe81bc2 751 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
cbd8acf3 752
cbd8acf3
DB
753 v->visitor.type_int64 = qobject_input_type_int64_keyval;
754 v->visitor.type_uint64 = qobject_input_type_uint64_keyval;
755 v->visitor.type_bool = qobject_input_type_bool_keyval;
31478f26 756 v->visitor.type_str = qobject_input_type_str_keyval;
cbd8acf3
DB
757 v->visitor.type_number = qobject_input_type_number_keyval;
758 v->visitor.type_any = qobject_input_type_any;
759 v->visitor.type_null = qobject_input_type_null;
760 v->visitor.type_size = qobject_input_type_size_keyval;
0b2c1bee 761 v->keyval = true;
cbd8acf3
DB
762
763 return &v->visitor;
764}
9d1eab4b
MA
765
766Visitor *qobject_input_visitor_new_str(const char *str,
767 const char *implied_key,
768 Error **errp)
769{
770 bool is_json = str[0] == '{';
771 QObject *obj;
772 QDict *args;
773 Visitor *v;
774
775 if (is_json) {
776 obj = qobject_from_json(str, errp);
777 if (!obj) {
9d1eab4b
MA
778 return NULL;
779 }
7dc847eb 780 args = qobject_to(QDict, obj);
9d1eab4b
MA
781 assert(args);
782 v = qobject_input_visitor_new(QOBJECT(args));
783 } else {
8bf12c4f 784 args = keyval_parse(str, implied_key, NULL, errp);
9d1eab4b
MA
785 if (!args) {
786 return NULL;
787 }
788 v = qobject_input_visitor_new_keyval(QOBJECT(args));
789 }
cb3e7f08 790 qobject_unref(args);
9d1eab4b
MA
791
792 return v;
793}
This page took 0.631326 seconds and 4 git commands to generate.