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