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 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 } 382 383 static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, 384 Error **errp) 385 { 386 QObjectInputVisitor *qiv = to_qiv(v); 387 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 388 QNum *qnum; 389 390 if (!qobj) { 391 return; 392 } 393 qnum = qobject_to_qnum(qobj); 394 if (!qnum || !qnum_get_try_int(qnum, obj)) { 395 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 396 full_name(qiv, name), "integer"); 397 } 398 } 399 400 static void qobject_input_type_int64_keyval(Visitor *v, const char *name, 401 int64_t *obj, Error **errp) 402 { 403 QObjectInputVisitor *qiv = to_qiv(v); 404 const char *str = qobject_input_get_keyval(qiv, name, errp); 405 406 if (!str) { 407 return; 408 } 409 410 if (qemu_strtoi64(str, NULL, 0, obj) < 0) { 411 /* TODO report -ERANGE more nicely */ 412 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 413 full_name(qiv, name), "integer"); 414 } 415 } 416 417 static void qobject_input_type_uint64(Visitor *v, const char *name, 418 uint64_t *obj, Error **errp) 419 { 420 QObjectInputVisitor *qiv = to_qiv(v); 421 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 422 QNum *qnum; 423 int64_t val; 424 425 if (!qobj) { 426 return; 427 } 428 qnum = qobject_to_qnum(qobj); 429 if (!qnum) { 430 goto err; 431 } 432 433 if (qnum_get_try_uint(qnum, obj)) { 434 return; 435 } 436 437 /* Need to accept negative values for backward compatibility */ 438 if (qnum_get_try_int(qnum, &val)) { 439 *obj = val; 440 return; 441 } 442 443 err: 444 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 445 full_name(qiv, name), "uint64"); 446 } 447 448 static void qobject_input_type_uint64_keyval(Visitor *v, const char *name, 449 uint64_t *obj, Error **errp) 450 { 451 QObjectInputVisitor *qiv = to_qiv(v); 452 const char *str = qobject_input_get_keyval(qiv, name, errp); 453 454 if (!str) { 455 return; 456 } 457 458 if (qemu_strtou64(str, NULL, 0, obj) < 0) { 459 /* TODO report -ERANGE more nicely */ 460 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 461 full_name(qiv, name), "integer"); 462 } 463 } 464 465 static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj, 466 Error **errp) 467 { 468 QObjectInputVisitor *qiv = to_qiv(v); 469 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 470 QBool *qbool; 471 472 if (!qobj) { 473 return; 474 } 475 qbool = qobject_to_qbool(qobj); 476 if (!qbool) { 477 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 478 full_name(qiv, name), "boolean"); 479 return; 480 } 481 482 *obj = qbool_get_bool(qbool); 483 } 484 485 static void qobject_input_type_bool_keyval(Visitor *v, const char *name, 486 bool *obj, Error **errp) 487 { 488 QObjectInputVisitor *qiv = to_qiv(v); 489 const char *str = qobject_input_get_keyval(qiv, name, errp); 490 491 if (!str) { 492 return; 493 } 494 495 if (!strcmp(str, "on")) { 496 *obj = true; 497 } else if (!strcmp(str, "off")) { 498 *obj = false; 499 } else { 500 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 501 full_name(qiv, name), "'on' or 'off'"); 502 } 503 } 504 505 static void qobject_input_type_str(Visitor *v, const char *name, char **obj, 506 Error **errp) 507 { 508 QObjectInputVisitor *qiv = to_qiv(v); 509 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 510 QString *qstr; 511 512 *obj = NULL; 513 if (!qobj) { 514 return; 515 } 516 qstr = qobject_to_qstring(qobj); 517 if (!qstr) { 518 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 519 full_name(qiv, name), "string"); 520 return; 521 } 522 523 *obj = g_strdup(qstring_get_str(qstr)); 524 } 525 526 static void qobject_input_type_str_keyval(Visitor *v, const char *name, 527 char **obj, Error **errp) 528 { 529 QObjectInputVisitor *qiv = to_qiv(v); 530 const char *str = qobject_input_get_keyval(qiv, name, errp); 531 532 *obj = g_strdup(str); 533 } 534 535 static void qobject_input_type_number(Visitor *v, const char *name, double *obj, 536 Error **errp) 537 { 538 QObjectInputVisitor *qiv = to_qiv(v); 539 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 540 QNum *qnum; 541 542 if (!qobj) { 543 return; 544 } 545 qnum = qobject_to_qnum(qobj); 546 if (!qnum) { 547 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 548 full_name(qiv, name), "number"); 549 return; 550 } 551 552 *obj = qnum_get_double(qnum); 553 } 554 555 static void qobject_input_type_number_keyval(Visitor *v, const char *name, 556 double *obj, Error **errp) 557 { 558 QObjectInputVisitor *qiv = to_qiv(v); 559 const char *str = qobject_input_get_keyval(qiv, name, errp); 560 char *endp; 561 562 if (!str) { 563 return; 564 } 565 566 errno = 0; 567 *obj = strtod(str, &endp); 568 if (errno || endp == str || *endp || !isfinite(*obj)) { 569 /* TODO report -ERANGE more nicely */ 570 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 571 full_name(qiv, name), "number"); 572 } 573 } 574 575 static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, 576 Error **errp) 577 { 578 QObjectInputVisitor *qiv = to_qiv(v); 579 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 580 581 *obj = NULL; 582 if (!qobj) { 583 return; 584 } 585 586 qobject_incref(qobj); 587 *obj = qobj; 588 } 589 590 static void qobject_input_type_null(Visitor *v, const char *name, Error **errp) 591 { 592 QObjectInputVisitor *qiv = to_qiv(v); 593 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 594 595 if (!qobj) { 596 return; 597 } 598 599 if (qobject_type(qobj) != QTYPE_QNULL) { 600 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 601 full_name(qiv, name), "null"); 602 } 603 } 604 605 static void qobject_input_type_size_keyval(Visitor *v, const char *name, 606 uint64_t *obj, Error **errp) 607 { 608 QObjectInputVisitor *qiv = to_qiv(v); 609 const char *str = qobject_input_get_keyval(qiv, name, errp); 610 611 if (!str) { 612 return; 613 } 614 615 if (qemu_strtosz(str, NULL, obj) < 0) { 616 /* TODO report -ERANGE more nicely */ 617 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 618 full_name(qiv, name), "size"); 619 } 620 } 621 622 static void qobject_input_optional(Visitor *v, const char *name, bool *present) 623 { 624 QObjectInputVisitor *qiv = to_qiv(v); 625 QObject *qobj = qobject_input_try_get_object(qiv, name, false); 626 627 if (!qobj) { 628 *present = false; 629 return; 630 } 631 632 *present = true; 633 } 634 635 static void qobject_input_free(Visitor *v) 636 { 637 QObjectInputVisitor *qiv = to_qiv(v); 638 639 while (!QSLIST_EMPTY(&qiv->stack)) { 640 StackObject *tos = QSLIST_FIRST(&qiv->stack); 641 642 QSLIST_REMOVE_HEAD(&qiv->stack, node); 643 qobject_input_stack_object_free(tos); 644 } 645 646 qobject_decref(qiv->root); 647 if (qiv->errname) { 648 g_string_free(qiv->errname, TRUE); 649 } 650 g_free(qiv); 651 } 652 653 static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) 654 { 655 QObjectInputVisitor *v = g_malloc0(sizeof(*v)); 656 657 assert(obj); 658 659 v->visitor.type = VISITOR_INPUT; 660 v->visitor.start_struct = qobject_input_start_struct; 661 v->visitor.check_struct = qobject_input_check_struct; 662 v->visitor.end_struct = qobject_input_end_struct; 663 v->visitor.start_list = qobject_input_start_list; 664 v->visitor.next_list = qobject_input_next_list; 665 v->visitor.check_list = qobject_input_check_list; 666 v->visitor.end_list = qobject_input_end_list; 667 v->visitor.start_alternate = qobject_input_start_alternate; 668 v->visitor.optional = qobject_input_optional; 669 v->visitor.free = qobject_input_free; 670 671 v->root = obj; 672 qobject_incref(obj); 673 674 return v; 675 } 676 677 Visitor *qobject_input_visitor_new(QObject *obj) 678 { 679 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 680 681 v->visitor.type_int64 = qobject_input_type_int64; 682 v->visitor.type_uint64 = qobject_input_type_uint64; 683 v->visitor.type_bool = qobject_input_type_bool; 684 v->visitor.type_str = qobject_input_type_str; 685 v->visitor.type_number = qobject_input_type_number; 686 v->visitor.type_any = qobject_input_type_any; 687 v->visitor.type_null = qobject_input_type_null; 688 689 return &v->visitor; 690 } 691 692 Visitor *qobject_input_visitor_new_keyval(QObject *obj) 693 { 694 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 695 696 v->visitor.type_int64 = qobject_input_type_int64_keyval; 697 v->visitor.type_uint64 = qobject_input_type_uint64_keyval; 698 v->visitor.type_bool = qobject_input_type_bool_keyval; 699 v->visitor.type_str = qobject_input_type_str_keyval; 700 v->visitor.type_number = qobject_input_type_number_keyval; 701 v->visitor.type_any = qobject_input_type_any; 702 v->visitor.type_null = qobject_input_type_null; 703 v->visitor.type_size = qobject_input_type_size_keyval; 704 v->keyval = true; 705 706 return &v->visitor; 707 } 708 709 Visitor *qobject_input_visitor_new_str(const char *str, 710 const char *implied_key, 711 Error **errp) 712 { 713 bool is_json = str[0] == '{'; 714 QObject *obj; 715 QDict *args; 716 Visitor *v; 717 718 if (is_json) { 719 obj = qobject_from_json(str, errp); 720 if (!obj) { 721 /* Work around qobject_from_json() lossage TODO fix that */ 722 if (errp && !*errp) { 723 error_setg(errp, "JSON parse error"); 724 return NULL; 725 } 726 return NULL; 727 } 728 args = qobject_to_qdict(obj); 729 assert(args); 730 v = qobject_input_visitor_new(QOBJECT(args)); 731 } else { 732 args = keyval_parse(str, implied_key, errp); 733 if (!args) { 734 return NULL; 735 } 736 v = qobject_input_visitor_new_keyval(QOBJECT(args)); 737 } 738 QDECREF(args); 739 740 return v; 741 } 742