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 (!strcmp(str, "on")) { 516 *obj = true; 517 } else if (!strcmp(str, "off")) { 518 *obj = false; 519 } else { 520 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 521 full_name(qiv, name), "'on' or 'off'"); 522 return false; 523 } 524 return true; 525 } 526 527 static bool qobject_input_type_str(Visitor *v, const char *name, char **obj, 528 Error **errp) 529 { 530 QObjectInputVisitor *qiv = to_qiv(v); 531 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 532 QString *qstr; 533 534 *obj = NULL; 535 if (!qobj) { 536 return false; 537 } 538 qstr = qobject_to(QString, qobj); 539 if (!qstr) { 540 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 541 full_name(qiv, name), "string"); 542 return false; 543 } 544 545 *obj = g_strdup(qstring_get_str(qstr)); 546 return true; 547 } 548 549 static bool qobject_input_type_str_keyval(Visitor *v, const char *name, 550 char **obj, Error **errp) 551 { 552 QObjectInputVisitor *qiv = to_qiv(v); 553 const char *str = qobject_input_get_keyval(qiv, name, errp); 554 555 *obj = g_strdup(str); 556 return !!str; 557 } 558 559 static bool qobject_input_type_number(Visitor *v, const char *name, double *obj, 560 Error **errp) 561 { 562 QObjectInputVisitor *qiv = to_qiv(v); 563 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 564 QNum *qnum; 565 566 if (!qobj) { 567 return false; 568 } 569 qnum = qobject_to(QNum, qobj); 570 if (!qnum) { 571 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 572 full_name(qiv, name), "number"); 573 return false; 574 } 575 576 *obj = qnum_get_double(qnum); 577 return true; 578 } 579 580 static bool qobject_input_type_number_keyval(Visitor *v, const char *name, 581 double *obj, Error **errp) 582 { 583 QObjectInputVisitor *qiv = to_qiv(v); 584 const char *str = qobject_input_get_keyval(qiv, name, errp); 585 double val; 586 587 if (!str) { 588 return false; 589 } 590 591 if (qemu_strtod_finite(str, NULL, &val)) { 592 /* TODO report -ERANGE more nicely */ 593 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 594 full_name(qiv, name), "number"); 595 return false; 596 } 597 598 *obj = val; 599 return true; 600 } 601 602 static bool qobject_input_type_any(Visitor *v, const char *name, QObject **obj, 603 Error **errp) 604 { 605 QObjectInputVisitor *qiv = to_qiv(v); 606 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 607 608 *obj = NULL; 609 if (!qobj) { 610 return false; 611 } 612 613 *obj = qobject_ref(qobj); 614 return true; 615 } 616 617 static bool qobject_input_type_null(Visitor *v, const char *name, 618 QNull **obj, Error **errp) 619 { 620 QObjectInputVisitor *qiv = to_qiv(v); 621 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 622 623 *obj = NULL; 624 if (!qobj) { 625 return false; 626 } 627 628 if (qobject_type(qobj) != QTYPE_QNULL) { 629 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 630 full_name(qiv, name), "null"); 631 return false; 632 } 633 *obj = qnull(); 634 return true; 635 } 636 637 static bool qobject_input_type_size_keyval(Visitor *v, const char *name, 638 uint64_t *obj, Error **errp) 639 { 640 QObjectInputVisitor *qiv = to_qiv(v); 641 const char *str = qobject_input_get_keyval(qiv, name, errp); 642 643 if (!str) { 644 return false; 645 } 646 647 if (qemu_strtosz(str, NULL, obj) < 0) { 648 /* TODO report -ERANGE more nicely */ 649 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 650 full_name(qiv, name), "size"); 651 return false; 652 } 653 return true; 654 } 655 656 static void qobject_input_optional(Visitor *v, const char *name, bool *present) 657 { 658 QObjectInputVisitor *qiv = to_qiv(v); 659 QObject *qobj = qobject_input_try_get_object(qiv, name, false); 660 661 if (!qobj) { 662 *present = false; 663 return; 664 } 665 666 *present = true; 667 } 668 669 static void qobject_input_free(Visitor *v) 670 { 671 QObjectInputVisitor *qiv = to_qiv(v); 672 673 while (!QSLIST_EMPTY(&qiv->stack)) { 674 StackObject *tos = QSLIST_FIRST(&qiv->stack); 675 676 QSLIST_REMOVE_HEAD(&qiv->stack, node); 677 qobject_input_stack_object_free(tos); 678 } 679 680 qobject_unref(qiv->root); 681 if (qiv->errname) { 682 g_string_free(qiv->errname, TRUE); 683 } 684 g_free(qiv); 685 } 686 687 static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) 688 { 689 QObjectInputVisitor *v = g_malloc0(sizeof(*v)); 690 691 assert(obj); 692 693 v->visitor.type = VISITOR_INPUT; 694 v->visitor.start_struct = qobject_input_start_struct; 695 v->visitor.check_struct = qobject_input_check_struct; 696 v->visitor.end_struct = qobject_input_end_struct; 697 v->visitor.start_list = qobject_input_start_list; 698 v->visitor.next_list = qobject_input_next_list; 699 v->visitor.check_list = qobject_input_check_list; 700 v->visitor.end_list = qobject_input_end_list; 701 v->visitor.start_alternate = qobject_input_start_alternate; 702 v->visitor.optional = qobject_input_optional; 703 v->visitor.free = qobject_input_free; 704 705 v->root = qobject_ref(obj); 706 707 return v; 708 } 709 710 Visitor *qobject_input_visitor_new(QObject *obj) 711 { 712 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 713 714 v->visitor.type_int64 = qobject_input_type_int64; 715 v->visitor.type_uint64 = qobject_input_type_uint64; 716 v->visitor.type_bool = qobject_input_type_bool; 717 v->visitor.type_str = qobject_input_type_str; 718 v->visitor.type_number = qobject_input_type_number; 719 v->visitor.type_any = qobject_input_type_any; 720 v->visitor.type_null = qobject_input_type_null; 721 722 return &v->visitor; 723 } 724 725 Visitor *qobject_input_visitor_new_keyval(QObject *obj) 726 { 727 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 728 729 v->visitor.type_int64 = qobject_input_type_int64_keyval; 730 v->visitor.type_uint64 = qobject_input_type_uint64_keyval; 731 v->visitor.type_bool = qobject_input_type_bool_keyval; 732 v->visitor.type_str = qobject_input_type_str_keyval; 733 v->visitor.type_number = qobject_input_type_number_keyval; 734 v->visitor.type_any = qobject_input_type_any; 735 v->visitor.type_null = qobject_input_type_null; 736 v->visitor.type_size = qobject_input_type_size_keyval; 737 v->keyval = true; 738 739 return &v->visitor; 740 } 741 742 Visitor *qobject_input_visitor_new_str(const char *str, 743 const char *implied_key, 744 Error **errp) 745 { 746 bool is_json = str[0] == '{'; 747 QObject *obj; 748 QDict *args; 749 Visitor *v; 750 751 if (is_json) { 752 obj = qobject_from_json(str, errp); 753 if (!obj) { 754 return NULL; 755 } 756 args = qobject_to(QDict, obj); 757 assert(args); 758 v = qobject_input_visitor_new(QOBJECT(args)); 759 } else { 760 args = keyval_parse(str, implied_key, errp); 761 if (!args) { 762 return NULL; 763 } 764 v = qobject_input_visitor_new_keyval(QOBJECT(args)); 765 } 766 qobject_unref(args); 767 768 return v; 769 } 770