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 const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, 207 const char *name, 208 QObject *obj, void *qapi) 209 { 210 GHashTable *h; 211 StackObject *tos = g_new0(StackObject, 1); 212 QDict *qdict = qobject_to(QDict, obj); 213 QList *qlist = qobject_to(QList, obj); 214 const QDictEntry *entry; 215 216 assert(obj); 217 tos->name = name; 218 tos->obj = obj; 219 tos->qapi = qapi; 220 221 if (qdict) { 222 h = g_hash_table_new(g_str_hash, g_str_equal); 223 for (entry = qdict_first(qdict); 224 entry; 225 entry = qdict_next(qdict, entry)) { 226 g_hash_table_insert(h, (void *)qdict_entry_key(entry), NULL); 227 } 228 tos->h = h; 229 } else { 230 assert(qlist); 231 tos->entry = qlist_first(qlist); 232 tos->index = -1; 233 } 234 235 QSLIST_INSERT_HEAD(&qiv->stack, tos, node); 236 return tos->entry; 237 } 238 239 240 static bool qobject_input_check_struct(Visitor *v, Error **errp) 241 { 242 QObjectInputVisitor *qiv = to_qiv(v); 243 StackObject *tos = QSLIST_FIRST(&qiv->stack); 244 GHashTableIter iter; 245 const char *key; 246 247 assert(tos && !tos->entry); 248 249 g_hash_table_iter_init(&iter, tos->h); 250 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) { 251 error_setg(errp, "Parameter '%s' is unexpected", 252 full_name(qiv, key)); 253 return false; 254 } 255 return true; 256 } 257 258 static void qobject_input_stack_object_free(StackObject *tos) 259 { 260 if (tos->h) { 261 g_hash_table_unref(tos->h); 262 } 263 264 g_free(tos); 265 } 266 267 static void qobject_input_pop(Visitor *v, void **obj) 268 { 269 QObjectInputVisitor *qiv = to_qiv(v); 270 StackObject *tos = QSLIST_FIRST(&qiv->stack); 271 272 assert(tos && tos->qapi == obj); 273 QSLIST_REMOVE_HEAD(&qiv->stack, node); 274 qobject_input_stack_object_free(tos); 275 } 276 277 static bool qobject_input_start_struct(Visitor *v, const char *name, void **obj, 278 size_t size, Error **errp) 279 { 280 QObjectInputVisitor *qiv = to_qiv(v); 281 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 282 283 if (obj) { 284 *obj = NULL; 285 } 286 if (!qobj) { 287 return false; 288 } 289 if (qobject_type(qobj) != QTYPE_QDICT) { 290 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 291 full_name(qiv, name), "object"); 292 return false; 293 } 294 295 qobject_input_push(qiv, name, qobj, obj); 296 297 if (obj) { 298 *obj = g_malloc0(size); 299 } 300 return true; 301 } 302 303 static void qobject_input_end_struct(Visitor *v, void **obj) 304 { 305 QObjectInputVisitor *qiv = to_qiv(v); 306 StackObject *tos = QSLIST_FIRST(&qiv->stack); 307 308 assert(qobject_type(tos->obj) == QTYPE_QDICT && tos->h); 309 qobject_input_pop(v, obj); 310 } 311 312 313 static bool qobject_input_start_list(Visitor *v, const char *name, 314 GenericList **list, size_t size, 315 Error **errp) 316 { 317 QObjectInputVisitor *qiv = to_qiv(v); 318 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 319 const QListEntry *entry; 320 321 if (list) { 322 *list = NULL; 323 } 324 if (!qobj) { 325 return false; 326 } 327 if (qobject_type(qobj) != QTYPE_QLIST) { 328 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 329 full_name(qiv, name), "array"); 330 return false; 331 } 332 333 entry = qobject_input_push(qiv, name, qobj, list); 334 if (entry && list) { 335 *list = g_malloc0(size); 336 } 337 return true; 338 } 339 340 static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail, 341 size_t size) 342 { 343 QObjectInputVisitor *qiv = to_qiv(v); 344 StackObject *tos = QSLIST_FIRST(&qiv->stack); 345 346 assert(tos && qobject_to(QList, tos->obj)); 347 348 if (!tos->entry) { 349 return NULL; 350 } 351 tail->next = g_malloc0(size); 352 return tail->next; 353 } 354 355 static bool qobject_input_check_list(Visitor *v, Error **errp) 356 { 357 QObjectInputVisitor *qiv = to_qiv(v); 358 StackObject *tos = QSLIST_FIRST(&qiv->stack); 359 360 assert(tos && qobject_to(QList, tos->obj)); 361 362 if (tos->entry) { 363 error_setg(errp, "Only %u list elements expected in %s", 364 tos->index + 1, full_name_nth(qiv, NULL, 1)); 365 return false; 366 } 367 return true; 368 } 369 370 static void qobject_input_end_list(Visitor *v, void **obj) 371 { 372 QObjectInputVisitor *qiv = to_qiv(v); 373 StackObject *tos = QSLIST_FIRST(&qiv->stack); 374 375 assert(qobject_type(tos->obj) == QTYPE_QLIST && !tos->h); 376 qobject_input_pop(v, obj); 377 } 378 379 static bool qobject_input_start_alternate(Visitor *v, const char *name, 380 GenericAlternate **obj, size_t size, 381 Error **errp) 382 { 383 QObjectInputVisitor *qiv = to_qiv(v); 384 QObject *qobj = qobject_input_get_object(qiv, name, false, errp); 385 386 if (!qobj) { 387 *obj = NULL; 388 return false; 389 } 390 *obj = g_malloc0(size); 391 (*obj)->type = qobject_type(qobj); 392 return true; 393 } 394 395 static bool qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, 396 Error **errp) 397 { 398 QObjectInputVisitor *qiv = to_qiv(v); 399 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 400 QNum *qnum; 401 402 if (!qobj) { 403 return false; 404 } 405 qnum = qobject_to(QNum, qobj); 406 if (!qnum || !qnum_get_try_int(qnum, obj)) { 407 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 408 full_name(qiv, name), "integer"); 409 return false; 410 } 411 return true; 412 } 413 414 static bool qobject_input_type_int64_keyval(Visitor *v, const char *name, 415 int64_t *obj, Error **errp) 416 { 417 QObjectInputVisitor *qiv = to_qiv(v); 418 const char *str = qobject_input_get_keyval(qiv, name, errp); 419 420 if (!str) { 421 return false; 422 } 423 424 if (qemu_strtoi64(str, NULL, 0, obj) < 0) { 425 /* TODO report -ERANGE more nicely */ 426 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 427 full_name(qiv, name), "integer"); 428 return false; 429 } 430 return true; 431 } 432 433 static bool qobject_input_type_uint64(Visitor *v, const char *name, 434 uint64_t *obj, Error **errp) 435 { 436 QObjectInputVisitor *qiv = to_qiv(v); 437 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 438 QNum *qnum; 439 int64_t val; 440 441 if (!qobj) { 442 return false; 443 } 444 qnum = qobject_to(QNum, qobj); 445 if (!qnum) { 446 goto err; 447 } 448 449 if (qnum_get_try_uint(qnum, obj)) { 450 return true; 451 } 452 453 /* Need to accept negative values for backward compatibility */ 454 if (qnum_get_try_int(qnum, &val)) { 455 *obj = val; 456 return true; 457 } 458 459 err: 460 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 461 full_name(qiv, name), "uint64"); 462 return false; 463 } 464 465 static bool qobject_input_type_uint64_keyval(Visitor *v, const char *name, 466 uint64_t *obj, Error **errp) 467 { 468 QObjectInputVisitor *qiv = to_qiv(v); 469 const char *str = qobject_input_get_keyval(qiv, name, errp); 470 471 if (!str) { 472 return false; 473 } 474 475 if (qemu_strtou64(str, NULL, 0, obj) < 0) { 476 /* TODO report -ERANGE more nicely */ 477 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 478 full_name(qiv, name), "integer"); 479 return false; 480 } 481 return true; 482 } 483 484 static bool qobject_input_type_bool(Visitor *v, const char *name, bool *obj, 485 Error **errp) 486 { 487 QObjectInputVisitor *qiv = to_qiv(v); 488 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 489 QBool *qbool; 490 491 if (!qobj) { 492 return false; 493 } 494 qbool = qobject_to(QBool, qobj); 495 if (!qbool) { 496 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 497 full_name(qiv, name), "boolean"); 498 return false; 499 } 500 501 *obj = qbool_get_bool(qbool); 502 return true; 503 } 504 505 static bool qobject_input_type_bool_keyval(Visitor *v, const char *name, 506 bool *obj, Error **errp) 507 { 508 QObjectInputVisitor *qiv = to_qiv(v); 509 const char *str = qobject_input_get_keyval(qiv, name, errp); 510 511 if (!str) { 512 return false; 513 } 514 515 if (!qapi_bool_parse(name, str, obj, NULL)) { 516 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 517 full_name(qiv, name), "'on' or 'off'"); 518 return false; 519 } 520 return true; 521 } 522 523 static bool qobject_input_type_str(Visitor *v, const char *name, char **obj, 524 Error **errp) 525 { 526 QObjectInputVisitor *qiv = to_qiv(v); 527 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 528 QString *qstr; 529 530 *obj = NULL; 531 if (!qobj) { 532 return false; 533 } 534 qstr = qobject_to(QString, qobj); 535 if (!qstr) { 536 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 537 full_name(qiv, name), "string"); 538 return false; 539 } 540 541 *obj = g_strdup(qstring_get_str(qstr)); 542 return true; 543 } 544 545 static bool qobject_input_type_str_keyval(Visitor *v, const char *name, 546 char **obj, Error **errp) 547 { 548 QObjectInputVisitor *qiv = to_qiv(v); 549 const char *str = qobject_input_get_keyval(qiv, name, errp); 550 551 *obj = g_strdup(str); 552 return !!str; 553 } 554 555 static bool qobject_input_type_number(Visitor *v, const char *name, double *obj, 556 Error **errp) 557 { 558 QObjectInputVisitor *qiv = to_qiv(v); 559 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 560 QNum *qnum; 561 562 if (!qobj) { 563 return false; 564 } 565 qnum = qobject_to(QNum, qobj); 566 if (!qnum) { 567 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 568 full_name(qiv, name), "number"); 569 return false; 570 } 571 572 *obj = qnum_get_double(qnum); 573 return true; 574 } 575 576 static bool qobject_input_type_number_keyval(Visitor *v, const char *name, 577 double *obj, Error **errp) 578 { 579 QObjectInputVisitor *qiv = to_qiv(v); 580 const char *str = qobject_input_get_keyval(qiv, name, errp); 581 double val; 582 583 if (!str) { 584 return false; 585 } 586 587 if (qemu_strtod_finite(str, NULL, &val)) { 588 /* TODO report -ERANGE more nicely */ 589 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 590 full_name(qiv, name), "number"); 591 return false; 592 } 593 594 *obj = val; 595 return true; 596 } 597 598 static bool qobject_input_type_any(Visitor *v, const char *name, QObject **obj, 599 Error **errp) 600 { 601 QObjectInputVisitor *qiv = to_qiv(v); 602 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 603 604 *obj = NULL; 605 if (!qobj) { 606 return false; 607 } 608 609 *obj = qobject_ref(qobj); 610 return true; 611 } 612 613 static bool qobject_input_type_null(Visitor *v, const char *name, 614 QNull **obj, Error **errp) 615 { 616 QObjectInputVisitor *qiv = to_qiv(v); 617 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 618 619 *obj = NULL; 620 if (!qobj) { 621 return false; 622 } 623 624 if (qobject_type(qobj) != QTYPE_QNULL) { 625 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 626 full_name(qiv, name), "null"); 627 return false; 628 } 629 *obj = qnull(); 630 return true; 631 } 632 633 static bool qobject_input_type_size_keyval(Visitor *v, const char *name, 634 uint64_t *obj, Error **errp) 635 { 636 QObjectInputVisitor *qiv = to_qiv(v); 637 const char *str = qobject_input_get_keyval(qiv, name, errp); 638 639 if (!str) { 640 return false; 641 } 642 643 if (qemu_strtosz(str, NULL, obj) < 0) { 644 /* TODO report -ERANGE more nicely */ 645 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 646 full_name(qiv, name), "size"); 647 return false; 648 } 649 return true; 650 } 651 652 static void qobject_input_optional(Visitor *v, const char *name, bool *present) 653 { 654 QObjectInputVisitor *qiv = to_qiv(v); 655 QObject *qobj = qobject_input_try_get_object(qiv, name, false); 656 657 if (!qobj) { 658 *present = false; 659 return; 660 } 661 662 *present = true; 663 } 664 665 static void qobject_input_free(Visitor *v) 666 { 667 QObjectInputVisitor *qiv = to_qiv(v); 668 669 while (!QSLIST_EMPTY(&qiv->stack)) { 670 StackObject *tos = QSLIST_FIRST(&qiv->stack); 671 672 QSLIST_REMOVE_HEAD(&qiv->stack, node); 673 qobject_input_stack_object_free(tos); 674 } 675 676 qobject_unref(qiv->root); 677 if (qiv->errname) { 678 g_string_free(qiv->errname, TRUE); 679 } 680 g_free(qiv); 681 } 682 683 static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) 684 { 685 QObjectInputVisitor *v = g_malloc0(sizeof(*v)); 686 687 assert(obj); 688 689 v->visitor.type = VISITOR_INPUT; 690 v->visitor.start_struct = qobject_input_start_struct; 691 v->visitor.check_struct = qobject_input_check_struct; 692 v->visitor.end_struct = qobject_input_end_struct; 693 v->visitor.start_list = qobject_input_start_list; 694 v->visitor.next_list = qobject_input_next_list; 695 v->visitor.check_list = qobject_input_check_list; 696 v->visitor.end_list = qobject_input_end_list; 697 v->visitor.start_alternate = qobject_input_start_alternate; 698 v->visitor.optional = qobject_input_optional; 699 v->visitor.free = qobject_input_free; 700 701 v->root = qobject_ref(obj); 702 703 return v; 704 } 705 706 Visitor *qobject_input_visitor_new(QObject *obj) 707 { 708 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 709 710 v->visitor.type_int64 = qobject_input_type_int64; 711 v->visitor.type_uint64 = qobject_input_type_uint64; 712 v->visitor.type_bool = qobject_input_type_bool; 713 v->visitor.type_str = qobject_input_type_str; 714 v->visitor.type_number = qobject_input_type_number; 715 v->visitor.type_any = qobject_input_type_any; 716 v->visitor.type_null = qobject_input_type_null; 717 718 return &v->visitor; 719 } 720 721 Visitor *qobject_input_visitor_new_keyval(QObject *obj) 722 { 723 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 724 725 v->visitor.type_int64 = qobject_input_type_int64_keyval; 726 v->visitor.type_uint64 = qobject_input_type_uint64_keyval; 727 v->visitor.type_bool = qobject_input_type_bool_keyval; 728 v->visitor.type_str = qobject_input_type_str_keyval; 729 v->visitor.type_number = qobject_input_type_number_keyval; 730 v->visitor.type_any = qobject_input_type_any; 731 v->visitor.type_null = qobject_input_type_null; 732 v->visitor.type_size = qobject_input_type_size_keyval; 733 v->keyval = true; 734 735 return &v->visitor; 736 } 737 738 Visitor *qobject_input_visitor_new_str(const char *str, 739 const char *implied_key, 740 Error **errp) 741 { 742 bool is_json = str[0] == '{'; 743 QObject *obj; 744 QDict *args; 745 Visitor *v; 746 747 if (is_json) { 748 obj = qobject_from_json(str, errp); 749 if (!obj) { 750 return NULL; 751 } 752 args = qobject_to(QDict, obj); 753 assert(args); 754 v = qobject_input_visitor_new(QOBJECT(args)); 755 } else { 756 args = keyval_parse(str, implied_key, NULL, errp); 757 if (!args) { 758 return NULL; 759 } 760 v = qobject_input_visitor_new_keyval(QOBJECT(args)); 761 } 762 qobject_unref(args); 763 764 return v; 765 } 766