12f28d2ffSAnthony Liguori /* 22f28d2ffSAnthony Liguori * QEMU Object Model 32f28d2ffSAnthony Liguori * 42f28d2ffSAnthony Liguori * Copyright IBM, Corp. 2011 52f28d2ffSAnthony Liguori * 62f28d2ffSAnthony Liguori * Authors: 72f28d2ffSAnthony Liguori * Anthony Liguori <aliguori@us.ibm.com> 82f28d2ffSAnthony Liguori * 92f28d2ffSAnthony Liguori * This work is licensed under the terms of the GNU GPL, version 2 or later. 102f28d2ffSAnthony Liguori * See the COPYING file in the top-level directory. 112f28d2ffSAnthony Liguori */ 122f28d2ffSAnthony Liguori 132f28d2ffSAnthony Liguori #include "qemu/object.h" 142f28d2ffSAnthony Liguori #include "qemu-common.h" 1557c9fafeSAnthony Liguori #include "qapi/qapi-visit-core.h" 1657c9fafeSAnthony Liguori #include "hw/qdev.h" 1757c9fafeSAnthony Liguori // FIXME remove above 182f28d2ffSAnthony Liguori 192f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 202f28d2ffSAnthony Liguori 212f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 222f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 232f28d2ffSAnthony Liguori 242f28d2ffSAnthony Liguori struct InterfaceImpl 252f28d2ffSAnthony Liguori { 262f28d2ffSAnthony Liguori const char *parent; 272f28d2ffSAnthony Liguori void (*interface_initfn)(ObjectClass *class, void *data); 282f28d2ffSAnthony Liguori TypeImpl *type; 292f28d2ffSAnthony Liguori }; 302f28d2ffSAnthony Liguori 312f28d2ffSAnthony Liguori struct TypeImpl 322f28d2ffSAnthony Liguori { 332f28d2ffSAnthony Liguori const char *name; 342f28d2ffSAnthony Liguori 352f28d2ffSAnthony Liguori size_t class_size; 362f28d2ffSAnthony Liguori 372f28d2ffSAnthony Liguori size_t instance_size; 382f28d2ffSAnthony Liguori 392f28d2ffSAnthony Liguori void (*class_init)(ObjectClass *klass, void *data); 402f28d2ffSAnthony Liguori void (*class_finalize)(ObjectClass *klass, void *data); 412f28d2ffSAnthony Liguori 422f28d2ffSAnthony Liguori void *class_data; 432f28d2ffSAnthony Liguori 442f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 452f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 462f28d2ffSAnthony Liguori 472f28d2ffSAnthony Liguori bool abstract; 482f28d2ffSAnthony Liguori 492f28d2ffSAnthony Liguori const char *parent; 502f28d2ffSAnthony Liguori TypeImpl *parent_type; 512f28d2ffSAnthony Liguori 522f28d2ffSAnthony Liguori ObjectClass *class; 532f28d2ffSAnthony Liguori 542f28d2ffSAnthony Liguori int num_interfaces; 552f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 562f28d2ffSAnthony Liguori }; 572f28d2ffSAnthony Liguori 582f28d2ffSAnthony Liguori typedef struct Interface 592f28d2ffSAnthony Liguori { 602f28d2ffSAnthony Liguori Object parent; 612f28d2ffSAnthony Liguori Object *obj; 622f28d2ffSAnthony Liguori } Interface; 632f28d2ffSAnthony Liguori 642f28d2ffSAnthony Liguori #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE) 652f28d2ffSAnthony Liguori 662f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 672f28d2ffSAnthony Liguori { 682f28d2ffSAnthony Liguori static GHashTable *type_table; 692f28d2ffSAnthony Liguori 702f28d2ffSAnthony Liguori if (type_table == NULL) { 712f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 722f28d2ffSAnthony Liguori } 732f28d2ffSAnthony Liguori 742f28d2ffSAnthony Liguori return type_table; 752f28d2ffSAnthony Liguori } 762f28d2ffSAnthony Liguori 772f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 782f28d2ffSAnthony Liguori { 792f28d2ffSAnthony Liguori g_hash_table_insert(type_table_get(), (void *)ti->name, ti); 802f28d2ffSAnthony Liguori } 812f28d2ffSAnthony Liguori 822f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name) 832f28d2ffSAnthony Liguori { 842f28d2ffSAnthony Liguori return g_hash_table_lookup(type_table_get(), name); 852f28d2ffSAnthony Liguori } 862f28d2ffSAnthony Liguori 872f28d2ffSAnthony Liguori TypeImpl *type_register(const TypeInfo *info) 882f28d2ffSAnthony Liguori { 892f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 902f28d2ffSAnthony Liguori 912f28d2ffSAnthony Liguori g_assert(info->name != NULL); 922f28d2ffSAnthony Liguori 9373093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 9473093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 9573093354SAnthony Liguori abort(); 9673093354SAnthony Liguori } 9773093354SAnthony Liguori 982f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 992f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1002f28d2ffSAnthony Liguori 1012f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1022f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1032f28d2ffSAnthony Liguori 1042f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1052f28d2ffSAnthony Liguori ti->class_finalize = info->class_finalize; 1062f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1072f28d2ffSAnthony Liguori 1082f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1092f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1102f28d2ffSAnthony Liguori 1112f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1122f28d2ffSAnthony Liguori 1132f28d2ffSAnthony Liguori if (info->interfaces) { 1142f28d2ffSAnthony Liguori int i; 1152f28d2ffSAnthony Liguori 1162f28d2ffSAnthony Liguori for (i = 0; info->interfaces[i].type; i++) { 1172f28d2ffSAnthony Liguori ti->interfaces[i].parent = info->interfaces[i].type; 1182f28d2ffSAnthony Liguori ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn; 1192f28d2ffSAnthony Liguori ti->num_interfaces++; 1202f28d2ffSAnthony Liguori } 1212f28d2ffSAnthony Liguori } 1222f28d2ffSAnthony Liguori 1232f28d2ffSAnthony Liguori type_table_add(ti); 1242f28d2ffSAnthony Liguori 1252f28d2ffSAnthony Liguori return ti; 1262f28d2ffSAnthony Liguori } 1272f28d2ffSAnthony Liguori 1282f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1292f28d2ffSAnthony Liguori { 1302f28d2ffSAnthony Liguori return type_register(info); 1312f28d2ffSAnthony Liguori } 1322f28d2ffSAnthony Liguori 1332f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1342f28d2ffSAnthony Liguori { 1352f28d2ffSAnthony Liguori if (name == NULL) { 1362f28d2ffSAnthony Liguori return NULL; 1372f28d2ffSAnthony Liguori } 1382f28d2ffSAnthony Liguori 1392f28d2ffSAnthony Liguori return type_table_lookup(name); 1402f28d2ffSAnthony Liguori } 1412f28d2ffSAnthony Liguori 1422f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1432f28d2ffSAnthony Liguori { 1442f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1452f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 1462f28d2ffSAnthony Liguori g_assert(type->parent_type != NULL); 1472f28d2ffSAnthony Liguori } 1482f28d2ffSAnthony Liguori 1492f28d2ffSAnthony Liguori return type->parent_type; 1502f28d2ffSAnthony Liguori } 1512f28d2ffSAnthony Liguori 1522f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1532f28d2ffSAnthony Liguori { 1542f28d2ffSAnthony Liguori return (type->parent != NULL); 1552f28d2ffSAnthony Liguori } 1562f28d2ffSAnthony Liguori 1572f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1582f28d2ffSAnthony Liguori { 1592f28d2ffSAnthony Liguori if (ti->class_size) { 1602f28d2ffSAnthony Liguori return ti->class_size; 1612f28d2ffSAnthony Liguori } 1622f28d2ffSAnthony Liguori 1632f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 1642f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 1652f28d2ffSAnthony Liguori } 1662f28d2ffSAnthony Liguori 1672f28d2ffSAnthony Liguori return sizeof(ObjectClass); 1682f28d2ffSAnthony Liguori } 1692f28d2ffSAnthony Liguori 1702f28d2ffSAnthony Liguori static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface) 1712f28d2ffSAnthony Liguori { 1722f28d2ffSAnthony Liguori TypeInfo info = { 1732f28d2ffSAnthony Liguori .instance_size = sizeof(Interface), 1742f28d2ffSAnthony Liguori .parent = iface->parent, 1752f28d2ffSAnthony Liguori .class_size = sizeof(InterfaceClass), 1762f28d2ffSAnthony Liguori .class_init = iface->interface_initfn, 1772f28d2ffSAnthony Liguori .abstract = true, 1782f28d2ffSAnthony Liguori }; 1792f28d2ffSAnthony Liguori char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent); 1802f28d2ffSAnthony Liguori 1812f28d2ffSAnthony Liguori info.name = name; 1822f28d2ffSAnthony Liguori iface->type = type_register(&info); 1832f28d2ffSAnthony Liguori g_free(name); 1842f28d2ffSAnthony Liguori } 1852f28d2ffSAnthony Liguori 1862f28d2ffSAnthony Liguori static void type_class_init(TypeImpl *ti) 1872f28d2ffSAnthony Liguori { 1882f28d2ffSAnthony Liguori size_t class_size = sizeof(ObjectClass); 1892f28d2ffSAnthony Liguori int i; 1902f28d2ffSAnthony Liguori 1912f28d2ffSAnthony Liguori if (ti->class) { 1922f28d2ffSAnthony Liguori return; 1932f28d2ffSAnthony Liguori } 1942f28d2ffSAnthony Liguori 1952f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 1962f28d2ffSAnthony Liguori 1972f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 1982f28d2ffSAnthony Liguori ti->class->type = ti; 1992f28d2ffSAnthony Liguori 2002f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 2012f28d2ffSAnthony Liguori TypeImpl *parent = type_get_parent(ti); 2022f28d2ffSAnthony Liguori 2032f28d2ffSAnthony Liguori type_class_init(parent); 2042f28d2ffSAnthony Liguori 2052f28d2ffSAnthony Liguori class_size = parent->class_size; 2062f28d2ffSAnthony Liguori g_assert(parent->class_size <= ti->class_size); 2072f28d2ffSAnthony Liguori 2082f28d2ffSAnthony Liguori memcpy((void *)ti->class + sizeof(ObjectClass), 2092f28d2ffSAnthony Liguori (void *)parent->class + sizeof(ObjectClass), 2102f28d2ffSAnthony Liguori parent->class_size - sizeof(ObjectClass)); 2112f28d2ffSAnthony Liguori } 2122f28d2ffSAnthony Liguori 2132f28d2ffSAnthony Liguori memset((void *)ti->class + class_size, 0, ti->class_size - class_size); 2142f28d2ffSAnthony Liguori 2152f28d2ffSAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 2162f28d2ffSAnthony Liguori type_class_interface_init(ti, &ti->interfaces[i]); 2172f28d2ffSAnthony Liguori } 2182f28d2ffSAnthony Liguori 2192f28d2ffSAnthony Liguori if (ti->class_init) { 2202f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 2212f28d2ffSAnthony Liguori } 2222f28d2ffSAnthony Liguori } 2232f28d2ffSAnthony Liguori 2242f28d2ffSAnthony Liguori static void object_interface_init(Object *obj, InterfaceImpl *iface) 2252f28d2ffSAnthony Liguori { 2262f28d2ffSAnthony Liguori TypeImpl *ti = iface->type; 2272f28d2ffSAnthony Liguori Interface *iface_obj; 2282f28d2ffSAnthony Liguori 2292f28d2ffSAnthony Liguori iface_obj = INTERFACE(object_new(ti->name)); 2302f28d2ffSAnthony Liguori iface_obj->obj = obj; 2312f28d2ffSAnthony Liguori 2322f28d2ffSAnthony Liguori obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj); 2332f28d2ffSAnthony Liguori } 2342f28d2ffSAnthony Liguori 2352f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 2362f28d2ffSAnthony Liguori { 2372f28d2ffSAnthony Liguori int i; 2382f28d2ffSAnthony Liguori 2392f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 2402f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 2412f28d2ffSAnthony Liguori } 2422f28d2ffSAnthony Liguori 2432f28d2ffSAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 2442f28d2ffSAnthony Liguori object_interface_init(obj, &ti->interfaces[i]); 2452f28d2ffSAnthony Liguori } 2462f28d2ffSAnthony Liguori 2472f28d2ffSAnthony Liguori if (ti->instance_init) { 2482f28d2ffSAnthony Liguori ti->instance_init(obj); 2492f28d2ffSAnthony Liguori } 2502f28d2ffSAnthony Liguori } 2512f28d2ffSAnthony Liguori 2522f28d2ffSAnthony Liguori void object_initialize_with_type(void *data, TypeImpl *type) 2532f28d2ffSAnthony Liguori { 2542f28d2ffSAnthony Liguori Object *obj = data; 2552f28d2ffSAnthony Liguori 2562f28d2ffSAnthony Liguori g_assert(type != NULL); 2572f28d2ffSAnthony Liguori g_assert(type->instance_size >= sizeof(ObjectClass)); 2582f28d2ffSAnthony Liguori 2592f28d2ffSAnthony Liguori type_class_init(type); 2602f28d2ffSAnthony Liguori g_assert(type->abstract == false); 2612f28d2ffSAnthony Liguori 2622f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 2632f28d2ffSAnthony Liguori obj->class = type->class; 26457c9fafeSAnthony Liguori QTAILQ_INIT(&obj->properties); 2652f28d2ffSAnthony Liguori object_init_with_type(obj, type); 2662f28d2ffSAnthony Liguori } 2672f28d2ffSAnthony Liguori 2682f28d2ffSAnthony Liguori void object_initialize(void *data, const char *typename) 2692f28d2ffSAnthony Liguori { 2702f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 2712f28d2ffSAnthony Liguori 2722f28d2ffSAnthony Liguori object_initialize_with_type(data, type); 2732f28d2ffSAnthony Liguori } 2742f28d2ffSAnthony Liguori 27557c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 27657c9fafeSAnthony Liguori { 27757c9fafeSAnthony Liguori while (!QTAILQ_EMPTY(&obj->properties)) { 27857c9fafeSAnthony Liguori ObjectProperty *prop = QTAILQ_FIRST(&obj->properties); 27957c9fafeSAnthony Liguori 28057c9fafeSAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 28157c9fafeSAnthony Liguori 28257c9fafeSAnthony Liguori if (prop->release) { 28357c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 28457c9fafeSAnthony Liguori } 28557c9fafeSAnthony Liguori 28657c9fafeSAnthony Liguori g_free(prop->name); 28757c9fafeSAnthony Liguori g_free(prop->type); 28857c9fafeSAnthony Liguori g_free(prop); 28957c9fafeSAnthony Liguori } 29057c9fafeSAnthony Liguori } 29157c9fafeSAnthony Liguori 29257c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 29357c9fafeSAnthony Liguori { 29457c9fafeSAnthony Liguori ObjectProperty *prop; 29557c9fafeSAnthony Liguori 29657c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 29757c9fafeSAnthony Liguori if (!strstart(prop->type, "child<", NULL)) { 29857c9fafeSAnthony Liguori continue; 29957c9fafeSAnthony Liguori } 30057c9fafeSAnthony Liguori 30157c9fafeSAnthony Liguori if (prop->opaque == child) { 30257c9fafeSAnthony Liguori object_property_del(obj, prop->name, errp); 30357c9fafeSAnthony Liguori } 30457c9fafeSAnthony Liguori } 30557c9fafeSAnthony Liguori } 30657c9fafeSAnthony Liguori 30757c9fafeSAnthony Liguori void object_unparent(Object *obj) 30857c9fafeSAnthony Liguori { 30957c9fafeSAnthony Liguori if (obj->parent) { 31057c9fafeSAnthony Liguori object_property_del_child(obj->parent, obj, NULL); 31157c9fafeSAnthony Liguori } 31257c9fafeSAnthony Liguori } 31357c9fafeSAnthony Liguori 3142f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 3152f28d2ffSAnthony Liguori { 3162f28d2ffSAnthony Liguori if (type->instance_finalize) { 3172f28d2ffSAnthony Liguori type->instance_finalize(obj); 3182f28d2ffSAnthony Liguori } 3192f28d2ffSAnthony Liguori 3202f28d2ffSAnthony Liguori while (obj->interfaces) { 3212f28d2ffSAnthony Liguori Interface *iface_obj = obj->interfaces->data; 3222f28d2ffSAnthony Liguori obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces); 3232f28d2ffSAnthony Liguori object_delete(OBJECT(iface_obj)); 3242f28d2ffSAnthony Liguori } 3252f28d2ffSAnthony Liguori 3262f28d2ffSAnthony Liguori if (type_has_parent(type)) { 3272f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 3282f28d2ffSAnthony Liguori } 32957c9fafeSAnthony Liguori 33057c9fafeSAnthony Liguori object_unparent(obj); 3312f28d2ffSAnthony Liguori } 3322f28d2ffSAnthony Liguori 3332f28d2ffSAnthony Liguori void object_finalize(void *data) 3342f28d2ffSAnthony Liguori { 3352f28d2ffSAnthony Liguori Object *obj = data; 3362f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 3372f28d2ffSAnthony Liguori 3382f28d2ffSAnthony Liguori object_deinit(obj, ti); 33957c9fafeSAnthony Liguori object_property_del_all(obj); 3402f28d2ffSAnthony Liguori } 3412f28d2ffSAnthony Liguori 3422f28d2ffSAnthony Liguori Object *object_new_with_type(Type type) 3432f28d2ffSAnthony Liguori { 3442f28d2ffSAnthony Liguori Object *obj; 3452f28d2ffSAnthony Liguori 3462f28d2ffSAnthony Liguori g_assert(type != NULL); 3472f28d2ffSAnthony Liguori 3482f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 3492f28d2ffSAnthony Liguori object_initialize_with_type(obj, type); 3502f28d2ffSAnthony Liguori 3512f28d2ffSAnthony Liguori return obj; 3522f28d2ffSAnthony Liguori } 3532f28d2ffSAnthony Liguori 3542f28d2ffSAnthony Liguori Object *object_new(const char *typename) 3552f28d2ffSAnthony Liguori { 3562f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 3572f28d2ffSAnthony Liguori 3582f28d2ffSAnthony Liguori return object_new_with_type(ti); 3592f28d2ffSAnthony Liguori } 3602f28d2ffSAnthony Liguori 3612f28d2ffSAnthony Liguori void object_delete(Object *obj) 3622f28d2ffSAnthony Liguori { 3632f28d2ffSAnthony Liguori object_finalize(obj); 3642f28d2ffSAnthony Liguori g_free(obj); 3652f28d2ffSAnthony Liguori } 3662f28d2ffSAnthony Liguori 3672f28d2ffSAnthony Liguori static bool object_is_type(Object *obj, const char *typename) 3682f28d2ffSAnthony Liguori { 3692f28d2ffSAnthony Liguori TypeImpl *target_type = type_get_by_name(typename); 3702f28d2ffSAnthony Liguori TypeImpl *type = obj->class->type; 3712f28d2ffSAnthony Liguori GSList *i; 3722f28d2ffSAnthony Liguori 3732f28d2ffSAnthony Liguori /* Check if typename is a direct ancestor of type */ 3742f28d2ffSAnthony Liguori while (type) { 3752f28d2ffSAnthony Liguori if (type == target_type) { 3762f28d2ffSAnthony Liguori return true; 3772f28d2ffSAnthony Liguori } 3782f28d2ffSAnthony Liguori 3792f28d2ffSAnthony Liguori type = type_get_parent(type); 3802f28d2ffSAnthony Liguori } 3812f28d2ffSAnthony Liguori 3822f28d2ffSAnthony Liguori /* Check if obj has an interface of typename */ 3832f28d2ffSAnthony Liguori for (i = obj->interfaces; i; i = i->next) { 3842f28d2ffSAnthony Liguori Interface *iface = i->data; 3852f28d2ffSAnthony Liguori 3862f28d2ffSAnthony Liguori if (object_is_type(OBJECT(iface), typename)) { 3872f28d2ffSAnthony Liguori return true; 3882f28d2ffSAnthony Liguori } 3892f28d2ffSAnthony Liguori } 3902f28d2ffSAnthony Liguori 3912f28d2ffSAnthony Liguori return false; 3922f28d2ffSAnthony Liguori } 3932f28d2ffSAnthony Liguori 3942f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 3952f28d2ffSAnthony Liguori { 3962f28d2ffSAnthony Liguori GSList *i; 3972f28d2ffSAnthony Liguori 3982f28d2ffSAnthony Liguori /* Check if typename is a direct ancestor */ 3992f28d2ffSAnthony Liguori if (object_is_type(obj, typename)) { 4002f28d2ffSAnthony Liguori return obj; 4012f28d2ffSAnthony Liguori } 4022f28d2ffSAnthony Liguori 4032f28d2ffSAnthony Liguori /* Check if obj has an interface of typename */ 4042f28d2ffSAnthony Liguori for (i = obj->interfaces; i; i = i->next) { 4052f28d2ffSAnthony Liguori Interface *iface = i->data; 4062f28d2ffSAnthony Liguori 4072f28d2ffSAnthony Liguori if (object_is_type(OBJECT(iface), typename)) { 4082f28d2ffSAnthony Liguori return OBJECT(iface); 4092f28d2ffSAnthony Liguori } 4102f28d2ffSAnthony Liguori } 4112f28d2ffSAnthony Liguori 4122f28d2ffSAnthony Liguori /* Check if obj is an interface and its containing object is a direct 4132f28d2ffSAnthony Liguori * ancestor of typename */ 4142f28d2ffSAnthony Liguori if (object_is_type(obj, TYPE_INTERFACE)) { 4152f28d2ffSAnthony Liguori Interface *iface = INTERFACE(obj); 4162f28d2ffSAnthony Liguori 4172f28d2ffSAnthony Liguori if (object_is_type(iface->obj, typename)) { 4182f28d2ffSAnthony Liguori return iface->obj; 4192f28d2ffSAnthony Liguori } 4202f28d2ffSAnthony Liguori } 4212f28d2ffSAnthony Liguori 4222f28d2ffSAnthony Liguori return NULL; 4232f28d2ffSAnthony Liguori } 4242f28d2ffSAnthony Liguori 4252f28d2ffSAnthony Liguori 4262f28d2ffSAnthony Liguori static void register_interface(void) 4272f28d2ffSAnthony Liguori { 4282f28d2ffSAnthony Liguori static TypeInfo interface_info = { 4292f28d2ffSAnthony Liguori .name = TYPE_INTERFACE, 4302f28d2ffSAnthony Liguori .instance_size = sizeof(Interface), 4312f28d2ffSAnthony Liguori .abstract = true, 4322f28d2ffSAnthony Liguori }; 4332f28d2ffSAnthony Liguori 4342f28d2ffSAnthony Liguori type_register_static(&interface_info); 4352f28d2ffSAnthony Liguori } 4362f28d2ffSAnthony Liguori 4372f28d2ffSAnthony Liguori device_init(register_interface); 4382f28d2ffSAnthony Liguori 4392f28d2ffSAnthony Liguori Object *object_dynamic_cast_assert(Object *obj, const char *typename) 4402f28d2ffSAnthony Liguori { 4412f28d2ffSAnthony Liguori Object *inst; 4422f28d2ffSAnthony Liguori 4432f28d2ffSAnthony Liguori inst = object_dynamic_cast(obj, typename); 4442f28d2ffSAnthony Liguori 4452f28d2ffSAnthony Liguori if (!inst) { 4462f28d2ffSAnthony Liguori fprintf(stderr, "Object %p is not an instance of type %s\n", 4472f28d2ffSAnthony Liguori obj, typename); 4482f28d2ffSAnthony Liguori abort(); 4492f28d2ffSAnthony Liguori } 4502f28d2ffSAnthony Liguori 4512f28d2ffSAnthony Liguori return inst; 4522f28d2ffSAnthony Liguori } 4532f28d2ffSAnthony Liguori 4542f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 4552f28d2ffSAnthony Liguori const char *typename) 4562f28d2ffSAnthony Liguori { 4572f28d2ffSAnthony Liguori TypeImpl *target_type = type_get_by_name(typename); 4582f28d2ffSAnthony Liguori TypeImpl *type = class->type; 4592f28d2ffSAnthony Liguori 4602f28d2ffSAnthony Liguori while (type) { 4612f28d2ffSAnthony Liguori if (type == target_type) { 4622f28d2ffSAnthony Liguori return class; 4632f28d2ffSAnthony Liguori } 4642f28d2ffSAnthony Liguori 4652f28d2ffSAnthony Liguori type = type_get_parent(type); 4662f28d2ffSAnthony Liguori } 4672f28d2ffSAnthony Liguori 4682f28d2ffSAnthony Liguori return NULL; 4692f28d2ffSAnthony Liguori } 4702f28d2ffSAnthony Liguori 4712f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 4722f28d2ffSAnthony Liguori const char *typename) 4732f28d2ffSAnthony Liguori { 4742f28d2ffSAnthony Liguori ObjectClass *ret = object_class_dynamic_cast(class, typename); 4752f28d2ffSAnthony Liguori 4762f28d2ffSAnthony Liguori if (!ret) { 4772f28d2ffSAnthony Liguori fprintf(stderr, "Object %p is not an instance of type %s\n", 4782f28d2ffSAnthony Liguori class, typename); 4792f28d2ffSAnthony Liguori abort(); 4802f28d2ffSAnthony Liguori } 4812f28d2ffSAnthony Liguori 4822f28d2ffSAnthony Liguori return ret; 4832f28d2ffSAnthony Liguori } 4842f28d2ffSAnthony Liguori 4852f28d2ffSAnthony Liguori const char *object_get_typename(Object *obj) 4862f28d2ffSAnthony Liguori { 4872f28d2ffSAnthony Liguori return obj->class->type->name; 4882f28d2ffSAnthony Liguori } 4892f28d2ffSAnthony Liguori 4902f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 4912f28d2ffSAnthony Liguori { 4922f28d2ffSAnthony Liguori return obj->class; 4932f28d2ffSAnthony Liguori } 4942f28d2ffSAnthony Liguori 4952f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 4962f28d2ffSAnthony Liguori { 4972f28d2ffSAnthony Liguori return klass->type->name; 4982f28d2ffSAnthony Liguori } 4992f28d2ffSAnthony Liguori 5002f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 5012f28d2ffSAnthony Liguori { 5022f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 5032f28d2ffSAnthony Liguori 5042f28d2ffSAnthony Liguori if (!type) { 5052f28d2ffSAnthony Liguori return NULL; 5062f28d2ffSAnthony Liguori } 5072f28d2ffSAnthony Liguori 5082f28d2ffSAnthony Liguori type_class_init(type); 5092f28d2ffSAnthony Liguori 5102f28d2ffSAnthony Liguori return type->class; 5112f28d2ffSAnthony Liguori } 5122f28d2ffSAnthony Liguori 5132f28d2ffSAnthony Liguori typedef struct OCFData 5142f28d2ffSAnthony Liguori { 5152f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 51693c511a1SAnthony Liguori const char *implements_type; 51793c511a1SAnthony Liguori bool include_abstract; 5182f28d2ffSAnthony Liguori void *opaque; 5192f28d2ffSAnthony Liguori } OCFData; 5202f28d2ffSAnthony Liguori 5212f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 5222f28d2ffSAnthony Liguori gpointer opaque) 5232f28d2ffSAnthony Liguori { 5242f28d2ffSAnthony Liguori OCFData *data = opaque; 5252f28d2ffSAnthony Liguori TypeImpl *type = value; 52693c511a1SAnthony Liguori ObjectClass *k; 5272f28d2ffSAnthony Liguori 5282f28d2ffSAnthony Liguori type_class_init(type); 52993c511a1SAnthony Liguori k = type->class; 5302f28d2ffSAnthony Liguori 53193c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 53293c511a1SAnthony Liguori return; 53393c511a1SAnthony Liguori } 53493c511a1SAnthony Liguori 53593c511a1SAnthony Liguori if (data->implements_type && 53693c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 53793c511a1SAnthony Liguori return; 53893c511a1SAnthony Liguori } 53993c511a1SAnthony Liguori 54093c511a1SAnthony Liguori data->fn(k, data->opaque); 5412f28d2ffSAnthony Liguori } 5422f28d2ffSAnthony Liguori 5432f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 54493c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 5452f28d2ffSAnthony Liguori void *opaque) 5462f28d2ffSAnthony Liguori { 54793c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 5482f28d2ffSAnthony Liguori 5492f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 5502f28d2ffSAnthony Liguori } 55157c9fafeSAnthony Liguori 55257c9fafeSAnthony Liguori void object_ref(Object *obj) 55357c9fafeSAnthony Liguori { 55457c9fafeSAnthony Liguori obj->ref++; 55557c9fafeSAnthony Liguori } 55657c9fafeSAnthony Liguori 55757c9fafeSAnthony Liguori void object_unref(Object *obj) 55857c9fafeSAnthony Liguori { 55957c9fafeSAnthony Liguori g_assert(obj->ref > 0); 56057c9fafeSAnthony Liguori obj->ref--; 56157c9fafeSAnthony Liguori 56257c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 56357c9fafeSAnthony Liguori if (obj->ref == 0) { 56457c9fafeSAnthony Liguori object_finalize(obj); 56557c9fafeSAnthony Liguori } 56657c9fafeSAnthony Liguori } 56757c9fafeSAnthony Liguori 56857c9fafeSAnthony Liguori void object_property_add(Object *obj, const char *name, const char *type, 56957c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 57057c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 57157c9fafeSAnthony Liguori ObjectPropertyRelease *release, 57257c9fafeSAnthony Liguori void *opaque, Error **errp) 57357c9fafeSAnthony Liguori { 57457c9fafeSAnthony Liguori ObjectProperty *prop = g_malloc0(sizeof(*prop)); 57557c9fafeSAnthony Liguori 57657c9fafeSAnthony Liguori prop->name = g_strdup(name); 57757c9fafeSAnthony Liguori prop->type = g_strdup(type); 57857c9fafeSAnthony Liguori 57957c9fafeSAnthony Liguori prop->get = get; 58057c9fafeSAnthony Liguori prop->set = set; 58157c9fafeSAnthony Liguori prop->release = release; 58257c9fafeSAnthony Liguori prop->opaque = opaque; 58357c9fafeSAnthony Liguori 58457c9fafeSAnthony Liguori QTAILQ_INSERT_TAIL(&obj->properties, prop, node); 58557c9fafeSAnthony Liguori } 58657c9fafeSAnthony Liguori 58757c9fafeSAnthony Liguori static ObjectProperty *object_property_find(Object *obj, const char *name) 58857c9fafeSAnthony Liguori { 58957c9fafeSAnthony Liguori ObjectProperty *prop; 59057c9fafeSAnthony Liguori 59157c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->properties, node) { 59257c9fafeSAnthony Liguori if (strcmp(prop->name, name) == 0) { 59357c9fafeSAnthony Liguori return prop; 59457c9fafeSAnthony Liguori } 59557c9fafeSAnthony Liguori } 59657c9fafeSAnthony Liguori 59757c9fafeSAnthony Liguori return NULL; 59857c9fafeSAnthony Liguori } 59957c9fafeSAnthony Liguori 60057c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 60157c9fafeSAnthony Liguori { 60257c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 60357c9fafeSAnthony Liguori 60457c9fafeSAnthony Liguori QTAILQ_REMOVE(&obj->properties, prop, node); 60557c9fafeSAnthony Liguori 60657c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 60757c9fafeSAnthony Liguori 60857c9fafeSAnthony Liguori g_free(prop->name); 60957c9fafeSAnthony Liguori g_free(prop->type); 61057c9fafeSAnthony Liguori g_free(prop); 61157c9fafeSAnthony Liguori } 61257c9fafeSAnthony Liguori 61357c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 61457c9fafeSAnthony Liguori Error **errp) 61557c9fafeSAnthony Liguori { 61657c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 61757c9fafeSAnthony Liguori 61857c9fafeSAnthony Liguori if (prop == NULL) { 61957c9fafeSAnthony Liguori error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); 62057c9fafeSAnthony Liguori return; 62157c9fafeSAnthony Liguori } 62257c9fafeSAnthony Liguori 62357c9fafeSAnthony Liguori if (!prop->get) { 62457c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 62557c9fafeSAnthony Liguori } else { 62657c9fafeSAnthony Liguori prop->get(obj, v, prop->opaque, name, errp); 62757c9fafeSAnthony Liguori } 62857c9fafeSAnthony Liguori } 62957c9fafeSAnthony Liguori 63057c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 63157c9fafeSAnthony Liguori Error **errp) 63257c9fafeSAnthony Liguori { 63357c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 63457c9fafeSAnthony Liguori 63557c9fafeSAnthony Liguori if (prop == NULL) { 63657c9fafeSAnthony Liguori error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); 63757c9fafeSAnthony Liguori return; 63857c9fafeSAnthony Liguori } 63957c9fafeSAnthony Liguori 64057c9fafeSAnthony Liguori if (!prop->set) { 64157c9fafeSAnthony Liguori error_set(errp, QERR_PERMISSION_DENIED); 64257c9fafeSAnthony Liguori } else { 64357c9fafeSAnthony Liguori prop->set(obj, v, prop->opaque, name, errp); 64457c9fafeSAnthony Liguori } 64557c9fafeSAnthony Liguori } 64657c9fafeSAnthony Liguori 64757c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 64857c9fafeSAnthony Liguori { 64957c9fafeSAnthony Liguori ObjectProperty *prop = object_property_find(obj, name); 65057c9fafeSAnthony Liguori 65157c9fafeSAnthony Liguori if (prop == NULL) { 65257c9fafeSAnthony Liguori error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name); 65357c9fafeSAnthony Liguori return NULL; 65457c9fafeSAnthony Liguori } 65557c9fafeSAnthony Liguori 65657c9fafeSAnthony Liguori return prop->type; 65757c9fafeSAnthony Liguori } 65857c9fafeSAnthony Liguori 65957c9fafeSAnthony Liguori Object *object_get_root(void) 66057c9fafeSAnthony Liguori { 66157c9fafeSAnthony Liguori static DeviceState *object_root; 66257c9fafeSAnthony Liguori 66357c9fafeSAnthony Liguori if (!object_root) { 66457c9fafeSAnthony Liguori object_root = qdev_create(NULL, "container"); 66557c9fafeSAnthony Liguori qdev_init_nofail(object_root); 66657c9fafeSAnthony Liguori } 66757c9fafeSAnthony Liguori 66857c9fafeSAnthony Liguori return OBJECT(object_root); 66957c9fafeSAnthony Liguori } 67057c9fafeSAnthony Liguori 67157c9fafeSAnthony Liguori static void object_get_child_property(Object *obj, Visitor *v, void *opaque, 67257c9fafeSAnthony Liguori const char *name, Error **errp) 67357c9fafeSAnthony Liguori { 67457c9fafeSAnthony Liguori Object *child = opaque; 67557c9fafeSAnthony Liguori gchar *path; 67657c9fafeSAnthony Liguori 67757c9fafeSAnthony Liguori path = object_get_canonical_path(child); 67857c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 67957c9fafeSAnthony Liguori g_free(path); 68057c9fafeSAnthony Liguori } 68157c9fafeSAnthony Liguori 68257c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 68357c9fafeSAnthony Liguori Object *child, Error **errp) 68457c9fafeSAnthony Liguori { 68557c9fafeSAnthony Liguori gchar *type; 68657c9fafeSAnthony Liguori 68757c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 68857c9fafeSAnthony Liguori 68957c9fafeSAnthony Liguori object_property_add(obj, name, type, object_get_child_property, 69057c9fafeSAnthony Liguori NULL, NULL, child, errp); 69157c9fafeSAnthony Liguori 69257c9fafeSAnthony Liguori object_ref(child); 69357c9fafeSAnthony Liguori g_assert(child->parent == NULL); 69457c9fafeSAnthony Liguori child->parent = obj; 69557c9fafeSAnthony Liguori 69657c9fafeSAnthony Liguori g_free(type); 69757c9fafeSAnthony Liguori } 69857c9fafeSAnthony Liguori 69957c9fafeSAnthony Liguori static void object_get_link_property(Object *obj, Visitor *v, void *opaque, 70057c9fafeSAnthony Liguori const char *name, Error **errp) 70157c9fafeSAnthony Liguori { 70257c9fafeSAnthony Liguori Object **child = opaque; 70357c9fafeSAnthony Liguori gchar *path; 70457c9fafeSAnthony Liguori 70557c9fafeSAnthony Liguori if (*child) { 70657c9fafeSAnthony Liguori path = object_get_canonical_path(*child); 70757c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 70857c9fafeSAnthony Liguori g_free(path); 70957c9fafeSAnthony Liguori } else { 71057c9fafeSAnthony Liguori path = (gchar *)""; 71157c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 71257c9fafeSAnthony Liguori } 71357c9fafeSAnthony Liguori } 71457c9fafeSAnthony Liguori 71557c9fafeSAnthony Liguori static void object_set_link_property(Object *obj, Visitor *v, void *opaque, 71657c9fafeSAnthony Liguori const char *name, Error **errp) 71757c9fafeSAnthony Liguori { 71857c9fafeSAnthony Liguori Object **child = opaque; 71957c9fafeSAnthony Liguori bool ambiguous = false; 72057c9fafeSAnthony Liguori const char *type; 72157c9fafeSAnthony Liguori char *path; 72257c9fafeSAnthony Liguori 72357c9fafeSAnthony Liguori type = object_property_get_type(obj, name, NULL); 72457c9fafeSAnthony Liguori 72557c9fafeSAnthony Liguori visit_type_str(v, &path, name, errp); 72657c9fafeSAnthony Liguori 72757c9fafeSAnthony Liguori if (*child) { 72857c9fafeSAnthony Liguori object_unref(*child); 72957c9fafeSAnthony Liguori } 73057c9fafeSAnthony Liguori 73157c9fafeSAnthony Liguori if (strcmp(path, "") != 0) { 73257c9fafeSAnthony Liguori Object *target; 73357c9fafeSAnthony Liguori 73457c9fafeSAnthony Liguori target = object_resolve_path(path, &ambiguous); 73557c9fafeSAnthony Liguori if (target) { 73657c9fafeSAnthony Liguori gchar *target_type; 73757c9fafeSAnthony Liguori 738*fe40e627SAnthony Liguori target_type = g_strdup(&type[5]); 739*fe40e627SAnthony Liguori target_type[strlen(target_type) - 2] = 0; 740*fe40e627SAnthony Liguori 741*fe40e627SAnthony Liguori if (object_dynamic_cast(target, target_type)) { 74257c9fafeSAnthony Liguori object_ref(target); 743*fe40e627SAnthony Liguori *child = target; 74457c9fafeSAnthony Liguori } else { 74557c9fafeSAnthony Liguori error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type); 74657c9fafeSAnthony Liguori } 74757c9fafeSAnthony Liguori 74857c9fafeSAnthony Liguori g_free(target_type); 74957c9fafeSAnthony Liguori } else { 75057c9fafeSAnthony Liguori error_set(errp, QERR_DEVICE_NOT_FOUND, path); 75157c9fafeSAnthony Liguori } 75257c9fafeSAnthony Liguori } else { 75357c9fafeSAnthony Liguori *child = NULL; 75457c9fafeSAnthony Liguori } 75557c9fafeSAnthony Liguori 75657c9fafeSAnthony Liguori g_free(path); 75757c9fafeSAnthony Liguori } 75857c9fafeSAnthony Liguori 75957c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name, 76057c9fafeSAnthony Liguori const char *type, Object **child, 76157c9fafeSAnthony Liguori Error **errp) 76257c9fafeSAnthony Liguori { 76357c9fafeSAnthony Liguori gchar *full_type; 76457c9fafeSAnthony Liguori 76557c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 76657c9fafeSAnthony Liguori 76757c9fafeSAnthony Liguori object_property_add(obj, name, full_type, 76857c9fafeSAnthony Liguori object_get_link_property, 76957c9fafeSAnthony Liguori object_set_link_property, 77057c9fafeSAnthony Liguori NULL, child, errp); 77157c9fafeSAnthony Liguori 77257c9fafeSAnthony Liguori g_free(full_type); 77357c9fafeSAnthony Liguori } 77457c9fafeSAnthony Liguori 77557c9fafeSAnthony Liguori gchar *object_get_canonical_path(Object *obj) 77657c9fafeSAnthony Liguori { 77757c9fafeSAnthony Liguori Object *root = object_get_root(); 77857c9fafeSAnthony Liguori char *newpath = NULL, *path = NULL; 77957c9fafeSAnthony Liguori 78057c9fafeSAnthony Liguori while (obj != root) { 78157c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 78257c9fafeSAnthony Liguori 78357c9fafeSAnthony Liguori g_assert(obj->parent != NULL); 78457c9fafeSAnthony Liguori 78557c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &obj->parent->properties, node) { 78657c9fafeSAnthony Liguori if (!strstart(prop->type, "child<", NULL)) { 78757c9fafeSAnthony Liguori continue; 78857c9fafeSAnthony Liguori } 78957c9fafeSAnthony Liguori 79057c9fafeSAnthony Liguori if (prop->opaque == obj) { 79157c9fafeSAnthony Liguori if (path) { 79257c9fafeSAnthony Liguori newpath = g_strdup_printf("%s/%s", prop->name, path); 79357c9fafeSAnthony Liguori g_free(path); 79457c9fafeSAnthony Liguori path = newpath; 79557c9fafeSAnthony Liguori } else { 79657c9fafeSAnthony Liguori path = g_strdup(prop->name); 79757c9fafeSAnthony Liguori } 79857c9fafeSAnthony Liguori break; 79957c9fafeSAnthony Liguori } 80057c9fafeSAnthony Liguori } 80157c9fafeSAnthony Liguori 80257c9fafeSAnthony Liguori g_assert(prop != NULL); 80357c9fafeSAnthony Liguori 80457c9fafeSAnthony Liguori obj = obj->parent; 80557c9fafeSAnthony Liguori } 80657c9fafeSAnthony Liguori 80757c9fafeSAnthony Liguori newpath = g_strdup_printf("/%s", path); 80857c9fafeSAnthony Liguori g_free(path); 80957c9fafeSAnthony Liguori 81057c9fafeSAnthony Liguori return newpath; 81157c9fafeSAnthony Liguori } 81257c9fafeSAnthony Liguori 81357c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 81457c9fafeSAnthony Liguori gchar **parts, 81557c9fafeSAnthony Liguori int index) 81657c9fafeSAnthony Liguori { 81757c9fafeSAnthony Liguori ObjectProperty *prop; 81857c9fafeSAnthony Liguori Object *child; 81957c9fafeSAnthony Liguori 82057c9fafeSAnthony Liguori if (parts[index] == NULL) { 82157c9fafeSAnthony Liguori return parent; 82257c9fafeSAnthony Liguori } 82357c9fafeSAnthony Liguori 82457c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 82557c9fafeSAnthony Liguori return object_resolve_abs_path(parent, parts, index + 1); 82657c9fafeSAnthony Liguori } 82757c9fafeSAnthony Liguori 82857c9fafeSAnthony Liguori prop = object_property_find(parent, parts[index]); 82957c9fafeSAnthony Liguori if (prop == NULL) { 83057c9fafeSAnthony Liguori return NULL; 83157c9fafeSAnthony Liguori } 83257c9fafeSAnthony Liguori 83357c9fafeSAnthony Liguori child = NULL; 83457c9fafeSAnthony Liguori if (strstart(prop->type, "link<", NULL)) { 83557c9fafeSAnthony Liguori Object **pchild = prop->opaque; 83657c9fafeSAnthony Liguori if (*pchild) { 83757c9fafeSAnthony Liguori child = *pchild; 83857c9fafeSAnthony Liguori } 83957c9fafeSAnthony Liguori } else if (strstart(prop->type, "child<", NULL)) { 84057c9fafeSAnthony Liguori child = prop->opaque; 84157c9fafeSAnthony Liguori } 84257c9fafeSAnthony Liguori 84357c9fafeSAnthony Liguori if (!child) { 84457c9fafeSAnthony Liguori return NULL; 84557c9fafeSAnthony Liguori } 84657c9fafeSAnthony Liguori 84757c9fafeSAnthony Liguori return object_resolve_abs_path(child, parts, index + 1); 84857c9fafeSAnthony Liguori } 84957c9fafeSAnthony Liguori 85057c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 85157c9fafeSAnthony Liguori gchar **parts, 85257c9fafeSAnthony Liguori bool *ambiguous) 85357c9fafeSAnthony Liguori { 85457c9fafeSAnthony Liguori Object *obj; 85557c9fafeSAnthony Liguori ObjectProperty *prop; 85657c9fafeSAnthony Liguori 85757c9fafeSAnthony Liguori obj = object_resolve_abs_path(parent, parts, 0); 85857c9fafeSAnthony Liguori 85957c9fafeSAnthony Liguori QTAILQ_FOREACH(prop, &parent->properties, node) { 86057c9fafeSAnthony Liguori Object *found; 86157c9fafeSAnthony Liguori 86257c9fafeSAnthony Liguori if (!strstart(prop->type, "child<", NULL)) { 86357c9fafeSAnthony Liguori continue; 86457c9fafeSAnthony Liguori } 86557c9fafeSAnthony Liguori 86657c9fafeSAnthony Liguori found = object_resolve_partial_path(prop->opaque, parts, ambiguous); 86757c9fafeSAnthony Liguori if (found) { 86857c9fafeSAnthony Liguori if (obj) { 86957c9fafeSAnthony Liguori if (ambiguous) { 87057c9fafeSAnthony Liguori *ambiguous = true; 87157c9fafeSAnthony Liguori } 87257c9fafeSAnthony Liguori return NULL; 87357c9fafeSAnthony Liguori } 87457c9fafeSAnthony Liguori obj = found; 87557c9fafeSAnthony Liguori } 87657c9fafeSAnthony Liguori 87757c9fafeSAnthony Liguori if (ambiguous && *ambiguous) { 87857c9fafeSAnthony Liguori return NULL; 87957c9fafeSAnthony Liguori } 88057c9fafeSAnthony Liguori } 88157c9fafeSAnthony Liguori 88257c9fafeSAnthony Liguori return obj; 88357c9fafeSAnthony Liguori } 88457c9fafeSAnthony Liguori 88557c9fafeSAnthony Liguori Object *object_resolve_path(const char *path, bool *ambiguous) 88657c9fafeSAnthony Liguori { 88757c9fafeSAnthony Liguori bool partial_path = true; 88857c9fafeSAnthony Liguori Object *obj; 88957c9fafeSAnthony Liguori gchar **parts; 89057c9fafeSAnthony Liguori 89157c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 89257c9fafeSAnthony Liguori if (parts == NULL || parts[0] == NULL) { 89357c9fafeSAnthony Liguori g_strfreev(parts); 89457c9fafeSAnthony Liguori return object_get_root(); 89557c9fafeSAnthony Liguori } 89657c9fafeSAnthony Liguori 89757c9fafeSAnthony Liguori if (strcmp(parts[0], "") == 0) { 89857c9fafeSAnthony Liguori partial_path = false; 89957c9fafeSAnthony Liguori } 90057c9fafeSAnthony Liguori 90157c9fafeSAnthony Liguori if (partial_path) { 90257c9fafeSAnthony Liguori if (ambiguous) { 90357c9fafeSAnthony Liguori *ambiguous = false; 90457c9fafeSAnthony Liguori } 90557c9fafeSAnthony Liguori obj = object_resolve_partial_path(object_get_root(), parts, ambiguous); 90657c9fafeSAnthony Liguori } else { 90757c9fafeSAnthony Liguori obj = object_resolve_abs_path(object_get_root(), parts, 1); 90857c9fafeSAnthony Liguori } 90957c9fafeSAnthony Liguori 91057c9fafeSAnthony Liguori g_strfreev(parts); 91157c9fafeSAnthony Liguori 91257c9fafeSAnthony Liguori return obj; 91357c9fafeSAnthony Liguori } 91457c9fafeSAnthony Liguori 91557c9fafeSAnthony Liguori typedef struct StringProperty 91657c9fafeSAnthony Liguori { 91757c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 91857c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 91957c9fafeSAnthony Liguori } StringProperty; 92057c9fafeSAnthony Liguori 92157c9fafeSAnthony Liguori static void object_property_get_str(Object *obj, Visitor *v, void *opaque, 92257c9fafeSAnthony Liguori const char *name, Error **errp) 92357c9fafeSAnthony Liguori { 92457c9fafeSAnthony Liguori StringProperty *prop = opaque; 92557c9fafeSAnthony Liguori char *value; 92657c9fafeSAnthony Liguori 92757c9fafeSAnthony Liguori value = prop->get(obj, errp); 92857c9fafeSAnthony Liguori if (value) { 92957c9fafeSAnthony Liguori visit_type_str(v, &value, name, errp); 93057c9fafeSAnthony Liguori g_free(value); 93157c9fafeSAnthony Liguori } 93257c9fafeSAnthony Liguori } 93357c9fafeSAnthony Liguori 93457c9fafeSAnthony Liguori static void object_property_set_str(Object *obj, Visitor *v, void *opaque, 93557c9fafeSAnthony Liguori const char *name, Error **errp) 93657c9fafeSAnthony Liguori { 93757c9fafeSAnthony Liguori StringProperty *prop = opaque; 93857c9fafeSAnthony Liguori char *value; 93957c9fafeSAnthony Liguori Error *local_err = NULL; 94057c9fafeSAnthony Liguori 94157c9fafeSAnthony Liguori visit_type_str(v, &value, name, &local_err); 94257c9fafeSAnthony Liguori if (local_err) { 94357c9fafeSAnthony Liguori error_propagate(errp, local_err); 94457c9fafeSAnthony Liguori return; 94557c9fafeSAnthony Liguori } 94657c9fafeSAnthony Liguori 94757c9fafeSAnthony Liguori prop->set(obj, value, errp); 94857c9fafeSAnthony Liguori g_free(value); 94957c9fafeSAnthony Liguori } 95057c9fafeSAnthony Liguori 95157c9fafeSAnthony Liguori static void object_property_release_str(Object *obj, const char *name, 95257c9fafeSAnthony Liguori void *opaque) 95357c9fafeSAnthony Liguori { 95457c9fafeSAnthony Liguori StringProperty *prop = opaque; 95557c9fafeSAnthony Liguori g_free(prop); 95657c9fafeSAnthony Liguori } 95757c9fafeSAnthony Liguori 95857c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 95957c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 96057c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 96157c9fafeSAnthony Liguori Error **errp) 96257c9fafeSAnthony Liguori { 96357c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 96457c9fafeSAnthony Liguori 96557c9fafeSAnthony Liguori prop->get = get; 96657c9fafeSAnthony Liguori prop->set = set; 96757c9fafeSAnthony Liguori 96857c9fafeSAnthony Liguori object_property_add(obj, name, "string", 96957c9fafeSAnthony Liguori get ? object_property_get_str : NULL, 97057c9fafeSAnthony Liguori set ? object_property_set_str : NULL, 97157c9fafeSAnthony Liguori object_property_release_str, 97257c9fafeSAnthony Liguori prop, errp); 97357c9fafeSAnthony Liguori } 974