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