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 "qemu-common.h" 22 #include "qapi/qmp/qjson.h" 23 #include "qapi/qmp/qbool.h" 24 #include "qapi/qmp/qdict.h" 25 #include "qapi/qmp/qerror.h" 26 #include "qapi/qmp/qlist.h" 27 #include "qapi/qmp/qnull.h" 28 #include "qapi/qmp/qnum.h" 29 #include "qapi/qmp/qstring.h" 30 #include "qemu/cutils.h" 31 #include "qemu/option.h" 32 33 typedef struct StackObject { 34 const char *name; /* Name of @obj in its parent, if any */ 35 QObject *obj; /* QDict or QList being visited */ 36 void *qapi; /* sanity check that caller uses same pointer */ 37 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 */ 41 42 QSLIST_ENTRY(StackObject) node; /* parent */ 43 } StackObject; 44 45 struct QObjectInputVisitor { 46 Visitor visitor; 47 48 /* Root of visit at visitor creation. */ 49 QObject *root; 50 bool keyval; /* Assume @root made with keyval_parse() */ 51 52 /* Stack of objects being visited (all entries will be either 53 * QDict or QList). */ 54 QSLIST_HEAD(, StackObject) stack; 55 56 GString *errname; /* Accumulator for full_name() */ 57 }; 58 59 static QObjectInputVisitor *to_qiv(Visitor *v) 60 { 61 return container_of(v, QObjectInputVisitor, visitor); 62 } 63 64 /* 65 * Find the full name of something @qiv is currently visiting. 66 * @qiv is visiting something named @name in the stack of containers 67 * @qiv->stack. 68 * If @n is zero, return its full name. 69 * If @n is positive, return the full name of the @n-th container 70 * counting from the top. The stack of containers must have at least 71 * @n elements. 72 * The returned string is valid until the next full_name_nth(@v) or 73 * destruction of @v. 74 */ 75 static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name, 76 int n) 77 { 78 StackObject *so; 79 char buf[32]; 80 81 if (qiv->errname) { 82 g_string_truncate(qiv->errname, 0); 83 } else { 84 qiv->errname = g_string_new(""); 85 } 86 87 QSLIST_FOREACH(so , &qiv->stack, node) { 88 if (n) { 89 n--; 90 } else if (qobject_type(so->obj) == QTYPE_QDICT) { 91 g_string_prepend(qiv->errname, name ?: "<anonymous>"); 92 g_string_prepend_c(qiv->errname, '.'); 93 } else { 94 snprintf(buf, sizeof(buf), 95 qiv->keyval ? ".%u" : "[%u]", 96 so->index); 97 g_string_prepend(qiv->errname, buf); 98 } 99 name = so->name; 100 } 101 assert(!n); 102 103 if (name) { 104 g_string_prepend(qiv->errname, name); 105 } else if (qiv->errname->str[0] == '.') { 106 g_string_erase(qiv->errname, 0, 1); 107 } else if (!qiv->errname->str[0]) { 108 return "<anonymous>"; 109 } 110 111 return qiv->errname->str; 112 } 113 114 static const char *full_name(QObjectInputVisitor *qiv, const char *name) 115 { 116 return full_name_nth(qiv, name, 0); 117 } 118 119 static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv, 120 const char *name, 121 bool consume) 122 { 123 StackObject *tos; 124 QObject *qobj; 125 QObject *ret; 126 127 if (QSLIST_EMPTY(&qiv->stack)) { 128 /* Starting at root, name is ignored. */ 129 assert(qiv->root); 130 return qiv->root; 131 } 132 133 /* We are in a container; find the next element. */ 134 tos = QSLIST_FIRST(&qiv->stack); 135 qobj = tos->obj; 136 assert(qobj); 137 138 if (qobject_type(qobj) == QTYPE_QDICT) { 139 assert(name); 140 ret = qdict_get(qobject_to(QDict, qobj), name); 141 if (tos->h && consume && ret) { 142 bool removed = g_hash_table_remove(tos->h, name); 143 assert(removed); 144 } 145 } else { 146 assert(qobject_type(qobj) == QTYPE_QLIST); 147 assert(!name); 148 if (tos->entry) { 149 ret = qlist_entry_obj(tos->entry); 150 if (consume) { 151 tos->entry = qlist_next(tos->entry); 152 } 153 } else { 154 ret = NULL; 155 } 156 if (consume) { 157 tos->index++; 158 } 159 } 160 161 return ret; 162 } 163 164 static QObject *qobject_input_get_object(QObjectInputVisitor *qiv, 165 const char *name, 166 bool consume, Error **errp) 167 { 168 QObject *obj = qobject_input_try_get_object(qiv, name, consume); 169 170 if (!obj) { 171 error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name)); 172 } 173 return obj; 174 } 175 176 static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv, 177 const char *name, 178 Error **errp) 179 { 180 QObject *qobj; 181 QString *qstr; 182 183 qobj = qobject_input_get_object(qiv, name, true, errp); 184 if (!qobj) { 185 return NULL; 186 } 187 188 qstr = qobject_to(QString, qobj); 189 if (!qstr) { 190 switch (qobject_type(qobj)) { 191 case QTYPE_QDICT: 192 case QTYPE_QLIST: 193 error_setg(errp, "Parameters '%s.*' are unexpected", 194 full_name(qiv, name)); 195 return NULL; 196 default: 197 /* Non-string scalar (should this be an assertion?) */ 198 error_setg(errp, "Internal error: parameter %s invalid", 199 full_name(qiv, name)); 200 return NULL; 201 } 202 } 203 204 return qstring_get_str(qstr); 205 } 206 207 static void qdict_add_key(const char *key, QObject *obj, void *opaque) 208 { 209 GHashTable *h = opaque; 210 g_hash_table_insert(h, (gpointer) key, NULL); 211 } 212 213 static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, 214 const char *name, 215 QObject *obj, void *qapi) 216 { 217 GHashTable *h; 218 StackObject *tos = g_new0(StackObject, 1); 219 220 assert(obj); 221 tos->name = name; 222 tos->obj = obj; 223 tos->qapi = qapi; 224 225 if (qobject_type(obj) == QTYPE_QDICT) { 226 h = g_hash_table_new(g_str_hash, g_str_equal); 227 qdict_iter(qobject_to(QDict, obj), qdict_add_key, h); 228 tos->h = h; 229 } else { 230 assert(qobject_type(obj) == QTYPE_QLIST); 231 tos->entry = qlist_first(qobject_to(QList, obj)); 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 char *endp; 566 567 if (!str) { 568 return; 569 } 570 571 errno = 0; 572 *obj = strtod(str, &endp); 573 if (errno || endp == str || *endp || !isfinite(*obj)) { 574 /* TODO report -ERANGE more nicely */ 575 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 576 full_name(qiv, name), "number"); 577 } 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 /* Work around qobject_from_json() lossage TODO fix that */ 729 if (errp && !*errp) { 730 error_setg(errp, "JSON parse error"); 731 return NULL; 732 } 733 return NULL; 734 } 735 args = qobject_to(QDict, obj); 736 assert(args); 737 v = qobject_input_visitor_new(QOBJECT(args)); 738 } else { 739 args = keyval_parse(str, implied_key, errp); 740 if (!args) { 741 return NULL; 742 } 743 v = qobject_input_visitor_new_keyval(QOBJECT(args)); 744 } 745 qobject_unref(args); 746 747 return v; 748 } 749