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