xref: /qemu/qom/object.c (revision fe40e627)
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