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