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 && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST); 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 && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST); 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 qobject_incref(qobj); 592 *obj = qobj; 593 } 594 595 static void qobject_input_type_null(Visitor *v, const char *name, 596 QNull **obj, Error **errp) 597 { 598 QObjectInputVisitor *qiv = to_qiv(v); 599 QObject *qobj = qobject_input_get_object(qiv, name, true, errp); 600 601 *obj = NULL; 602 if (!qobj) { 603 return; 604 } 605 606 if (qobject_type(qobj) != QTYPE_QNULL) { 607 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, 608 full_name(qiv, name), "null"); 609 return; 610 } 611 *obj = qnull(); 612 } 613 614 static void qobject_input_type_size_keyval(Visitor *v, const char *name, 615 uint64_t *obj, Error **errp) 616 { 617 QObjectInputVisitor *qiv = to_qiv(v); 618 const char *str = qobject_input_get_keyval(qiv, name, errp); 619 620 if (!str) { 621 return; 622 } 623 624 if (qemu_strtosz(str, NULL, obj) < 0) { 625 /* TODO report -ERANGE more nicely */ 626 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 627 full_name(qiv, name), "size"); 628 } 629 } 630 631 static void qobject_input_optional(Visitor *v, const char *name, bool *present) 632 { 633 QObjectInputVisitor *qiv = to_qiv(v); 634 QObject *qobj = qobject_input_try_get_object(qiv, name, false); 635 636 if (!qobj) { 637 *present = false; 638 return; 639 } 640 641 *present = true; 642 } 643 644 static void qobject_input_free(Visitor *v) 645 { 646 QObjectInputVisitor *qiv = to_qiv(v); 647 648 while (!QSLIST_EMPTY(&qiv->stack)) { 649 StackObject *tos = QSLIST_FIRST(&qiv->stack); 650 651 QSLIST_REMOVE_HEAD(&qiv->stack, node); 652 qobject_input_stack_object_free(tos); 653 } 654 655 qobject_decref(qiv->root); 656 if (qiv->errname) { 657 g_string_free(qiv->errname, TRUE); 658 } 659 g_free(qiv); 660 } 661 662 static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) 663 { 664 QObjectInputVisitor *v = g_malloc0(sizeof(*v)); 665 666 assert(obj); 667 668 v->visitor.type = VISITOR_INPUT; 669 v->visitor.start_struct = qobject_input_start_struct; 670 v->visitor.check_struct = qobject_input_check_struct; 671 v->visitor.end_struct = qobject_input_end_struct; 672 v->visitor.start_list = qobject_input_start_list; 673 v->visitor.next_list = qobject_input_next_list; 674 v->visitor.check_list = qobject_input_check_list; 675 v->visitor.end_list = qobject_input_end_list; 676 v->visitor.start_alternate = qobject_input_start_alternate; 677 v->visitor.optional = qobject_input_optional; 678 v->visitor.free = qobject_input_free; 679 680 v->root = obj; 681 qobject_incref(obj); 682 683 return v; 684 } 685 686 Visitor *qobject_input_visitor_new(QObject *obj) 687 { 688 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 689 690 v->visitor.type_int64 = qobject_input_type_int64; 691 v->visitor.type_uint64 = qobject_input_type_uint64; 692 v->visitor.type_bool = qobject_input_type_bool; 693 v->visitor.type_str = qobject_input_type_str; 694 v->visitor.type_number = qobject_input_type_number; 695 v->visitor.type_any = qobject_input_type_any; 696 v->visitor.type_null = qobject_input_type_null; 697 698 return &v->visitor; 699 } 700 701 Visitor *qobject_input_visitor_new_keyval(QObject *obj) 702 { 703 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); 704 705 v->visitor.type_int64 = qobject_input_type_int64_keyval; 706 v->visitor.type_uint64 = qobject_input_type_uint64_keyval; 707 v->visitor.type_bool = qobject_input_type_bool_keyval; 708 v->visitor.type_str = qobject_input_type_str_keyval; 709 v->visitor.type_number = qobject_input_type_number_keyval; 710 v->visitor.type_any = qobject_input_type_any; 711 v->visitor.type_null = qobject_input_type_null; 712 v->visitor.type_size = qobject_input_type_size_keyval; 713 v->keyval = true; 714 715 return &v->visitor; 716 } 717 718 Visitor *qobject_input_visitor_new_str(const char *str, 719 const char *implied_key, 720 Error **errp) 721 { 722 bool is_json = str[0] == '{'; 723 QObject *obj; 724 QDict *args; 725 Visitor *v; 726 727 if (is_json) { 728 obj = qobject_from_json(str, errp); 729 if (!obj) { 730 /* Work around qobject_from_json() lossage TODO fix that */ 731 if (errp && !*errp) { 732 error_setg(errp, "JSON parse error"); 733 return NULL; 734 } 735 return NULL; 736 } 737 args = qobject_to_qdict(obj); 738 assert(args); 739 v = qobject_input_visitor_new(QOBJECT(args)); 740 } else { 741 args = keyval_parse(str, implied_key, errp); 742 if (!args) { 743 return NULL; 744 } 745 v = qobject_input_visitor_new_keyval(QOBJECT(args)); 746 } 747 QDECREF(args); 748 749 return v; 750 } 751