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