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