|
|
1.1 ! root 1: /* ! 2: * QEMU Object Model ! 3: * ! 4: * Copyright IBM, Corp. 2011 ! 5: * ! 6: * Authors: ! 7: * Anthony Liguori <[email protected]> ! 8: * ! 9: * This work is licensed under the terms of the GNU GPL, version 2 or later. ! 10: * See the COPYING file in the top-level directory. ! 11: */ ! 12: ! 13: #include "qemu/object.h" ! 14: #include "qemu-common.h" ! 15: #include "qapi/qapi-visit-core.h" ! 16: #include "qapi/string-input-visitor.h" ! 17: #include "qapi/string-output-visitor.h" ! 18: ! 19: /* TODO: replace QObject with a simpler visitor to avoid a dependency ! 20: * of the QOM core on QObject? */ ! 21: #include "qemu/qom-qobject.h" ! 22: #include "qobject.h" ! 23: #include "qbool.h" ! 24: #include "qint.h" ! 25: #include "qstring.h" ! 26: ! 27: #define MAX_INTERFACES 32 ! 28: ! 29: typedef struct InterfaceImpl InterfaceImpl; ! 30: typedef struct TypeImpl TypeImpl; ! 31: ! 32: struct InterfaceImpl ! 33: { ! 34: const char *parent; ! 35: void (*interface_initfn)(ObjectClass *class, void *data); ! 36: TypeImpl *type; ! 37: }; ! 38: ! 39: struct TypeImpl ! 40: { ! 41: const char *name; ! 42: ! 43: size_t class_size; ! 44: ! 45: size_t instance_size; ! 46: ! 47: void (*class_init)(ObjectClass *klass, void *data); ! 48: void (*class_finalize)(ObjectClass *klass, void *data); ! 49: ! 50: void *class_data; ! 51: ! 52: void (*instance_init)(Object *obj); ! 53: void (*instance_finalize)(Object *obj); ! 54: ! 55: bool abstract; ! 56: ! 57: const char *parent; ! 58: TypeImpl *parent_type; ! 59: ! 60: ObjectClass *class; ! 61: ! 62: int num_interfaces; ! 63: InterfaceImpl interfaces[MAX_INTERFACES]; ! 64: }; ! 65: ! 66: typedef struct Interface ! 67: { ! 68: Object parent; ! 69: Object *obj; ! 70: } Interface; ! 71: ! 72: #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE) ! 73: ! 74: static Type type_interface; ! 75: ! 76: static GHashTable *type_table_get(void) ! 77: { ! 78: static GHashTable *type_table; ! 79: ! 80: if (type_table == NULL) { ! 81: type_table = g_hash_table_new(g_str_hash, g_str_equal); ! 82: } ! 83: ! 84: return type_table; ! 85: } ! 86: ! 87: static void type_table_add(TypeImpl *ti) ! 88: { ! 89: g_hash_table_insert(type_table_get(), (void *)ti->name, ti); ! 90: } ! 91: ! 92: static TypeImpl *type_table_lookup(const char *name) ! 93: { ! 94: return g_hash_table_lookup(type_table_get(), name); ! 95: } ! 96: ! 97: TypeImpl *type_register(const TypeInfo *info) ! 98: { ! 99: TypeImpl *ti = g_malloc0(sizeof(*ti)); ! 100: ! 101: g_assert(info->name != NULL); ! 102: ! 103: if (type_table_lookup(info->name) != NULL) { ! 104: fprintf(stderr, "Registering `%s' which already exists\n", info->name); ! 105: abort(); ! 106: } ! 107: ! 108: ti->name = g_strdup(info->name); ! 109: ti->parent = g_strdup(info->parent); ! 110: ! 111: ti->class_size = info->class_size; ! 112: ti->instance_size = info->instance_size; ! 113: ! 114: ti->class_init = info->class_init; ! 115: ti->class_finalize = info->class_finalize; ! 116: ti->class_data = info->class_data; ! 117: ! 118: ti->instance_init = info->instance_init; ! 119: ti->instance_finalize = info->instance_finalize; ! 120: ! 121: ti->abstract = info->abstract; ! 122: ! 123: if (info->interfaces) { ! 124: int i; ! 125: ! 126: for (i = 0; info->interfaces[i].type; i++) { ! 127: ti->interfaces[i].parent = info->interfaces[i].type; ! 128: ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn; ! 129: ti->num_interfaces++; ! 130: } ! 131: } ! 132: ! 133: type_table_add(ti); ! 134: ! 135: return ti; ! 136: } ! 137: ! 138: TypeImpl *type_register_static(const TypeInfo *info) ! 139: { ! 140: return type_register(info); ! 141: } ! 142: ! 143: static TypeImpl *type_get_by_name(const char *name) ! 144: { ! 145: if (name == NULL) { ! 146: return NULL; ! 147: } ! 148: ! 149: return type_table_lookup(name); ! 150: } ! 151: ! 152: static TypeImpl *type_get_parent(TypeImpl *type) ! 153: { ! 154: if (!type->parent_type && type->parent) { ! 155: type->parent_type = type_get_by_name(type->parent); ! 156: g_assert(type->parent_type != NULL); ! 157: } ! 158: ! 159: return type->parent_type; ! 160: } ! 161: ! 162: static bool type_has_parent(TypeImpl *type) ! 163: { ! 164: return (type->parent != NULL); ! 165: } ! 166: ! 167: static size_t type_class_get_size(TypeImpl *ti) ! 168: { ! 169: if (ti->class_size) { ! 170: return ti->class_size; ! 171: } ! 172: ! 173: if (type_has_parent(ti)) { ! 174: return type_class_get_size(type_get_parent(ti)); ! 175: } ! 176: ! 177: return sizeof(ObjectClass); ! 178: } ! 179: ! 180: static size_t type_object_get_size(TypeImpl *ti) ! 181: { ! 182: if (ti->instance_size) { ! 183: return ti->instance_size; ! 184: } ! 185: ! 186: if (type_has_parent(ti)) { ! 187: return type_object_get_size(type_get_parent(ti)); ! 188: } ! 189: ! 190: return 0; ! 191: } ! 192: ! 193: static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface) ! 194: { ! 195: TypeInfo info = { ! 196: .instance_size = sizeof(Interface), ! 197: .parent = iface->parent, ! 198: .class_size = sizeof(InterfaceClass), ! 199: .class_init = iface->interface_initfn, ! 200: .abstract = true, ! 201: }; ! 202: char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent); ! 203: ! 204: info.name = name; ! 205: iface->type = type_register(&info); ! 206: g_free(name); ! 207: } ! 208: ! 209: static void type_initialize(TypeImpl *ti) ! 210: { ! 211: size_t class_size = sizeof(ObjectClass); ! 212: int i; ! 213: ! 214: if (ti->class) { ! 215: return; ! 216: } ! 217: ! 218: ti->class_size = type_class_get_size(ti); ! 219: ti->instance_size = type_object_get_size(ti); ! 220: ! 221: ti->class = g_malloc0(ti->class_size); ! 222: ti->class->type = ti; ! 223: ! 224: if (type_has_parent(ti)) { ! 225: TypeImpl *parent = type_get_parent(ti); ! 226: ! 227: type_initialize(parent); ! 228: ! 229: class_size = parent->class_size; ! 230: g_assert(parent->class_size <= ti->class_size); ! 231: ! 232: memcpy((void *)ti->class + sizeof(ObjectClass), ! 233: (void *)parent->class + sizeof(ObjectClass), ! 234: parent->class_size - sizeof(ObjectClass)); ! 235: } ! 236: ! 237: memset((void *)ti->class + class_size, 0, ti->class_size - class_size); ! 238: ! 239: for (i = 0; i < ti->num_interfaces; i++) { ! 240: type_class_interface_init(ti, &ti->interfaces[i]); ! 241: } ! 242: ! 243: if (ti->class_init) { ! 244: ti->class_init(ti->class, ti->class_data); ! 245: } ! 246: } ! 247: ! 248: static void object_interface_init(Object *obj, InterfaceImpl *iface) ! 249: { ! 250: TypeImpl *ti = iface->type; ! 251: Interface *iface_obj; ! 252: ! 253: iface_obj = INTERFACE(object_new(ti->name)); ! 254: iface_obj->obj = obj; ! 255: ! 256: obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj); ! 257: } ! 258: ! 259: static void object_init_with_type(Object *obj, TypeImpl *ti) ! 260: { ! 261: int i; ! 262: ! 263: if (type_has_parent(ti)) { ! 264: object_init_with_type(obj, type_get_parent(ti)); ! 265: } ! 266: ! 267: for (i = 0; i < ti->num_interfaces; i++) { ! 268: object_interface_init(obj, &ti->interfaces[i]); ! 269: } ! 270: ! 271: if (ti->instance_init) { ! 272: ti->instance_init(obj); ! 273: } ! 274: } ! 275: ! 276: void object_initialize_with_type(void *data, TypeImpl *type) ! 277: { ! 278: Object *obj = data; ! 279: ! 280: g_assert(type != NULL); ! 281: type_initialize(type); ! 282: ! 283: g_assert(type->instance_size >= sizeof(Object)); ! 284: g_assert(type->abstract == false); ! 285: ! 286: memset(obj, 0, type->instance_size); ! 287: obj->class = type->class; ! 288: QTAILQ_INIT(&obj->properties); ! 289: object_init_with_type(obj, type); ! 290: } ! 291: ! 292: void object_initialize(void *data, const char *typename) ! 293: { ! 294: TypeImpl *type = type_get_by_name(typename); ! 295: ! 296: object_initialize_with_type(data, type); ! 297: } ! 298: ! 299: static void object_property_del_all(Object *obj) ! 300: { ! 301: while (!QTAILQ_EMPTY(&obj->properties)) { ! 302: ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); ! 303: ! 304: QTAILQ_REMOVE(&obj->properties, prop, node); ! 305: ! 306: if (prop->release) { ! 307: prop->release(obj, prop->name, prop->opaque); ! 308: } ! 309: ! 310: g_free(prop->name); ! 311: g_free(prop->type); ! 312: g_free(prop); ! 313: } ! 314: } ! 315: ! 316: static void object_property_del_child(Object *obj, Object *child, Error **errp) ! 317: { ! 318: ObjectProperty *prop; ! 319: ! 320: QTAILQ_FOREACH(prop, &obj->properties, node) { ! 321: if (strstart(prop->type, "child<", NULL) && prop->opaque == child) { ! 322: object_property_del(obj, prop->name, errp); ! 323: break; ! 324: } ! 325: } ! 326: } ! 327: ! 328: void object_unparent(Object *obj) ! 329: { ! 330: if (obj->parent) { ! 331: object_property_del_child(obj->parent, obj, NULL); ! 332: } ! 333: } ! 334: ! 335: static void object_deinit(Object *obj, TypeImpl *type) ! 336: { ! 337: if (type->instance_finalize) { ! 338: type->instance_finalize(obj); ! 339: } ! 340: ! 341: while (obj->interfaces) { ! 342: Interface *iface_obj = obj->interfaces->data; ! 343: obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces); ! 344: object_delete(OBJECT(iface_obj)); ! 345: } ! 346: ! 347: if (type_has_parent(type)) { ! 348: object_deinit(obj, type_get_parent(type)); ! 349: } ! 350: ! 351: object_unparent(obj); ! 352: } ! 353: ! 354: void object_finalize(void *data) ! 355: { ! 356: Object *obj = data; ! 357: TypeImpl *ti = obj->class->type; ! 358: ! 359: object_deinit(obj, ti); ! 360: object_property_del_all(obj); ! 361: ! 362: g_assert(obj->ref == 0); ! 363: } ! 364: ! 365: Object *object_new_with_type(Type type) ! 366: { ! 367: Object *obj; ! 368: ! 369: g_assert(type != NULL); ! 370: type_initialize(type); ! 371: ! 372: obj = g_malloc(type->instance_size); ! 373: object_initialize_with_type(obj, type); ! 374: object_ref(obj); ! 375: ! 376: return obj; ! 377: } ! 378: ! 379: Object *object_new(const char *typename) ! 380: { ! 381: TypeImpl *ti = type_get_by_name(typename); ! 382: ! 383: return object_new_with_type(ti); ! 384: } ! 385: ! 386: void object_delete(Object *obj) ! 387: { ! 388: object_unref(obj); ! 389: g_assert(obj->ref == 0); ! 390: g_free(obj); ! 391: } ! 392: ! 393: static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) ! 394: { ! 395: assert(target_type); ! 396: ! 397: /* Check if typename is a direct ancestor of type */ ! 398: while (type) { ! 399: if (type == target_type) { ! 400: return true; ! 401: } ! 402: ! 403: type = type_get_parent(type); ! 404: } ! 405: ! 406: return false; ! 407: } ! 408: ! 409: static bool object_is_type(Object *obj, TypeImpl *target_type) ! 410: { ! 411: return !target_type || type_is_ancestor(obj->class->type, target_type); ! 412: } ! 413: ! 414: Object *object_dynamic_cast(Object *obj, const char *typename) ! 415: { ! 416: TypeImpl *target_type = type_get_by_name(typename); ! 417: GSList *i; ! 418: ! 419: /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT, ! 420: * we want to go back from interfaces to the parent. ! 421: */ ! 422: if (target_type && object_is_type(obj, target_type)) { ! 423: return obj; ! 424: } ! 425: ! 426: /* Check if obj is an interface and its containing object is a direct ! 427: * ancestor of typename. In principle we could do this test at the very ! 428: * beginning of object_dynamic_cast, avoiding a second call to ! 429: * object_is_type. However, casting between interfaces is relatively ! 430: * rare, and object_is_type(obj, type_interface) would fail almost always. ! 431: * ! 432: * Perhaps we could add a magic value to the object header for increased ! 433: * (run-time) type safety and to speed up tests like this one. If we ever ! 434: * do that we can revisit the order here. ! 435: */ ! 436: if (object_is_type(obj, type_interface)) { ! 437: assert(!obj->interfaces); ! 438: obj = INTERFACE(obj)->obj; ! 439: if (object_is_type(obj, target_type)) { ! 440: return obj; ! 441: } ! 442: } ! 443: ! 444: if (!target_type) { ! 445: return obj; ! 446: } ! 447: ! 448: /* Check if obj has an interface of typename */ ! 449: for (i = obj->interfaces; i; i = i->next) { ! 450: Interface *iface = i->data; ! 451: ! 452: if (object_is_type(OBJECT(iface), target_type)) { ! 453: return OBJECT(iface); ! 454: } ! 455: } ! 456: ! 457: return NULL; ! 458: } ! 459: ! 460: ! 461: static void register_types(void) ! 462: { ! 463: static TypeInfo interface_info = { ! 464: .name = TYPE_INTERFACE, ! 465: .instance_size = sizeof(Interface), ! 466: .abstract = true, ! 467: }; ! 468: ! 469: type_interface = type_register_static(&interface_info); ! 470: } ! 471: ! 472: type_init(register_types) ! 473: ! 474: Object *object_dynamic_cast_assert(Object *obj, const char *typename) ! 475: { ! 476: Object *inst; ! 477: ! 478: inst = object_dynamic_cast(obj, typename); ! 479: ! 480: if (!inst) { ! 481: fprintf(stderr, "Object %p is not an instance of type %s\n", ! 482: obj, typename); ! 483: abort(); ! 484: } ! 485: ! 486: return inst; ! 487: } ! 488: ! 489: ObjectClass *object_class_dynamic_cast(ObjectClass *class, ! 490: const char *typename) ! 491: { ! 492: TypeImpl *target_type = type_get_by_name(typename); ! 493: TypeImpl *type = class->type; ! 494: ! 495: while (type) { ! 496: if (type == target_type) { ! 497: return class; ! 498: } ! 499: ! 500: type = type_get_parent(type); ! 501: } ! 502: ! 503: return NULL; ! 504: } ! 505: ! 506: ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, ! 507: const char *typename) ! 508: { ! 509: ObjectClass *ret = object_class_dynamic_cast(class, typename); ! 510: ! 511: if (!ret) { ! 512: fprintf(stderr, "Object %p is not an instance of type %s\n", ! 513: class, typename); ! 514: abort(); ! 515: } ! 516: ! 517: return ret; ! 518: } ! 519: ! 520: const char *object_get_typename(Object *obj) ! 521: { ! 522: return obj->class->type->name; ! 523: } ! 524: ! 525: ObjectClass *object_get_class(Object *obj) ! 526: { ! 527: return obj->class; ! 528: } ! 529: ! 530: const char *object_class_get_name(ObjectClass *klass) ! 531: { ! 532: return klass->type->name; ! 533: } ! 534: ! 535: ObjectClass *object_class_by_name(const char *typename) ! 536: { ! 537: TypeImpl *type = type_get_by_name(typename); ! 538: ! 539: if (!type) { ! 540: return NULL; ! 541: } ! 542: ! 543: type_initialize(type); ! 544: ! 545: return type->class; ! 546: } ! 547: ! 548: typedef struct OCFData ! 549: { ! 550: void (*fn)(ObjectClass *klass, void *opaque); ! 551: const char *implements_type; ! 552: bool include_abstract; ! 553: void *opaque; ! 554: } OCFData; ! 555: ! 556: static void object_class_foreach_tramp(gpointer key, gpointer value, ! 557: gpointer opaque) ! 558: { ! 559: OCFData *data = opaque; ! 560: TypeImpl *type = value; ! 561: ObjectClass *k; ! 562: ! 563: type_initialize(type); ! 564: k = type->class; ! 565: ! 566: if (!data->include_abstract && type->abstract) { ! 567: return; ! 568: } ! 569: ! 570: if (data->implements_type && ! 571: !object_class_dynamic_cast(k, data->implements_type)) { ! 572: return; ! 573: } ! 574: ! 575: data->fn(k, data->opaque); ! 576: } ! 577: ! 578: void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), ! 579: const char *implements_type, bool include_abstract, ! 580: void *opaque) ! 581: { ! 582: OCFData data = { fn, implements_type, include_abstract, opaque }; ! 583: ! 584: g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); ! 585: } ! 586: ! 587: static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) ! 588: { ! 589: GSList **list = opaque; ! 590: ! 591: *list = g_slist_prepend(*list, klass); ! 592: } ! 593: ! 594: GSList *object_class_get_list(const char *implements_type, ! 595: bool include_abstract) ! 596: { ! 597: GSList *list = NULL; ! 598: ! 599: object_class_foreach(object_class_get_list_tramp, ! 600: implements_type, include_abstract, &list); ! 601: return list; ! 602: } ! 603: ! 604: void object_ref(Object *obj) ! 605: { ! 606: obj->ref++; ! 607: } ! 608: ! 609: void object_unref(Object *obj) ! 610: { ! 611: g_assert(obj->ref > 0); ! 612: obj->ref--; ! 613: ! 614: /* parent always holds a reference to its children */ ! 615: if (obj->ref == 0) { ! 616: object_finalize(obj); ! 617: } ! 618: } ! 619: ! 620: void object_property_add(Object *obj, const char *name, const char *type, ! 621: ObjectPropertyAccessor *get, ! 622: ObjectPropertyAccessor *set, ! 623: ObjectPropertyRelease *release, ! 624: void *opaque, Error **errp) ! 625: { ! 626: ObjectProperty *prop = g_malloc0(sizeof(*prop)); ! 627: ! 628: prop->name = g_strdup(name); ! 629: prop->type = g_strdup(type); ! 630: ! 631: prop->get = get; ! 632: prop->set = set; ! 633: prop->release = release; ! 634: prop->opaque = opaque; ! 635: ! 636: QTAILQ_INSERT_TAIL(&obj->properties, prop, node); ! 637: } ! 638: ! 639: static ObjectProperty *object_property_find(Object *obj, const char *name) ! 640: { ! 641: ObjectProperty *prop; ! 642: ! 643: QTAILQ_FOREACH(prop, &obj->properties, node) { ! 644: if (strcmp(prop->name, name) == 0) { ! 645: return prop; ! 646: } ! 647: } ! 648: ! 649: return NULL; ! 650: } ! 651: ! 652: void object_property_del(Object *obj, const char *name, Error **errp) ! 653: { ! 654: ObjectProperty *prop = object_property_find(obj, name); ! 655: ! 656: QTAILQ_REMOVE(&obj->properties, prop, node); ! 657: ! 658: prop->release(obj, prop->name, prop->opaque); ! 659: ! 660: g_free(prop->name); ! 661: g_free(prop->type); ! 662: g_free(prop); ! 663: } ! 664: ! 665: void object_property_get(Object *obj, Visitor *v, const char *name, ! 666: Error **errp) ! 667: { ! 668: ObjectProperty *prop = object_property_find(obj, name); ! 669: ! 670: if (prop == NULL) { ! 671: error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); ! 672: return; ! 673: } ! 674: ! 675: if (!prop->get) { ! 676: error_set(errp, QERR_PERMISSION_DENIED); ! 677: } else { ! 678: prop->get(obj, v, prop->opaque, name, errp); ! 679: } ! 680: } ! 681: ! 682: void object_property_set(Object *obj, Visitor *v, const char *name, ! 683: Error **errp) ! 684: { ! 685: ObjectProperty *prop = object_property_find(obj, name); ! 686: ! 687: if (prop == NULL) { ! 688: error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); ! 689: return; ! 690: } ! 691: ! 692: if (!prop->set) { ! 693: error_set(errp, QERR_PERMISSION_DENIED); ! 694: } else { ! 695: prop->set(obj, v, prop->opaque, name, errp); ! 696: } ! 697: } ! 698: ! 699: void object_property_set_str(Object *obj, const char *value, ! 700: const char *name, Error **errp) ! 701: { ! 702: QString *qstr = qstring_from_str(value); ! 703: object_property_set_qobject(obj, QOBJECT(qstr), name, errp); ! 704: ! 705: QDECREF(qstr); ! 706: } ! 707: ! 708: char *object_property_get_str(Object *obj, const char *name, ! 709: Error **errp) ! 710: { ! 711: QObject *ret = object_property_get_qobject(obj, name, errp); ! 712: QString *qstring; ! 713: char *retval; ! 714: ! 715: if (!ret) { ! 716: return NULL; ! 717: } ! 718: qstring = qobject_to_qstring(ret); ! 719: if (!qstring) { ! 720: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); ! 721: retval = NULL; ! 722: } else { ! 723: retval = g_strdup(qstring_get_str(qstring)); ! 724: } ! 725: ! 726: QDECREF(qstring); ! 727: return retval; ! 728: } ! 729: ! 730: void object_property_set_link(Object *obj, Object *value, ! 731: const char *name, Error **errp) ! 732: { ! 733: object_property_set_str(obj, object_get_canonical_path(value), ! 734: name, errp); ! 735: } ! 736: ! 737: Object *object_property_get_link(Object *obj, const char *name, ! 738: Error **errp) ! 739: { ! 740: char *str = object_property_get_str(obj, name, errp); ! 741: Object *target = NULL; ! 742: ! 743: if (str && *str) { ! 744: target = object_resolve_path(str, NULL); ! 745: if (!target) { ! 746: error_set(errp, QERR_DEVICE_NOT_FOUND, str); ! 747: } ! 748: } ! 749: ! 750: g_free(str); ! 751: return target; ! 752: } ! 753: ! 754: void object_property_set_bool(Object *obj, bool value, ! 755: const char *name, Error **errp) ! 756: { ! 757: QBool *qbool = qbool_from_int(value); ! 758: object_property_set_qobject(obj, QOBJECT(qbool), name, errp); ! 759: ! 760: QDECREF(qbool); ! 761: } ! 762: ! 763: bool object_property_get_bool(Object *obj, const char *name, ! 764: Error **errp) ! 765: { ! 766: QObject *ret = object_property_get_qobject(obj, name, errp); ! 767: QBool *qbool; ! 768: bool retval; ! 769: ! 770: if (!ret) { ! 771: return false; ! 772: } ! 773: qbool = qobject_to_qbool(ret); ! 774: if (!qbool) { ! 775: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); ! 776: retval = false; ! 777: } else { ! 778: retval = qbool_get_int(qbool); ! 779: } ! 780: ! 781: QDECREF(qbool); ! 782: return retval; ! 783: } ! 784: ! 785: void object_property_set_int(Object *obj, int64_t value, ! 786: const char *name, Error **errp) ! 787: { ! 788: QInt *qint = qint_from_int(value); ! 789: object_property_set_qobject(obj, QOBJECT(qint), name, errp); ! 790: ! 791: QDECREF(qint); ! 792: } ! 793: ! 794: int64_t object_property_get_int(Object *obj, const char *name, ! 795: Error **errp) ! 796: { ! 797: QObject *ret = object_property_get_qobject(obj, name, errp); ! 798: QInt *qint; ! 799: int64_t retval; ! 800: ! 801: if (!ret) { ! 802: return -1; ! 803: } ! 804: qint = qobject_to_qint(ret); ! 805: if (!qint) { ! 806: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); ! 807: retval = -1; ! 808: } else { ! 809: retval = qint_get_int(qint); ! 810: } ! 811: ! 812: QDECREF(qint); ! 813: return retval; ! 814: } ! 815: ! 816: void object_property_parse(Object *obj, const char *string, ! 817: const char *name, Error **errp) ! 818: { ! 819: StringInputVisitor *mi; ! 820: mi = string_input_visitor_new(string); ! 821: object_property_set(obj, string_input_get_visitor(mi), name, errp); ! 822: ! 823: string_input_visitor_cleanup(mi); ! 824: } ! 825: ! 826: char *object_property_print(Object *obj, const char *name, ! 827: Error **errp) ! 828: { ! 829: StringOutputVisitor *mo; ! 830: char *string; ! 831: ! 832: mo = string_output_visitor_new(); ! 833: object_property_get(obj, string_output_get_visitor(mo), name, errp); ! 834: string = string_output_get_string(mo); ! 835: string_output_visitor_cleanup(mo); ! 836: return string; ! 837: } ! 838: ! 839: const char *object_property_get_type(Object *obj, const char *name, Error **errp) ! 840: { ! 841: ObjectProperty *prop = object_property_find(obj, name); ! 842: ! 843: if (prop == NULL) { ! 844: error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); ! 845: return NULL; ! 846: } ! 847: ! 848: return prop->type; ! 849: } ! 850: ! 851: Object *object_get_root(void) ! 852: { ! 853: static Object *root; ! 854: ! 855: if (!root) { ! 856: root = object_new("container"); ! 857: } ! 858: ! 859: return root; ! 860: } ! 861: ! 862: static void object_get_child_property(Object *obj, Visitor *v, void *opaque, ! 863: const char *name, Error **errp) ! 864: { ! 865: Object *child = opaque; ! 866: gchar *path; ! 867: ! 868: path = object_get_canonical_path(child); ! 869: visit_type_str(v, &path, name, errp); ! 870: g_free(path); ! 871: } ! 872: ! 873: static void object_finalize_child_property(Object *obj, const char *name, ! 874: void *opaque) ! 875: { ! 876: Object *child = opaque; ! 877: ! 878: object_unref(child); ! 879: } ! 880: ! 881: void object_property_add_child(Object *obj, const char *name, ! 882: Object *child, Error **errp) ! 883: { ! 884: gchar *type; ! 885: ! 886: /* Registering an interface object in the composition tree will mightily ! 887: * confuse object_get_canonical_path (which, on the other hand, knows how ! 888: * to get the canonical path of an interface object). ! 889: */ ! 890: assert(!object_is_type(obj, type_interface)); ! 891: ! 892: type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); ! 893: ! 894: object_property_add(obj, name, type, object_get_child_property, ! 895: NULL, object_finalize_child_property, child, errp); ! 896: ! 897: object_ref(child); ! 898: g_assert(child->parent == NULL); ! 899: child->parent = obj; ! 900: ! 901: g_free(type); ! 902: } ! 903: ! 904: static void object_get_link_property(Object *obj, Visitor *v, void *opaque, ! 905: const char *name, Error **errp) ! 906: { ! 907: Object **child = opaque; ! 908: gchar *path; ! 909: ! 910: if (*child) { ! 911: path = object_get_canonical_path(*child); ! 912: visit_type_str(v, &path, name, errp); ! 913: g_free(path); ! 914: } else { ! 915: path = (gchar *)""; ! 916: visit_type_str(v, &path, name, errp); ! 917: } ! 918: } ! 919: ! 920: static void object_set_link_property(Object *obj, Visitor *v, void *opaque, ! 921: const char *name, Error **errp) ! 922: { ! 923: Object **child = opaque; ! 924: Object *old_target; ! 925: bool ambiguous = false; ! 926: const char *type; ! 927: char *path; ! 928: gchar *target_type; ! 929: ! 930: type = object_property_get_type(obj, name, NULL); ! 931: ! 932: visit_type_str(v, &path, name, errp); ! 933: ! 934: old_target = *child; ! 935: *child = NULL; ! 936: ! 937: if (strcmp(path, "") != 0) { ! 938: Object *target; ! 939: ! 940: /* Go from link<FOO> to FOO. */ ! 941: target_type = g_strndup(&type[5], strlen(type) - 6); ! 942: target = object_resolve_path_type(path, target_type, &ambiguous); ! 943: ! 944: if (ambiguous) { ! 945: error_set(errp, QERR_AMBIGUOUS_PATH, path); ! 946: } else if (target) { ! 947: object_ref(target); ! 948: *child = target; ! 949: } else { ! 950: target = object_resolve_path(path, &ambiguous); ! 951: if (target || ambiguous) { ! 952: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); ! 953: } else { ! 954: error_set(errp, QERR_DEVICE_NOT_FOUND, path); ! 955: } ! 956: } ! 957: g_free(target_type); ! 958: } ! 959: ! 960: g_free(path); ! 961: ! 962: if (old_target != NULL) { ! 963: object_unref(old_target); ! 964: } ! 965: } ! 966: ! 967: void object_property_add_link(Object *obj, const char *name, ! 968: const char *type, Object **child, ! 969: Error **errp) ! 970: { ! 971: gchar *full_type; ! 972: ! 973: full_type = g_strdup_printf("link<%s>", type); ! 974: ! 975: object_property_add(obj, name, full_type, ! 976: object_get_link_property, ! 977: object_set_link_property, ! 978: NULL, child, errp); ! 979: ! 980: g_free(full_type); ! 981: } ! 982: ! 983: gchar *object_get_canonical_path(Object *obj) ! 984: { ! 985: Object *root = object_get_root(); ! 986: char *newpath = NULL, *path = NULL; ! 987: ! 988: if (object_is_type(obj, type_interface)) { ! 989: obj = INTERFACE(obj)->obj; ! 990: } ! 991: ! 992: while (obj != root) { ! 993: ObjectProperty *prop = NULL; ! 994: ! 995: g_assert(obj->parent != NULL); ! 996: ! 997: QTAILQ_FOREACH(prop, &obj->parent->properties, node) { ! 998: if (!strstart(prop->type, "child<", NULL)) { ! 999: continue; ! 1000: } ! 1001: ! 1002: if (prop->opaque == obj) { ! 1003: if (path) { ! 1004: newpath = g_strdup_printf("%s/%s", prop->name, path); ! 1005: g_free(path); ! 1006: path = newpath; ! 1007: } else { ! 1008: path = g_strdup(prop->name); ! 1009: } ! 1010: break; ! 1011: } ! 1012: } ! 1013: ! 1014: g_assert(prop != NULL); ! 1015: ! 1016: obj = obj->parent; ! 1017: } ! 1018: ! 1019: newpath = g_strdup_printf("/%s", path); ! 1020: g_free(path); ! 1021: ! 1022: return newpath; ! 1023: } ! 1024: ! 1025: Object *object_resolve_path_component(Object *parent, gchar *part) ! 1026: { ! 1027: ObjectProperty *prop = object_property_find(parent, part); ! 1028: if (prop == NULL) { ! 1029: return NULL; ! 1030: } ! 1031: ! 1032: if (strstart(prop->type, "link<", NULL)) { ! 1033: return *(Object **)prop->opaque; ! 1034: } else if (strstart(prop->type, "child<", NULL)) { ! 1035: return prop->opaque; ! 1036: } else { ! 1037: return NULL; ! 1038: } ! 1039: } ! 1040: ! 1041: static Object *object_resolve_abs_path(Object *parent, ! 1042: gchar **parts, ! 1043: const char *typename, ! 1044: int index) ! 1045: { ! 1046: Object *child; ! 1047: ! 1048: if (parts[index] == NULL) { ! 1049: return object_dynamic_cast(parent, typename); ! 1050: } ! 1051: ! 1052: if (strcmp(parts[index], "") == 0) { ! 1053: return object_resolve_abs_path(parent, parts, typename, index + 1); ! 1054: } ! 1055: ! 1056: child = object_resolve_path_component(parent, parts[index]); ! 1057: if (!child) { ! 1058: return NULL; ! 1059: } ! 1060: ! 1061: return object_resolve_abs_path(child, parts, typename, index + 1); ! 1062: } ! 1063: ! 1064: static Object *object_resolve_partial_path(Object *parent, ! 1065: gchar **parts, ! 1066: const char *typename, ! 1067: bool *ambiguous) ! 1068: { ! 1069: Object *obj; ! 1070: ObjectProperty *prop; ! 1071: ! 1072: obj = object_resolve_abs_path(parent, parts, typename, 0); ! 1073: ! 1074: QTAILQ_FOREACH(prop, &parent->properties, node) { ! 1075: Object *found; ! 1076: ! 1077: if (!strstart(prop->type, "child<", NULL)) { ! 1078: continue; ! 1079: } ! 1080: ! 1081: found = object_resolve_partial_path(prop->opaque, parts, ! 1082: typename, ambiguous); ! 1083: if (found) { ! 1084: if (obj) { ! 1085: if (ambiguous) { ! 1086: *ambiguous = true; ! 1087: } ! 1088: return NULL; ! 1089: } ! 1090: obj = found; ! 1091: } ! 1092: ! 1093: if (ambiguous && *ambiguous) { ! 1094: return NULL; ! 1095: } ! 1096: } ! 1097: ! 1098: return obj; ! 1099: } ! 1100: ! 1101: Object *object_resolve_path_type(const char *path, const char *typename, ! 1102: bool *ambiguous) ! 1103: { ! 1104: bool partial_path = true; ! 1105: Object *obj; ! 1106: gchar **parts; ! 1107: ! 1108: parts = g_strsplit(path, "/", 0); ! 1109: if (parts == NULL || parts[0] == NULL) { ! 1110: g_strfreev(parts); ! 1111: return object_get_root(); ! 1112: } ! 1113: ! 1114: if (strcmp(parts[0], "") == 0) { ! 1115: partial_path = false; ! 1116: } ! 1117: ! 1118: if (partial_path) { ! 1119: if (ambiguous) { ! 1120: *ambiguous = false; ! 1121: } ! 1122: obj = object_resolve_partial_path(object_get_root(), parts, ! 1123: typename, ambiguous); ! 1124: } else { ! 1125: obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); ! 1126: } ! 1127: ! 1128: g_strfreev(parts); ! 1129: ! 1130: return obj; ! 1131: } ! 1132: ! 1133: Object *object_resolve_path(const char *path, bool *ambiguous) ! 1134: { ! 1135: return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); ! 1136: } ! 1137: ! 1138: typedef struct StringProperty ! 1139: { ! 1140: char *(*get)(Object *, Error **); ! 1141: void (*set)(Object *, const char *, Error **); ! 1142: } StringProperty; ! 1143: ! 1144: static void property_get_str(Object *obj, Visitor *v, void *opaque, ! 1145: const char *name, Error **errp) ! 1146: { ! 1147: StringProperty *prop = opaque; ! 1148: char *value; ! 1149: ! 1150: value = prop->get(obj, errp); ! 1151: if (value) { ! 1152: visit_type_str(v, &value, name, errp); ! 1153: g_free(value); ! 1154: } ! 1155: } ! 1156: ! 1157: static void property_set_str(Object *obj, Visitor *v, void *opaque, ! 1158: const char *name, Error **errp) ! 1159: { ! 1160: StringProperty *prop = opaque; ! 1161: char *value; ! 1162: Error *local_err = NULL; ! 1163: ! 1164: visit_type_str(v, &value, name, &local_err); ! 1165: if (local_err) { ! 1166: error_propagate(errp, local_err); ! 1167: return; ! 1168: } ! 1169: ! 1170: prop->set(obj, value, errp); ! 1171: g_free(value); ! 1172: } ! 1173: ! 1174: static void property_release_str(Object *obj, const char *name, ! 1175: void *opaque) ! 1176: { ! 1177: StringProperty *prop = opaque; ! 1178: g_free(prop); ! 1179: } ! 1180: ! 1181: void object_property_add_str(Object *obj, const char *name, ! 1182: char *(*get)(Object *, Error **), ! 1183: void (*set)(Object *, const char *, Error **), ! 1184: Error **errp) ! 1185: { ! 1186: StringProperty *prop = g_malloc0(sizeof(*prop)); ! 1187: ! 1188: prop->get = get; ! 1189: prop->set = set; ! 1190: ! 1191: object_property_add(obj, name, "string", ! 1192: get ? property_get_str : NULL, ! 1193: set ? property_set_str : NULL, ! 1194: property_release_str, ! 1195: prop, errp); ! 1196: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.