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