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