xref: /qemu/qom/object.c (revision 7c47c4ea)
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 
139bbc853bSPeter Maydell #include "qemu/osdep.h"
14da34e65cSMarkus Armbruster #include "qapi/error.h"
1514cccb61SPaolo Bonzini #include "qom/object.h"
16a31bdae5SDaniel P. Berrange #include "qom/object_interfaces.h"
17f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
187b1b5d19SPaolo Bonzini #include "qapi/visitor.h"
191f21772dSHu Tao #include "qapi-visit.h"
20b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h"
21b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h"
227b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h"
23fa131d94SPaolo Bonzini #include "trace.h"
242f28d2ffSAnthony Liguori 
257b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency
267b7b7d18SPaolo Bonzini  * of the QOM core on QObject?  */
2714cccb61SPaolo Bonzini #include "qom/qom-qobject.h"
287b1b5d19SPaolo Bonzini #include "qapi/qmp/qobject.h"
297b1b5d19SPaolo Bonzini #include "qapi/qmp/qbool.h"
307b1b5d19SPaolo Bonzini #include "qapi/qmp/qstring.h"
317b7b7d18SPaolo Bonzini 
322f28d2ffSAnthony Liguori #define MAX_INTERFACES 32
332f28d2ffSAnthony Liguori 
342f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl;
352f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl;
362f28d2ffSAnthony Liguori 
372f28d2ffSAnthony Liguori struct InterfaceImpl
382f28d2ffSAnthony Liguori {
3933e95c63SAnthony Liguori     const char *typename;
402f28d2ffSAnthony Liguori };
412f28d2ffSAnthony Liguori 
422f28d2ffSAnthony Liguori struct TypeImpl
432f28d2ffSAnthony Liguori {
442f28d2ffSAnthony Liguori     const char *name;
452f28d2ffSAnthony Liguori 
462f28d2ffSAnthony Liguori     size_t class_size;
472f28d2ffSAnthony Liguori 
482f28d2ffSAnthony Liguori     size_t instance_size;
492f28d2ffSAnthony Liguori 
502f28d2ffSAnthony Liguori     void (*class_init)(ObjectClass *klass, void *data);
513b50e311SPaolo Bonzini     void (*class_base_init)(ObjectClass *klass, void *data);
522f28d2ffSAnthony Liguori     void (*class_finalize)(ObjectClass *klass, void *data);
532f28d2ffSAnthony Liguori 
542f28d2ffSAnthony Liguori     void *class_data;
552f28d2ffSAnthony Liguori 
562f28d2ffSAnthony Liguori     void (*instance_init)(Object *obj);
578231c2ddSEduardo Habkost     void (*instance_post_init)(Object *obj);
582f28d2ffSAnthony Liguori     void (*instance_finalize)(Object *obj);
592f28d2ffSAnthony Liguori 
602f28d2ffSAnthony Liguori     bool abstract;
612f28d2ffSAnthony Liguori 
622f28d2ffSAnthony Liguori     const char *parent;
632f28d2ffSAnthony Liguori     TypeImpl *parent_type;
642f28d2ffSAnthony Liguori 
652f28d2ffSAnthony Liguori     ObjectClass *class;
662f28d2ffSAnthony Liguori 
672f28d2ffSAnthony Liguori     int num_interfaces;
682f28d2ffSAnthony Liguori     InterfaceImpl interfaces[MAX_INTERFACES];
692f28d2ffSAnthony Liguori };
702f28d2ffSAnthony Liguori 
719970bd88SPaolo Bonzini static Type type_interface;
729970bd88SPaolo Bonzini 
732f28d2ffSAnthony Liguori static GHashTable *type_table_get(void)
742f28d2ffSAnthony Liguori {
752f28d2ffSAnthony Liguori     static GHashTable *type_table;
762f28d2ffSAnthony Liguori 
772f28d2ffSAnthony Liguori     if (type_table == NULL) {
782f28d2ffSAnthony Liguori         type_table = g_hash_table_new(g_str_hash, g_str_equal);
792f28d2ffSAnthony Liguori     }
802f28d2ffSAnthony Liguori 
812f28d2ffSAnthony Liguori     return type_table;
822f28d2ffSAnthony Liguori }
832f28d2ffSAnthony Liguori 
84f54c19caSHervé Poussineau static bool enumerating_types;
85f54c19caSHervé Poussineau 
862f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti)
872f28d2ffSAnthony Liguori {
88f54c19caSHervé Poussineau     assert(!enumerating_types);
892f28d2ffSAnthony Liguori     g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
902f28d2ffSAnthony Liguori }
912f28d2ffSAnthony Liguori 
922f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name)
932f28d2ffSAnthony Liguori {
942f28d2ffSAnthony Liguori     return g_hash_table_lookup(type_table_get(), name);
952f28d2ffSAnthony Liguori }
962f28d2ffSAnthony Liguori 
97b061dc41SPaolo Bonzini static TypeImpl *type_new(const TypeInfo *info)
982f28d2ffSAnthony Liguori {
992f28d2ffSAnthony Liguori     TypeImpl *ti = g_malloc0(sizeof(*ti));
10033e95c63SAnthony Liguori     int i;
1012f28d2ffSAnthony Liguori 
1022f28d2ffSAnthony Liguori     g_assert(info->name != NULL);
1032f28d2ffSAnthony Liguori 
10473093354SAnthony Liguori     if (type_table_lookup(info->name) != NULL) {
10573093354SAnthony Liguori         fprintf(stderr, "Registering `%s' which already exists\n", info->name);
10673093354SAnthony Liguori         abort();
10773093354SAnthony Liguori     }
10873093354SAnthony Liguori 
1092f28d2ffSAnthony Liguori     ti->name = g_strdup(info->name);
1102f28d2ffSAnthony Liguori     ti->parent = g_strdup(info->parent);
1112f28d2ffSAnthony Liguori 
1122f28d2ffSAnthony Liguori     ti->class_size = info->class_size;
1132f28d2ffSAnthony Liguori     ti->instance_size = info->instance_size;
1142f28d2ffSAnthony Liguori 
1152f28d2ffSAnthony Liguori     ti->class_init = info->class_init;
1163b50e311SPaolo Bonzini     ti->class_base_init = info->class_base_init;
1172f28d2ffSAnthony Liguori     ti->class_finalize = info->class_finalize;
1182f28d2ffSAnthony Liguori     ti->class_data = info->class_data;
1192f28d2ffSAnthony Liguori 
1202f28d2ffSAnthony Liguori     ti->instance_init = info->instance_init;
1218231c2ddSEduardo Habkost     ti->instance_post_init = info->instance_post_init;
1222f28d2ffSAnthony Liguori     ti->instance_finalize = info->instance_finalize;
1232f28d2ffSAnthony Liguori 
1242f28d2ffSAnthony Liguori     ti->abstract = info->abstract;
1252f28d2ffSAnthony Liguori 
12633e95c63SAnthony Liguori     for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
12733e95c63SAnthony Liguori         ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
1282f28d2ffSAnthony Liguori     }
12933e95c63SAnthony Liguori     ti->num_interfaces = i;
1302f28d2ffSAnthony Liguori 
131b061dc41SPaolo Bonzini     return ti;
132b061dc41SPaolo Bonzini }
1332f28d2ffSAnthony Liguori 
134b061dc41SPaolo Bonzini static TypeImpl *type_register_internal(const TypeInfo *info)
135b061dc41SPaolo Bonzini {
136b061dc41SPaolo Bonzini     TypeImpl *ti;
137b061dc41SPaolo Bonzini     ti = type_new(info);
138b061dc41SPaolo Bonzini 
139b061dc41SPaolo Bonzini     type_table_add(ti);
1402f28d2ffSAnthony Liguori     return ti;
1412f28d2ffSAnthony Liguori }
1422f28d2ffSAnthony Liguori 
143049cb3cfSPaolo Bonzini TypeImpl *type_register(const TypeInfo *info)
144049cb3cfSPaolo Bonzini {
145049cb3cfSPaolo Bonzini     assert(info->parent);
146049cb3cfSPaolo Bonzini     return type_register_internal(info);
147049cb3cfSPaolo Bonzini }
148049cb3cfSPaolo Bonzini 
1492f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info)
1502f28d2ffSAnthony Liguori {
1512f28d2ffSAnthony Liguori     return type_register(info);
1522f28d2ffSAnthony Liguori }
1532f28d2ffSAnthony Liguori 
1542f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name)
1552f28d2ffSAnthony Liguori {
1562f28d2ffSAnthony Liguori     if (name == NULL) {
1572f28d2ffSAnthony Liguori         return NULL;
1582f28d2ffSAnthony Liguori     }
1592f28d2ffSAnthony Liguori 
1602f28d2ffSAnthony Liguori     return type_table_lookup(name);
1612f28d2ffSAnthony Liguori }
1622f28d2ffSAnthony Liguori 
1632f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type)
1642f28d2ffSAnthony Liguori {
1652f28d2ffSAnthony Liguori     if (!type->parent_type && type->parent) {
1662f28d2ffSAnthony Liguori         type->parent_type = type_get_by_name(type->parent);
1672f28d2ffSAnthony Liguori         g_assert(type->parent_type != NULL);
1682f28d2ffSAnthony Liguori     }
1692f28d2ffSAnthony Liguori 
1702f28d2ffSAnthony Liguori     return type->parent_type;
1712f28d2ffSAnthony Liguori }
1722f28d2ffSAnthony Liguori 
1732f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type)
1742f28d2ffSAnthony Liguori {
1752f28d2ffSAnthony Liguori     return (type->parent != NULL);
1762f28d2ffSAnthony Liguori }
1772f28d2ffSAnthony Liguori 
1782f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti)
1792f28d2ffSAnthony Liguori {
1802f28d2ffSAnthony Liguori     if (ti->class_size) {
1812f28d2ffSAnthony Liguori         return ti->class_size;
1822f28d2ffSAnthony Liguori     }
1832f28d2ffSAnthony Liguori 
1842f28d2ffSAnthony Liguori     if (type_has_parent(ti)) {
1852f28d2ffSAnthony Liguori         return type_class_get_size(type_get_parent(ti));
1862f28d2ffSAnthony Liguori     }
1872f28d2ffSAnthony Liguori 
1882f28d2ffSAnthony Liguori     return sizeof(ObjectClass);
1892f28d2ffSAnthony Liguori }
1902f28d2ffSAnthony Liguori 
191aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti)
192aca59af6SIgor Mitsyanko {
193aca59af6SIgor Mitsyanko     if (ti->instance_size) {
194aca59af6SIgor Mitsyanko         return ti->instance_size;
195aca59af6SIgor Mitsyanko     }
196aca59af6SIgor Mitsyanko 
197aca59af6SIgor Mitsyanko     if (type_has_parent(ti)) {
198aca59af6SIgor Mitsyanko         return type_object_get_size(type_get_parent(ti));
199aca59af6SIgor Mitsyanko     }
200aca59af6SIgor Mitsyanko 
201aca59af6SIgor Mitsyanko     return 0;
202aca59af6SIgor Mitsyanko }
203aca59af6SIgor Mitsyanko 
2043f97b53aSBharata B Rao size_t object_type_get_instance_size(const char *typename)
2053f97b53aSBharata B Rao {
2063f97b53aSBharata B Rao     TypeImpl *type = type_get_by_name(typename);
2073f97b53aSBharata B Rao 
2083f97b53aSBharata B Rao     g_assert(type != NULL);
2093f97b53aSBharata B Rao     return type_object_get_size(type);
2103f97b53aSBharata B Rao }
2113f97b53aSBharata B Rao 
21233e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
2132f28d2ffSAnthony Liguori {
21433e95c63SAnthony Liguori     assert(target_type);
2152f28d2ffSAnthony Liguori 
216b30d8054SCao jin     /* Check if target_type is a direct ancestor of type */
21733e95c63SAnthony Liguori     while (type) {
21833e95c63SAnthony Liguori         if (type == target_type) {
21933e95c63SAnthony Liguori             return true;
22033e95c63SAnthony Liguori         }
22133e95c63SAnthony Liguori 
22233e95c63SAnthony Liguori         type = type_get_parent(type);
22333e95c63SAnthony Liguori     }
22433e95c63SAnthony Liguori 
22533e95c63SAnthony Liguori     return false;
22633e95c63SAnthony Liguori }
22733e95c63SAnthony Liguori 
22833e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti);
22933e95c63SAnthony Liguori 
230b061dc41SPaolo Bonzini static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type,
231b061dc41SPaolo Bonzini                                       TypeImpl *parent_type)
23233e95c63SAnthony Liguori {
23333e95c63SAnthony Liguori     InterfaceClass *new_iface;
23433e95c63SAnthony Liguori     TypeInfo info = { };
23533e95c63SAnthony Liguori     TypeImpl *iface_impl;
23633e95c63SAnthony Liguori 
237b061dc41SPaolo Bonzini     info.parent = parent_type->name;
238b061dc41SPaolo Bonzini     info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name);
23933e95c63SAnthony Liguori     info.abstract = true;
24033e95c63SAnthony Liguori 
241b061dc41SPaolo Bonzini     iface_impl = type_new(&info);
242b061dc41SPaolo Bonzini     iface_impl->parent_type = parent_type;
24333e95c63SAnthony Liguori     type_initialize(iface_impl);
24433e95c63SAnthony Liguori     g_free((char *)info.name);
24533e95c63SAnthony Liguori 
24633e95c63SAnthony Liguori     new_iface = (InterfaceClass *)iface_impl->class;
24733e95c63SAnthony Liguori     new_iface->concrete_class = ti->class;
248b061dc41SPaolo Bonzini     new_iface->interface_type = interface_type;
24933e95c63SAnthony Liguori 
25033e95c63SAnthony Liguori     ti->class->interfaces = g_slist_append(ti->class->interfaces,
25133e95c63SAnthony Liguori                                            iface_impl->class);
2522f28d2ffSAnthony Liguori }
2532f28d2ffSAnthony Liguori 
25416bf7f52SDaniel P. Berrange static void object_property_free(gpointer data)
25516bf7f52SDaniel P. Berrange {
25616bf7f52SDaniel P. Berrange     ObjectProperty *prop = data;
25716bf7f52SDaniel P. Berrange 
25816bf7f52SDaniel P. Berrange     g_free(prop->name);
25916bf7f52SDaniel P. Berrange     g_free(prop->type);
26016bf7f52SDaniel P. Berrange     g_free(prop->description);
26116bf7f52SDaniel P. Berrange     g_free(prop);
26216bf7f52SDaniel P. Berrange }
26316bf7f52SDaniel P. Berrange 
264ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti)
2652f28d2ffSAnthony Liguori {
266745549c8SPaolo Bonzini     TypeImpl *parent;
2672f28d2ffSAnthony Liguori 
2682f28d2ffSAnthony Liguori     if (ti->class) {
2692f28d2ffSAnthony Liguori         return;
2702f28d2ffSAnthony Liguori     }
2712f28d2ffSAnthony Liguori 
2722f28d2ffSAnthony Liguori     ti->class_size = type_class_get_size(ti);
273aca59af6SIgor Mitsyanko     ti->instance_size = type_object_get_size(ti);
2741c6d75d5SEduardo Habkost     /* Any type with zero instance_size is implicitly abstract.
2751c6d75d5SEduardo Habkost      * This means interface types are all abstract.
2761c6d75d5SEduardo Habkost      */
2771c6d75d5SEduardo Habkost     if (ti->instance_size == 0) {
2781c6d75d5SEduardo Habkost         ti->abstract = true;
2791c6d75d5SEduardo Habkost     }
2802f28d2ffSAnthony Liguori 
2812f28d2ffSAnthony Liguori     ti->class = g_malloc0(ti->class_size);
2822f28d2ffSAnthony Liguori 
283745549c8SPaolo Bonzini     parent = type_get_parent(ti);
284745549c8SPaolo Bonzini     if (parent) {
285ac451033SIgor Mitsyanko         type_initialize(parent);
28633e95c63SAnthony Liguori         GSList *e;
28733e95c63SAnthony Liguori         int i;
2882f28d2ffSAnthony Liguori 
2898438a135SAndreas Färber         g_assert_cmpint(parent->class_size, <=, ti->class_size);
290745549c8SPaolo Bonzini         memcpy(ti->class, parent->class, parent->class_size);
2913e407de4SPeter Crosthwaite         ti->class->interfaces = NULL;
29216bf7f52SDaniel P. Berrange         ti->class->properties = g_hash_table_new_full(
29316bf7f52SDaniel P. Berrange             g_str_hash, g_str_equal, g_free, object_property_free);
29433e95c63SAnthony Liguori 
29533e95c63SAnthony Liguori         for (e = parent->class->interfaces; e; e = e->next) {
296b061dc41SPaolo Bonzini             InterfaceClass *iface = e->data;
297b061dc41SPaolo Bonzini             ObjectClass *klass = OBJECT_CLASS(iface);
298b061dc41SPaolo Bonzini 
299b061dc41SPaolo Bonzini             type_initialize_interface(ti, iface->interface_type, klass->type);
30033e95c63SAnthony Liguori         }
30133e95c63SAnthony Liguori 
30233e95c63SAnthony Liguori         for (i = 0; i < ti->num_interfaces; i++) {
30333e95c63SAnthony Liguori             TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
30433e95c63SAnthony Liguori             for (e = ti->class->interfaces; e; e = e->next) {
30533e95c63SAnthony Liguori                 TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
30633e95c63SAnthony Liguori 
30733e95c63SAnthony Liguori                 if (type_is_ancestor(target_type, t)) {
30833e95c63SAnthony Liguori                     break;
30933e95c63SAnthony Liguori                 }
31033e95c63SAnthony Liguori             }
31133e95c63SAnthony Liguori 
31233e95c63SAnthony Liguori             if (e) {
31333e95c63SAnthony Liguori                 continue;
31433e95c63SAnthony Liguori             }
31533e95c63SAnthony Liguori 
316b061dc41SPaolo Bonzini             type_initialize_interface(ti, t, t);
31733e95c63SAnthony Liguori         }
31816bf7f52SDaniel P. Berrange     } else {
31916bf7f52SDaniel P. Berrange         ti->class->properties = g_hash_table_new_full(
32016bf7f52SDaniel P. Berrange             g_str_hash, g_str_equal, g_free, object_property_free);
321745549c8SPaolo Bonzini     }
3222f28d2ffSAnthony Liguori 
323745549c8SPaolo Bonzini     ti->class->type = ti;
3243b50e311SPaolo Bonzini 
3253b50e311SPaolo Bonzini     while (parent) {
3263b50e311SPaolo Bonzini         if (parent->class_base_init) {
3273b50e311SPaolo Bonzini             parent->class_base_init(ti->class, ti->class_data);
3283b50e311SPaolo Bonzini         }
3293b50e311SPaolo Bonzini         parent = type_get_parent(parent);
3303b50e311SPaolo Bonzini     }
3312f28d2ffSAnthony Liguori 
3322f28d2ffSAnthony Liguori     if (ti->class_init) {
3332f28d2ffSAnthony Liguori         ti->class_init(ti->class, ti->class_data);
3342f28d2ffSAnthony Liguori     }
3352f28d2ffSAnthony Liguori }
3362f28d2ffSAnthony Liguori 
3372f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti)
3382f28d2ffSAnthony Liguori {
3392f28d2ffSAnthony Liguori     if (type_has_parent(ti)) {
3402f28d2ffSAnthony Liguori         object_init_with_type(obj, type_get_parent(ti));
3412f28d2ffSAnthony Liguori     }
3422f28d2ffSAnthony Liguori 
3432f28d2ffSAnthony Liguori     if (ti->instance_init) {
3442f28d2ffSAnthony Liguori         ti->instance_init(obj);
3452f28d2ffSAnthony Liguori     }
3462f28d2ffSAnthony Liguori }
3472f28d2ffSAnthony Liguori 
3488231c2ddSEduardo Habkost static void object_post_init_with_type(Object *obj, TypeImpl *ti)
3498231c2ddSEduardo Habkost {
3508231c2ddSEduardo Habkost     if (ti->instance_post_init) {
3518231c2ddSEduardo Habkost         ti->instance_post_init(obj);
3528231c2ddSEduardo Habkost     }
3538231c2ddSEduardo Habkost 
3548231c2ddSEduardo Habkost     if (type_has_parent(ti)) {
3558231c2ddSEduardo Habkost         object_post_init_with_type(obj, type_get_parent(ti));
3568231c2ddSEduardo Habkost     }
3578231c2ddSEduardo Habkost }
3588231c2ddSEduardo Habkost 
35963f7b10bSMarc-André Lureau static void object_initialize_with_type(void *data, size_t size, TypeImpl *type)
3602f28d2ffSAnthony Liguori {
3612f28d2ffSAnthony Liguori     Object *obj = data;
3622f28d2ffSAnthony Liguori 
3632f28d2ffSAnthony Liguori     g_assert(type != NULL);
364ac451033SIgor Mitsyanko     type_initialize(type);
365aca59af6SIgor Mitsyanko 
3668438a135SAndreas Färber     g_assert_cmpint(type->instance_size, >=, sizeof(Object));
3672f28d2ffSAnthony Liguori     g_assert(type->abstract == false);
3688438a135SAndreas Färber     g_assert_cmpint(size, >=, type->instance_size);
3692f28d2ffSAnthony Liguori 
3702f28d2ffSAnthony Liguori     memset(obj, 0, type->instance_size);
3712f28d2ffSAnthony Liguori     obj->class = type->class;
372764b6312SPaolo Bonzini     object_ref(obj);
373b604a854SPavel Fedin     obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
374b604a854SPavel Fedin                                             NULL, object_property_free);
3752f28d2ffSAnthony Liguori     object_init_with_type(obj, type);
3768231c2ddSEduardo Habkost     object_post_init_with_type(obj, type);
3772f28d2ffSAnthony Liguori }
3782f28d2ffSAnthony Liguori 
379213f0c4fSAndreas Färber void object_initialize(void *data, size_t size, const char *typename)
3802f28d2ffSAnthony Liguori {
3812f28d2ffSAnthony Liguori     TypeImpl *type = type_get_by_name(typename);
3822f28d2ffSAnthony Liguori 
3835b9237f6SAndreas Färber     object_initialize_with_type(data, size, type);
3842f28d2ffSAnthony Liguori }
3852f28d2ffSAnthony Liguori 
3865d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop)
3875d9d3f47SAndreas Färber {
3885d9d3f47SAndreas Färber     return strstart(prop->type, "child<", NULL);
3895d9d3f47SAndreas Färber }
3905d9d3f47SAndreas Färber 
39157c9fafeSAnthony Liguori static void object_property_del_all(Object *obj)
39257c9fafeSAnthony Liguori {
393b604a854SPavel Fedin     ObjectProperty *prop;
394b604a854SPavel Fedin     GHashTableIter iter;
395b604a854SPavel Fedin     gpointer key, value;
396b604a854SPavel Fedin     bool released;
39757c9fafeSAnthony Liguori 
398b604a854SPavel Fedin     do {
399b604a854SPavel Fedin         released = false;
400b604a854SPavel Fedin         g_hash_table_iter_init(&iter, obj->properties);
401b604a854SPavel Fedin         while (g_hash_table_iter_next(&iter, &key, &value)) {
402b604a854SPavel Fedin             prop = value;
40357c9fafeSAnthony Liguori             if (prop->release) {
40457c9fafeSAnthony Liguori                 prop->release(obj, prop->name, prop->opaque);
405b604a854SPavel Fedin                 prop->release = NULL;
406b604a854SPavel Fedin                 released = true;
407b604a854SPavel Fedin                 break;
40857c9fafeSAnthony Liguori             }
409b604a854SPavel Fedin             g_hash_table_iter_remove(&iter);
410b604a854SPavel Fedin         }
411b604a854SPavel Fedin     } while (released);
41257c9fafeSAnthony Liguori 
413b604a854SPavel Fedin     g_hash_table_unref(obj->properties);
41457c9fafeSAnthony Liguori }
41557c9fafeSAnthony Liguori 
41657c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp)
41757c9fafeSAnthony Liguori {
41857c9fafeSAnthony Liguori     ObjectProperty *prop;
419b604a854SPavel Fedin     GHashTableIter iter;
420b604a854SPavel Fedin     gpointer key, value;
42157c9fafeSAnthony Liguori 
422b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->properties);
423b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, &key, &value)) {
424b604a854SPavel Fedin         prop = value;
4255d9d3f47SAndreas Färber         if (object_property_is_child(prop) && prop->opaque == child) {
426b604a854SPavel Fedin             if (prop->release) {
427b604a854SPavel Fedin                 prop->release(obj, prop->name, prop->opaque);
428b604a854SPavel Fedin                 prop->release = NULL;
429b604a854SPavel Fedin             }
430b604a854SPavel Fedin             break;
431b604a854SPavel Fedin         }
432b604a854SPavel Fedin     }
433b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->properties);
434b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, &key, &value)) {
435b604a854SPavel Fedin         prop = value;
436b604a854SPavel Fedin         if (object_property_is_child(prop) && prop->opaque == child) {
437b604a854SPavel Fedin             g_hash_table_iter_remove(&iter);
4386c1fdcf9SPaolo Bonzini             break;
43957c9fafeSAnthony Liguori         }
44057c9fafeSAnthony Liguori     }
44157c9fafeSAnthony Liguori }
44257c9fafeSAnthony Liguori 
44357c9fafeSAnthony Liguori void object_unparent(Object *obj)
44457c9fafeSAnthony Liguori {
445e998fa8dSMichael S. Tsirkin     if (obj->parent) {
446e998fa8dSMichael S. Tsirkin         object_property_del_child(obj->parent, obj, NULL);
447e998fa8dSMichael S. Tsirkin     }
44857c9fafeSAnthony Liguori }
44957c9fafeSAnthony Liguori 
4502f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type)
4512f28d2ffSAnthony Liguori {
4522f28d2ffSAnthony Liguori     if (type->instance_finalize) {
4532f28d2ffSAnthony Liguori         type->instance_finalize(obj);
4542f28d2ffSAnthony Liguori     }
4552f28d2ffSAnthony Liguori 
4562f28d2ffSAnthony Liguori     if (type_has_parent(type)) {
4572f28d2ffSAnthony Liguori         object_deinit(obj, type_get_parent(type));
4582f28d2ffSAnthony Liguori     }
4592f28d2ffSAnthony Liguori }
4602f28d2ffSAnthony Liguori 
461339c2708SPaolo Bonzini static void object_finalize(void *data)
4622f28d2ffSAnthony Liguori {
4632f28d2ffSAnthony Liguori     Object *obj = data;
4642f28d2ffSAnthony Liguori     TypeImpl *ti = obj->class->type;
4652f28d2ffSAnthony Liguori 
46657c9fafeSAnthony Liguori     object_property_del_all(obj);
46776a6e1ccSPaolo Bonzini     object_deinit(obj, ti);
468db85b575SAnthony Liguori 
4698438a135SAndreas Färber     g_assert_cmpint(obj->ref, ==, 0);
470fde9bf44SPaolo Bonzini     if (obj->free) {
471fde9bf44SPaolo Bonzini         obj->free(obj);
472fde9bf44SPaolo Bonzini     }
4732f28d2ffSAnthony Liguori }
4742f28d2ffSAnthony Liguori 
47563f7b10bSMarc-André Lureau static Object *object_new_with_type(Type type)
4762f28d2ffSAnthony Liguori {
4772f28d2ffSAnthony Liguori     Object *obj;
4782f28d2ffSAnthony Liguori 
4792f28d2ffSAnthony Liguori     g_assert(type != NULL);
480ac451033SIgor Mitsyanko     type_initialize(type);
4812f28d2ffSAnthony Liguori 
4822f28d2ffSAnthony Liguori     obj = g_malloc(type->instance_size);
4835b9237f6SAndreas Färber     object_initialize_with_type(obj, type->instance_size, type);
484fde9bf44SPaolo Bonzini     obj->free = g_free;
4852f28d2ffSAnthony Liguori 
4862f28d2ffSAnthony Liguori     return obj;
4872f28d2ffSAnthony Liguori }
4882f28d2ffSAnthony Liguori 
4892f28d2ffSAnthony Liguori Object *object_new(const char *typename)
4902f28d2ffSAnthony Liguori {
4912f28d2ffSAnthony Liguori     TypeImpl *ti = type_get_by_name(typename);
4922f28d2ffSAnthony Liguori 
4932f28d2ffSAnthony Liguori     return object_new_with_type(ti);
4942f28d2ffSAnthony Liguori }
4952f28d2ffSAnthony Liguori 
496a31bdae5SDaniel P. Berrange 
497a31bdae5SDaniel P. Berrange Object *object_new_with_props(const char *typename,
498a31bdae5SDaniel P. Berrange                               Object *parent,
499a31bdae5SDaniel P. Berrange                               const char *id,
500a31bdae5SDaniel P. Berrange                               Error **errp,
501a31bdae5SDaniel P. Berrange                               ...)
502a31bdae5SDaniel P. Berrange {
503a31bdae5SDaniel P. Berrange     va_list vargs;
504a31bdae5SDaniel P. Berrange     Object *obj;
505a31bdae5SDaniel P. Berrange 
506a31bdae5SDaniel P. Berrange     va_start(vargs, errp);
507a31bdae5SDaniel P. Berrange     obj = object_new_with_propv(typename, parent, id, errp, vargs);
508a31bdae5SDaniel P. Berrange     va_end(vargs);
509a31bdae5SDaniel P. Berrange 
510a31bdae5SDaniel P. Berrange     return obj;
511a31bdae5SDaniel P. Berrange }
512a31bdae5SDaniel P. Berrange 
513a31bdae5SDaniel P. Berrange 
514a31bdae5SDaniel P. Berrange Object *object_new_with_propv(const char *typename,
515a31bdae5SDaniel P. Berrange                               Object *parent,
516a31bdae5SDaniel P. Berrange                               const char *id,
517a31bdae5SDaniel P. Berrange                               Error **errp,
518a31bdae5SDaniel P. Berrange                               va_list vargs)
519a31bdae5SDaniel P. Berrange {
520a31bdae5SDaniel P. Berrange     Object *obj;
521a31bdae5SDaniel P. Berrange     ObjectClass *klass;
522a31bdae5SDaniel P. Berrange     Error *local_err = NULL;
523a31bdae5SDaniel P. Berrange 
524a31bdae5SDaniel P. Berrange     klass = object_class_by_name(typename);
525a31bdae5SDaniel P. Berrange     if (!klass) {
526a31bdae5SDaniel P. Berrange         error_setg(errp, "invalid object type: %s", typename);
527a31bdae5SDaniel P. Berrange         return NULL;
528a31bdae5SDaniel P. Berrange     }
529a31bdae5SDaniel P. Berrange 
530a31bdae5SDaniel P. Berrange     if (object_class_is_abstract(klass)) {
531a31bdae5SDaniel P. Berrange         error_setg(errp, "object type '%s' is abstract", typename);
532a31bdae5SDaniel P. Berrange         return NULL;
533a31bdae5SDaniel P. Berrange     }
534a31bdae5SDaniel P. Berrange     obj = object_new(typename);
535a31bdae5SDaniel P. Berrange 
536a31bdae5SDaniel P. Berrange     if (object_set_propv(obj, &local_err, vargs) < 0) {
537a31bdae5SDaniel P. Berrange         goto error;
538a31bdae5SDaniel P. Berrange     }
539a31bdae5SDaniel P. Berrange 
540a31bdae5SDaniel P. Berrange     object_property_add_child(parent, id, obj, &local_err);
541a31bdae5SDaniel P. Berrange     if (local_err) {
542a31bdae5SDaniel P. Berrange         goto error;
543a31bdae5SDaniel P. Berrange     }
544a31bdae5SDaniel P. Berrange 
545a31bdae5SDaniel P. Berrange     if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
546a31bdae5SDaniel P. Berrange         user_creatable_complete(obj, &local_err);
547a31bdae5SDaniel P. Berrange         if (local_err) {
548a31bdae5SDaniel P. Berrange             object_unparent(obj);
549a31bdae5SDaniel P. Berrange             goto error;
550a31bdae5SDaniel P. Berrange         }
551a31bdae5SDaniel P. Berrange     }
552a31bdae5SDaniel P. Berrange 
553a31bdae5SDaniel P. Berrange     object_unref(OBJECT(obj));
554a31bdae5SDaniel P. Berrange     return obj;
555a31bdae5SDaniel P. Berrange 
556a31bdae5SDaniel P. Berrange  error:
557a31bdae5SDaniel P. Berrange     error_propagate(errp, local_err);
558a31bdae5SDaniel P. Berrange     object_unref(obj);
559a31bdae5SDaniel P. Berrange     return NULL;
560a31bdae5SDaniel P. Berrange }
561a31bdae5SDaniel P. Berrange 
562a31bdae5SDaniel P. Berrange 
563a31bdae5SDaniel P. Berrange int object_set_props(Object *obj,
564a31bdae5SDaniel P. Berrange                      Error **errp,
565a31bdae5SDaniel P. Berrange                      ...)
566a31bdae5SDaniel P. Berrange {
567a31bdae5SDaniel P. Berrange     va_list vargs;
568a31bdae5SDaniel P. Berrange     int ret;
569a31bdae5SDaniel P. Berrange 
570a31bdae5SDaniel P. Berrange     va_start(vargs, errp);
571a31bdae5SDaniel P. Berrange     ret = object_set_propv(obj, errp, vargs);
572a31bdae5SDaniel P. Berrange     va_end(vargs);
573a31bdae5SDaniel P. Berrange 
574a31bdae5SDaniel P. Berrange     return ret;
575a31bdae5SDaniel P. Berrange }
576a31bdae5SDaniel P. Berrange 
577a31bdae5SDaniel P. Berrange 
578a31bdae5SDaniel P. Berrange int object_set_propv(Object *obj,
579a31bdae5SDaniel P. Berrange                      Error **errp,
580a31bdae5SDaniel P. Berrange                      va_list vargs)
581a31bdae5SDaniel P. Berrange {
582a31bdae5SDaniel P. Berrange     const char *propname;
583a31bdae5SDaniel P. Berrange     Error *local_err = NULL;
584a31bdae5SDaniel P. Berrange 
585a31bdae5SDaniel P. Berrange     propname = va_arg(vargs, char *);
586a31bdae5SDaniel P. Berrange     while (propname != NULL) {
587a31bdae5SDaniel P. Berrange         const char *value = va_arg(vargs, char *);
588a31bdae5SDaniel P. Berrange 
589a31bdae5SDaniel P. Berrange         g_assert(value != NULL);
590a31bdae5SDaniel P. Berrange         object_property_parse(obj, value, propname, &local_err);
591a31bdae5SDaniel P. Berrange         if (local_err) {
592a31bdae5SDaniel P. Berrange             error_propagate(errp, local_err);
593a31bdae5SDaniel P. Berrange             return -1;
594a31bdae5SDaniel P. Berrange         }
595a31bdae5SDaniel P. Berrange         propname = va_arg(vargs, char *);
596a31bdae5SDaniel P. Berrange     }
597a31bdae5SDaniel P. Berrange 
598a31bdae5SDaniel P. Berrange     return 0;
599a31bdae5SDaniel P. Berrange }
600a31bdae5SDaniel P. Berrange 
601a31bdae5SDaniel P. Berrange 
6022f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename)
6032f28d2ffSAnthony Liguori {
604b7f43fe4SPaolo Bonzini     if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) {
605acc4af3fSPaolo Bonzini         return obj;
606acc4af3fSPaolo Bonzini     }
607acc4af3fSPaolo Bonzini 
6082f28d2ffSAnthony Liguori     return NULL;
6092f28d2ffSAnthony Liguori }
6102f28d2ffSAnthony Liguori 
611be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename,
612be17f18bSPaolo Bonzini                                    const char *file, int line, const char *func)
6132f28d2ffSAnthony Liguori {
614fa131d94SPaolo Bonzini     trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)",
615fa131d94SPaolo Bonzini                                      typename, file, line, func);
616fa131d94SPaolo Bonzini 
6173556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG
61803587328SAnthony Liguori     int i;
61903587328SAnthony Liguori     Object *inst;
62003587328SAnthony Liguori 
62195916abcSPeter Crosthwaite     for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) {
622b6b3ccfdSAlex Bennée         if (atomic_read(&obj->class->object_cast_cache[i]) == typename) {
62303587328SAnthony Liguori             goto out;
62403587328SAnthony Liguori         }
62503587328SAnthony Liguori     }
62603587328SAnthony Liguori 
62703587328SAnthony Liguori     inst = object_dynamic_cast(obj, typename);
6282f28d2ffSAnthony Liguori 
629b7f43fe4SPaolo Bonzini     if (!inst && obj) {
630be17f18bSPaolo Bonzini         fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
631be17f18bSPaolo Bonzini                 file, line, func, obj, typename);
6322f28d2ffSAnthony Liguori         abort();
6332f28d2ffSAnthony Liguori     }
6342f28d2ffSAnthony Liguori 
6353556c233SPaolo Bonzini     assert(obj == inst);
63603587328SAnthony Liguori 
63795916abcSPeter Crosthwaite     if (obj && obj == inst) {
63803587328SAnthony Liguori         for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
639b6b3ccfdSAlex Bennée             atomic_set(&obj->class->object_cast_cache[i - 1],
640b6b3ccfdSAlex Bennée                        atomic_read(&obj->class->object_cast_cache[i]));
64103587328SAnthony Liguori         }
642b6b3ccfdSAlex Bennée         atomic_set(&obj->class->object_cast_cache[i - 1], typename);
64303587328SAnthony Liguori     }
64403587328SAnthony Liguori 
64503587328SAnthony Liguori out:
6463556c233SPaolo Bonzini #endif
6473556c233SPaolo Bonzini     return obj;
6482f28d2ffSAnthony Liguori }
6492f28d2ffSAnthony Liguori 
6502f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class,
6512f28d2ffSAnthony Liguori                                        const char *typename)
6522f28d2ffSAnthony Liguori {
65333e95c63SAnthony Liguori     ObjectClass *ret = NULL;
654bf0fda34SPaolo Bonzini     TypeImpl *target_type;
655bf0fda34SPaolo Bonzini     TypeImpl *type;
6562f28d2ffSAnthony Liguori 
657bf0fda34SPaolo Bonzini     if (!class) {
658bf0fda34SPaolo Bonzini         return NULL;
659bf0fda34SPaolo Bonzini     }
660bf0fda34SPaolo Bonzini 
661793c96b5SPaolo Bonzini     /* A simple fast path that can trigger a lot for leaf classes.  */
662bf0fda34SPaolo Bonzini     type = class->type;
663793c96b5SPaolo Bonzini     if (type->name == typename) {
664793c96b5SPaolo Bonzini         return class;
665793c96b5SPaolo Bonzini     }
666793c96b5SPaolo Bonzini 
667bf0fda34SPaolo Bonzini     target_type = type_get_by_name(typename);
6689ab880b3SAlexander Graf     if (!target_type) {
6699ab880b3SAlexander Graf         /* target class type unknown, so fail the cast */
6709ab880b3SAlexander Graf         return NULL;
6719ab880b3SAlexander Graf     }
6729ab880b3SAlexander Graf 
67300e2ceaeSPeter Crosthwaite     if (type->class->interfaces &&
67400e2ceaeSPeter Crosthwaite             type_is_ancestor(target_type, type_interface)) {
67533e95c63SAnthony Liguori         int found = 0;
67633e95c63SAnthony Liguori         GSList *i;
67733e95c63SAnthony Liguori 
67833e95c63SAnthony Liguori         for (i = class->interfaces; i; i = i->next) {
67933e95c63SAnthony Liguori             ObjectClass *target_class = i->data;
68033e95c63SAnthony Liguori 
68133e95c63SAnthony Liguori             if (type_is_ancestor(target_class->type, target_type)) {
68233e95c63SAnthony Liguori                 ret = target_class;
68333e95c63SAnthony Liguori                 found++;
68433e95c63SAnthony Liguori             }
6852f28d2ffSAnthony Liguori          }
6862f28d2ffSAnthony Liguori 
68733e95c63SAnthony Liguori         /* The match was ambiguous, don't allow a cast */
68833e95c63SAnthony Liguori         if (found > 1) {
68933e95c63SAnthony Liguori             ret = NULL;
69033e95c63SAnthony Liguori         }
69133e95c63SAnthony Liguori     } else if (type_is_ancestor(type, target_type)) {
69233e95c63SAnthony Liguori         ret = class;
6932f28d2ffSAnthony Liguori     }
6942f28d2ffSAnthony Liguori 
69533e95c63SAnthony Liguori     return ret;
6962f28d2ffSAnthony Liguori }
6972f28d2ffSAnthony Liguori 
6982f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
699be17f18bSPaolo Bonzini                                               const char *typename,
700be17f18bSPaolo Bonzini                                               const char *file, int line,
701be17f18bSPaolo Bonzini                                               const char *func)
7022f28d2ffSAnthony Liguori {
703fa131d94SPaolo Bonzini     ObjectClass *ret;
7042f28d2ffSAnthony Liguori 
705fa131d94SPaolo Bonzini     trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)",
706fa131d94SPaolo Bonzini                                            typename, file, line, func);
707fa131d94SPaolo Bonzini 
70803587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG
70903587328SAnthony Liguori     int i;
71003587328SAnthony Liguori 
7119d6a3d58SPeter Crosthwaite     for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) {
712b6b3ccfdSAlex Bennée         if (atomic_read(&class->class_cast_cache[i]) == typename) {
71303587328SAnthony Liguori             ret = class;
71403587328SAnthony Liguori             goto out;
71503587328SAnthony Liguori         }
71603587328SAnthony Liguori     }
71703587328SAnthony Liguori #else
7189d6a3d58SPeter Crosthwaite     if (!class || !class->interfaces) {
7193556c233SPaolo Bonzini         return class;
7203556c233SPaolo Bonzini     }
7213556c233SPaolo Bonzini #endif
7223556c233SPaolo Bonzini 
723fa131d94SPaolo Bonzini     ret = object_class_dynamic_cast(class, typename);
724bf0fda34SPaolo Bonzini     if (!ret && class) {
725be17f18bSPaolo Bonzini         fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
726be17f18bSPaolo Bonzini                 file, line, func, class, typename);
7272f28d2ffSAnthony Liguori         abort();
7282f28d2ffSAnthony Liguori     }
7292f28d2ffSAnthony Liguori 
73003587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG
7319d6a3d58SPeter Crosthwaite     if (class && ret == class) {
73203587328SAnthony Liguori         for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
733b6b3ccfdSAlex Bennée             atomic_set(&class->class_cast_cache[i - 1],
734b6b3ccfdSAlex Bennée                        atomic_read(&class->class_cast_cache[i]));
73503587328SAnthony Liguori         }
736b6b3ccfdSAlex Bennée         atomic_set(&class->class_cast_cache[i - 1], typename);
73703587328SAnthony Liguori     }
73803587328SAnthony Liguori out:
73903587328SAnthony Liguori #endif
7402f28d2ffSAnthony Liguori     return ret;
7412f28d2ffSAnthony Liguori }
7422f28d2ffSAnthony Liguori 
7438f5d58efSIgor Mammedov const char *object_get_typename(const Object *obj)
7442f28d2ffSAnthony Liguori {
7452f28d2ffSAnthony Liguori     return obj->class->type->name;
7462f28d2ffSAnthony Liguori }
7472f28d2ffSAnthony Liguori 
7482f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj)
7492f28d2ffSAnthony Liguori {
7502f28d2ffSAnthony Liguori     return obj->class;
7512f28d2ffSAnthony Liguori }
7522f28d2ffSAnthony Liguori 
75317862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass)
75417862378SAndreas Färber {
75517862378SAndreas Färber     return klass->type->abstract;
75617862378SAndreas Färber }
75717862378SAndreas Färber 
7582f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass)
7592f28d2ffSAnthony Liguori {
7602f28d2ffSAnthony Liguori     return klass->type->name;
7612f28d2ffSAnthony Liguori }
7622f28d2ffSAnthony Liguori 
7632f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename)
7642f28d2ffSAnthony Liguori {
7652f28d2ffSAnthony Liguori     TypeImpl *type = type_get_by_name(typename);
7662f28d2ffSAnthony Liguori 
7672f28d2ffSAnthony Liguori     if (!type) {
7682f28d2ffSAnthony Liguori         return NULL;
7692f28d2ffSAnthony Liguori     }
7702f28d2ffSAnthony Liguori 
771ac451033SIgor Mitsyanko     type_initialize(type);
7722f28d2ffSAnthony Liguori 
7732f28d2ffSAnthony Liguori     return type->class;
7742f28d2ffSAnthony Liguori }
7752f28d2ffSAnthony Liguori 
776e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class)
777e7cce67fSPaolo Bonzini {
778e7cce67fSPaolo Bonzini     TypeImpl *type = type_get_parent(class->type);
779e7cce67fSPaolo Bonzini 
780e7cce67fSPaolo Bonzini     if (!type) {
781e7cce67fSPaolo Bonzini         return NULL;
782e7cce67fSPaolo Bonzini     }
783e7cce67fSPaolo Bonzini 
784e7cce67fSPaolo Bonzini     type_initialize(type);
785e7cce67fSPaolo Bonzini 
786e7cce67fSPaolo Bonzini     return type->class;
787e7cce67fSPaolo Bonzini }
788e7cce67fSPaolo Bonzini 
7892f28d2ffSAnthony Liguori typedef struct OCFData
7902f28d2ffSAnthony Liguori {
7912f28d2ffSAnthony Liguori     void (*fn)(ObjectClass *klass, void *opaque);
79293c511a1SAnthony Liguori     const char *implements_type;
79393c511a1SAnthony Liguori     bool include_abstract;
7942f28d2ffSAnthony Liguori     void *opaque;
7952f28d2ffSAnthony Liguori } OCFData;
7962f28d2ffSAnthony Liguori 
7972f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value,
7982f28d2ffSAnthony Liguori                                        gpointer opaque)
7992f28d2ffSAnthony Liguori {
8002f28d2ffSAnthony Liguori     OCFData *data = opaque;
8012f28d2ffSAnthony Liguori     TypeImpl *type = value;
80293c511a1SAnthony Liguori     ObjectClass *k;
8032f28d2ffSAnthony Liguori 
804ac451033SIgor Mitsyanko     type_initialize(type);
80593c511a1SAnthony Liguori     k = type->class;
8062f28d2ffSAnthony Liguori 
80793c511a1SAnthony Liguori     if (!data->include_abstract && type->abstract) {
80893c511a1SAnthony Liguori         return;
80993c511a1SAnthony Liguori     }
81093c511a1SAnthony Liguori 
81193c511a1SAnthony Liguori     if (data->implements_type &&
81293c511a1SAnthony Liguori         !object_class_dynamic_cast(k, data->implements_type)) {
81393c511a1SAnthony Liguori         return;
81493c511a1SAnthony Liguori     }
81593c511a1SAnthony Liguori 
81693c511a1SAnthony Liguori     data->fn(k, data->opaque);
8172f28d2ffSAnthony Liguori }
8182f28d2ffSAnthony Liguori 
8192f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
82093c511a1SAnthony Liguori                           const char *implements_type, bool include_abstract,
8212f28d2ffSAnthony Liguori                           void *opaque)
8222f28d2ffSAnthony Liguori {
82393c511a1SAnthony Liguori     OCFData data = { fn, implements_type, include_abstract, opaque };
8242f28d2ffSAnthony Liguori 
825f54c19caSHervé Poussineau     enumerating_types = true;
8262f28d2ffSAnthony Liguori     g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
827f54c19caSHervé Poussineau     enumerating_types = false;
8282f28d2ffSAnthony Liguori }
82957c9fafeSAnthony Liguori 
830d714b8deSPeter Crosthwaite static int do_object_child_foreach(Object *obj,
831d714b8deSPeter Crosthwaite                                    int (*fn)(Object *child, void *opaque),
832d714b8deSPeter Crosthwaite                                    void *opaque, bool recurse)
83332efc535SPaolo Bonzini {
834b604a854SPavel Fedin     GHashTableIter iter;
835b604a854SPavel Fedin     ObjectProperty *prop;
83632efc535SPaolo Bonzini     int ret = 0;
83732efc535SPaolo Bonzini 
838b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->properties);
839b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) {
84032efc535SPaolo Bonzini         if (object_property_is_child(prop)) {
841d714b8deSPeter Crosthwaite             Object *child = prop->opaque;
842d714b8deSPeter Crosthwaite 
843d714b8deSPeter Crosthwaite             ret = fn(child, opaque);
84432efc535SPaolo Bonzini             if (ret != 0) {
84532efc535SPaolo Bonzini                 break;
84632efc535SPaolo Bonzini             }
847d714b8deSPeter Crosthwaite             if (recurse) {
848d714b8deSPeter Crosthwaite                 do_object_child_foreach(child, fn, opaque, true);
849d714b8deSPeter Crosthwaite             }
85032efc535SPaolo Bonzini         }
85132efc535SPaolo Bonzini     }
85232efc535SPaolo Bonzini     return ret;
85332efc535SPaolo Bonzini }
85432efc535SPaolo Bonzini 
855d714b8deSPeter Crosthwaite int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque),
856d714b8deSPeter Crosthwaite                          void *opaque)
857d714b8deSPeter Crosthwaite {
858d714b8deSPeter Crosthwaite     return do_object_child_foreach(obj, fn, opaque, false);
859d714b8deSPeter Crosthwaite }
860d714b8deSPeter Crosthwaite 
861d714b8deSPeter Crosthwaite int object_child_foreach_recursive(Object *obj,
862d714b8deSPeter Crosthwaite                                    int (*fn)(Object *child, void *opaque),
863d714b8deSPeter Crosthwaite                                    void *opaque)
864d714b8deSPeter Crosthwaite {
865d714b8deSPeter Crosthwaite     return do_object_child_foreach(obj, fn, opaque, true);
866d714b8deSPeter Crosthwaite }
867d714b8deSPeter Crosthwaite 
868418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque)
869418ba9e5SAndreas Färber {
870418ba9e5SAndreas Färber     GSList **list = opaque;
871418ba9e5SAndreas Färber 
872418ba9e5SAndreas Färber     *list = g_slist_prepend(*list, klass);
873418ba9e5SAndreas Färber }
874418ba9e5SAndreas Färber 
875418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type,
876418ba9e5SAndreas Färber                               bool include_abstract)
877418ba9e5SAndreas Färber {
878418ba9e5SAndreas Färber     GSList *list = NULL;
879418ba9e5SAndreas Färber 
880418ba9e5SAndreas Färber     object_class_foreach(object_class_get_list_tramp,
881418ba9e5SAndreas Färber                          implements_type, include_abstract, &list);
882418ba9e5SAndreas Färber     return list;
883418ba9e5SAndreas Färber }
884418ba9e5SAndreas Färber 
88557c9fafeSAnthony Liguori void object_ref(Object *obj)
88657c9fafeSAnthony Liguori {
8878ffad850SPeter Crosthwaite     if (!obj) {
8888ffad850SPeter Crosthwaite         return;
8898ffad850SPeter Crosthwaite     }
890f08c03f3SJan Kiszka     atomic_inc(&obj->ref);
89157c9fafeSAnthony Liguori }
89257c9fafeSAnthony Liguori 
89357c9fafeSAnthony Liguori void object_unref(Object *obj)
89457c9fafeSAnthony Liguori {
8958ffad850SPeter Crosthwaite     if (!obj) {
8968ffad850SPeter Crosthwaite         return;
8978ffad850SPeter Crosthwaite     }
8988438a135SAndreas Färber     g_assert_cmpint(obj->ref, >, 0);
89957c9fafeSAnthony Liguori 
90057c9fafeSAnthony Liguori     /* parent always holds a reference to its children */
901f08c03f3SJan Kiszka     if (atomic_fetch_dec(&obj->ref) == 1) {
90257c9fafeSAnthony Liguori         object_finalize(obj);
90357c9fafeSAnthony Liguori     }
90457c9fafeSAnthony Liguori }
90557c9fafeSAnthony Liguori 
90664607d08SPaolo Bonzini ObjectProperty *
90764607d08SPaolo Bonzini object_property_add(Object *obj, const char *name, const char *type,
90857c9fafeSAnthony Liguori                     ObjectPropertyAccessor *get,
90957c9fafeSAnthony Liguori                     ObjectPropertyAccessor *set,
91057c9fafeSAnthony Liguori                     ObjectPropertyRelease *release,
91157c9fafeSAnthony Liguori                     void *opaque, Error **errp)
91257c9fafeSAnthony Liguori {
91354852b03SPeter Maydell     ObjectProperty *prop;
91433965904SPeter Crosthwaite     size_t name_len = strlen(name);
91533965904SPeter Crosthwaite 
91633965904SPeter Crosthwaite     if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) {
91733965904SPeter Crosthwaite         int i;
91833965904SPeter Crosthwaite         ObjectProperty *ret;
91933965904SPeter Crosthwaite         char *name_no_array = g_strdup(name);
92033965904SPeter Crosthwaite 
92133965904SPeter Crosthwaite         name_no_array[name_len - 3] = '\0';
92233965904SPeter Crosthwaite         for (i = 0; ; ++i) {
92333965904SPeter Crosthwaite             char *full_name = g_strdup_printf("%s[%d]", name_no_array, i);
92433965904SPeter Crosthwaite 
92533965904SPeter Crosthwaite             ret = object_property_add(obj, full_name, type, get, set,
92633965904SPeter Crosthwaite                                       release, opaque, NULL);
92733965904SPeter Crosthwaite             g_free(full_name);
92833965904SPeter Crosthwaite             if (ret) {
92933965904SPeter Crosthwaite                 break;
93033965904SPeter Crosthwaite             }
93133965904SPeter Crosthwaite         }
93233965904SPeter Crosthwaite         g_free(name_no_array);
93333965904SPeter Crosthwaite         return ret;
93433965904SPeter Crosthwaite     }
93554852b03SPeter Maydell 
93616bf7f52SDaniel P. Berrange     if (object_property_find(obj, name, NULL) != NULL) {
93754852b03SPeter Maydell         error_setg(errp, "attempt to add duplicate property '%s'"
93854852b03SPeter Maydell                    " to object (type '%s')", name,
93954852b03SPeter Maydell                    object_get_typename(obj));
94064607d08SPaolo Bonzini         return NULL;
94154852b03SPeter Maydell     }
94254852b03SPeter Maydell 
94354852b03SPeter Maydell     prop = g_malloc0(sizeof(*prop));
94457c9fafeSAnthony Liguori 
94557c9fafeSAnthony Liguori     prop->name = g_strdup(name);
94657c9fafeSAnthony Liguori     prop->type = g_strdup(type);
94757c9fafeSAnthony Liguori 
94857c9fafeSAnthony Liguori     prop->get = get;
94957c9fafeSAnthony Liguori     prop->set = set;
95057c9fafeSAnthony Liguori     prop->release = release;
95157c9fafeSAnthony Liguori     prop->opaque = opaque;
95257c9fafeSAnthony Liguori 
953b604a854SPavel Fedin     g_hash_table_insert(obj->properties, prop->name, prop);
95464607d08SPaolo Bonzini     return prop;
95557c9fafeSAnthony Liguori }
95657c9fafeSAnthony Liguori 
95716bf7f52SDaniel P. Berrange ObjectProperty *
95816bf7f52SDaniel P. Berrange object_class_property_add(ObjectClass *klass,
95916bf7f52SDaniel P. Berrange                           const char *name,
96016bf7f52SDaniel P. Berrange                           const char *type,
96116bf7f52SDaniel P. Berrange                           ObjectPropertyAccessor *get,
96216bf7f52SDaniel P. Berrange                           ObjectPropertyAccessor *set,
96316bf7f52SDaniel P. Berrange                           ObjectPropertyRelease *release,
96416bf7f52SDaniel P. Berrange                           void *opaque,
96516bf7f52SDaniel P. Berrange                           Error **errp)
96616bf7f52SDaniel P. Berrange {
96716bf7f52SDaniel P. Berrange     ObjectProperty *prop;
96816bf7f52SDaniel P. Berrange 
96916bf7f52SDaniel P. Berrange     if (object_class_property_find(klass, name, NULL) != NULL) {
97016bf7f52SDaniel P. Berrange         error_setg(errp, "attempt to add duplicate property '%s'"
97116bf7f52SDaniel P. Berrange                    " to object (type '%s')", name,
97216bf7f52SDaniel P. Berrange                    object_class_get_name(klass));
97316bf7f52SDaniel P. Berrange         return NULL;
97416bf7f52SDaniel P. Berrange     }
97516bf7f52SDaniel P. Berrange 
97616bf7f52SDaniel P. Berrange     prop = g_malloc0(sizeof(*prop));
97716bf7f52SDaniel P. Berrange 
97816bf7f52SDaniel P. Berrange     prop->name = g_strdup(name);
97916bf7f52SDaniel P. Berrange     prop->type = g_strdup(type);
98016bf7f52SDaniel P. Berrange 
98116bf7f52SDaniel P. Berrange     prop->get = get;
98216bf7f52SDaniel P. Berrange     prop->set = set;
98316bf7f52SDaniel P. Berrange     prop->release = release;
98416bf7f52SDaniel P. Berrange     prop->opaque = opaque;
98516bf7f52SDaniel P. Berrange 
98616bf7f52SDaniel P. Berrange     g_hash_table_insert(klass->properties, g_strdup(name), prop);
98716bf7f52SDaniel P. Berrange 
98816bf7f52SDaniel P. Berrange     return prop;
98916bf7f52SDaniel P. Berrange }
99016bf7f52SDaniel P. Berrange 
99189bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name,
99289bfe000SPaolo Bonzini                                      Error **errp)
99357c9fafeSAnthony Liguori {
99457c9fafeSAnthony Liguori     ObjectProperty *prop;
99516bf7f52SDaniel P. Berrange     ObjectClass *klass = object_get_class(obj);
99616bf7f52SDaniel P. Berrange 
99716bf7f52SDaniel P. Berrange     prop = object_class_property_find(klass, name, NULL);
99816bf7f52SDaniel P. Berrange     if (prop) {
99916bf7f52SDaniel P. Berrange         return prop;
100016bf7f52SDaniel P. Berrange     }
100157c9fafeSAnthony Liguori 
1002b604a854SPavel Fedin     prop = g_hash_table_lookup(obj->properties, name);
1003b604a854SPavel Fedin     if (prop) {
100457c9fafeSAnthony Liguori         return prop;
100557c9fafeSAnthony Liguori     }
100657c9fafeSAnthony Liguori 
1007f231b88dSCole Robinson     error_setg(errp, "Property '.%s' not found", name);
100857c9fafeSAnthony Liguori     return NULL;
100957c9fafeSAnthony Liguori }
101057c9fafeSAnthony Liguori 
10117746abd8SDaniel P. Berrange void object_property_iter_init(ObjectPropertyIterator *iter,
10127746abd8SDaniel P. Berrange                                Object *obj)
1013a00c9482SDaniel P. Berrange {
10147746abd8SDaniel P. Berrange     g_hash_table_iter_init(&iter->iter, obj->properties);
10157746abd8SDaniel P. Berrange     iter->nextclass = object_get_class(obj);
1016a00c9482SDaniel P. Berrange }
1017a00c9482SDaniel P. Berrange 
1018a00c9482SDaniel P. Berrange ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter)
1019a00c9482SDaniel P. Berrange {
1020b604a854SPavel Fedin     gpointer key, val;
102116bf7f52SDaniel P. Berrange     while (!g_hash_table_iter_next(&iter->iter, &key, &val)) {
102216bf7f52SDaniel P. Berrange         if (!iter->nextclass) {
1023b604a854SPavel Fedin             return NULL;
1024a00c9482SDaniel P. Berrange         }
102516bf7f52SDaniel P. Berrange         g_hash_table_iter_init(&iter->iter, iter->nextclass->properties);
102616bf7f52SDaniel P. Berrange         iter->nextclass = object_class_get_parent(iter->nextclass);
102716bf7f52SDaniel P. Berrange     }
1028b604a854SPavel Fedin     return val;
1029a00c9482SDaniel P. Berrange }
1030a00c9482SDaniel P. Berrange 
103116bf7f52SDaniel P. Berrange ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
103216bf7f52SDaniel P. Berrange                                            Error **errp)
103316bf7f52SDaniel P. Berrange {
103416bf7f52SDaniel P. Berrange     ObjectProperty *prop;
103516bf7f52SDaniel P. Berrange     ObjectClass *parent_klass;
103616bf7f52SDaniel P. Berrange 
103716bf7f52SDaniel P. Berrange     parent_klass = object_class_get_parent(klass);
103816bf7f52SDaniel P. Berrange     if (parent_klass) {
103916bf7f52SDaniel P. Berrange         prop = object_class_property_find(parent_klass, name, NULL);
104016bf7f52SDaniel P. Berrange         if (prop) {
104116bf7f52SDaniel P. Berrange             return prop;
104216bf7f52SDaniel P. Berrange         }
104316bf7f52SDaniel P. Berrange     }
104416bf7f52SDaniel P. Berrange 
104516bf7f52SDaniel P. Berrange     prop = g_hash_table_lookup(klass->properties, name);
104616bf7f52SDaniel P. Berrange     if (!prop) {
104716bf7f52SDaniel P. Berrange         error_setg(errp, "Property '.%s' not found", name);
104816bf7f52SDaniel P. Berrange     }
104916bf7f52SDaniel P. Berrange     return prop;
105016bf7f52SDaniel P. Berrange }
105116bf7f52SDaniel P. Berrange 
105257c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp)
105357c9fafeSAnthony Liguori {
1054b604a854SPavel Fedin     ObjectProperty *prop = g_hash_table_lookup(obj->properties, name);
1055b604a854SPavel Fedin 
1056b604a854SPavel Fedin     if (!prop) {
1057b604a854SPavel Fedin         error_setg(errp, "Property '.%s' not found", name);
10580866aca1SAnthony Liguori         return;
10590866aca1SAnthony Liguori     }
106057c9fafeSAnthony Liguori 
10610866aca1SAnthony Liguori     if (prop->release) {
10620866aca1SAnthony Liguori         prop->release(obj, name, prop->opaque);
10630866aca1SAnthony Liguori     }
1064b604a854SPavel Fedin     g_hash_table_remove(obj->properties, name);
106557c9fafeSAnthony Liguori }
106657c9fafeSAnthony Liguori 
106757c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name,
106857c9fafeSAnthony Liguori                          Error **errp)
106957c9fafeSAnthony Liguori {
107089bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(obj, name, errp);
107157c9fafeSAnthony Liguori     if (prop == NULL) {
107257c9fafeSAnthony Liguori         return;
107357c9fafeSAnthony Liguori     }
107457c9fafeSAnthony Liguori 
107557c9fafeSAnthony Liguori     if (!prop->get) {
1076c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_PERMISSION_DENIED);
107757c9fafeSAnthony Liguori     } else {
1078d7bce999SEric Blake         prop->get(obj, v, name, prop->opaque, errp);
107957c9fafeSAnthony Liguori     }
108057c9fafeSAnthony Liguori }
108157c9fafeSAnthony Liguori 
108257c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name,
108357c9fafeSAnthony Liguori                          Error **errp)
108457c9fafeSAnthony Liguori {
108589bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(obj, name, errp);
108657c9fafeSAnthony Liguori     if (prop == NULL) {
108757c9fafeSAnthony Liguori         return;
108857c9fafeSAnthony Liguori     }
108957c9fafeSAnthony Liguori 
109057c9fafeSAnthony Liguori     if (!prop->set) {
1091c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_PERMISSION_DENIED);
109257c9fafeSAnthony Liguori     } else {
1093d7bce999SEric Blake         prop->set(obj, v, name, prop->opaque, errp);
109457c9fafeSAnthony Liguori     }
109557c9fafeSAnthony Liguori }
109657c9fafeSAnthony Liguori 
10977b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value,
10987b7b7d18SPaolo Bonzini                              const char *name, Error **errp)
10997b7b7d18SPaolo Bonzini {
11007b7b7d18SPaolo Bonzini     QString *qstr = qstring_from_str(value);
11017b7b7d18SPaolo Bonzini     object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
11027b7b7d18SPaolo Bonzini 
11037b7b7d18SPaolo Bonzini     QDECREF(qstr);
11047b7b7d18SPaolo Bonzini }
11057b7b7d18SPaolo Bonzini 
11067b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name,
11077b7b7d18SPaolo Bonzini                               Error **errp)
11087b7b7d18SPaolo Bonzini {
11097b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
11107b7b7d18SPaolo Bonzini     QString *qstring;
11117b7b7d18SPaolo Bonzini     char *retval;
11127b7b7d18SPaolo Bonzini 
11137b7b7d18SPaolo Bonzini     if (!ret) {
11147b7b7d18SPaolo Bonzini         return NULL;
11157b7b7d18SPaolo Bonzini     }
11167b7b7d18SPaolo Bonzini     qstring = qobject_to_qstring(ret);
11177b7b7d18SPaolo Bonzini     if (!qstring) {
1118c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
11197b7b7d18SPaolo Bonzini         retval = NULL;
11207b7b7d18SPaolo Bonzini     } else {
11217b7b7d18SPaolo Bonzini         retval = g_strdup(qstring_get_str(qstring));
11227b7b7d18SPaolo Bonzini     }
11237b7b7d18SPaolo Bonzini 
1124560f19f1SMarc-André Lureau     qobject_decref(ret);
11257b7b7d18SPaolo Bonzini     return retval;
11267b7b7d18SPaolo Bonzini }
11277b7b7d18SPaolo Bonzini 
11281d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value,
11291d9c5a12SPaolo Bonzini                               const char *name, Error **errp)
11301d9c5a12SPaolo Bonzini {
1131d3c49316SPeter Crosthwaite     if (value) {
11322d3aa28cSVlad Yasevich         gchar *path = object_get_canonical_path(value);
11332d3aa28cSVlad Yasevich         object_property_set_str(obj, path, name, errp);
11342d3aa28cSVlad Yasevich         g_free(path);
1135d3c49316SPeter Crosthwaite     } else {
1136d3c49316SPeter Crosthwaite         object_property_set_str(obj, "", name, errp);
1137d3c49316SPeter Crosthwaite     }
11381d9c5a12SPaolo Bonzini }
11391d9c5a12SPaolo Bonzini 
11401d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name,
11411d9c5a12SPaolo Bonzini                                  Error **errp)
11421d9c5a12SPaolo Bonzini {
11431d9c5a12SPaolo Bonzini     char *str = object_property_get_str(obj, name, errp);
11441d9c5a12SPaolo Bonzini     Object *target = NULL;
11451d9c5a12SPaolo Bonzini 
11461d9c5a12SPaolo Bonzini     if (str && *str) {
11471d9c5a12SPaolo Bonzini         target = object_resolve_path(str, NULL);
11481d9c5a12SPaolo Bonzini         if (!target) {
114975158ebbSMarkus Armbruster             error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
115075158ebbSMarkus Armbruster                       "Device '%s' not found", str);
11511d9c5a12SPaolo Bonzini         }
11521d9c5a12SPaolo Bonzini     }
11531d9c5a12SPaolo Bonzini 
11541d9c5a12SPaolo Bonzini     g_free(str);
11551d9c5a12SPaolo Bonzini     return target;
11561d9c5a12SPaolo Bonzini }
11571d9c5a12SPaolo Bonzini 
11587b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value,
11597b7b7d18SPaolo Bonzini                               const char *name, Error **errp)
11607b7b7d18SPaolo Bonzini {
1161fc48ffc3SEric Blake     QBool *qbool = qbool_from_bool(value);
11627b7b7d18SPaolo Bonzini     object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
11637b7b7d18SPaolo Bonzini 
11647b7b7d18SPaolo Bonzini     QDECREF(qbool);
11657b7b7d18SPaolo Bonzini }
11667b7b7d18SPaolo Bonzini 
11677b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name,
11687b7b7d18SPaolo Bonzini                               Error **errp)
11697b7b7d18SPaolo Bonzini {
11707b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
11717b7b7d18SPaolo Bonzini     QBool *qbool;
11727b7b7d18SPaolo Bonzini     bool retval;
11737b7b7d18SPaolo Bonzini 
11747b7b7d18SPaolo Bonzini     if (!ret) {
11757b7b7d18SPaolo Bonzini         return false;
11767b7b7d18SPaolo Bonzini     }
11777b7b7d18SPaolo Bonzini     qbool = qobject_to_qbool(ret);
11787b7b7d18SPaolo Bonzini     if (!qbool) {
1179c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
11807b7b7d18SPaolo Bonzini         retval = false;
11817b7b7d18SPaolo Bonzini     } else {
1182fc48ffc3SEric Blake         retval = qbool_get_bool(qbool);
11837b7b7d18SPaolo Bonzini     }
11847b7b7d18SPaolo Bonzini 
1185560f19f1SMarc-André Lureau     qobject_decref(ret);
11867b7b7d18SPaolo Bonzini     return retval;
11877b7b7d18SPaolo Bonzini }
11887b7b7d18SPaolo Bonzini 
11897b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value,
11907b7b7d18SPaolo Bonzini                              const char *name, Error **errp)
11917b7b7d18SPaolo Bonzini {
119201b2ffceSMarc-André Lureau     QNum *qnum = qnum_from_int(value);
119301b2ffceSMarc-André Lureau     object_property_set_qobject(obj, QOBJECT(qnum), name, errp);
11947b7b7d18SPaolo Bonzini 
119501b2ffceSMarc-André Lureau     QDECREF(qnum);
11967b7b7d18SPaolo Bonzini }
11977b7b7d18SPaolo Bonzini 
11987b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name,
11997b7b7d18SPaolo Bonzini                                 Error **errp)
12007b7b7d18SPaolo Bonzini {
12017b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
120201b2ffceSMarc-André Lureau     QNum *qnum;
12037b7b7d18SPaolo Bonzini     int64_t retval;
12047b7b7d18SPaolo Bonzini 
12057b7b7d18SPaolo Bonzini     if (!ret) {
12067b7b7d18SPaolo Bonzini         return -1;
12077b7b7d18SPaolo Bonzini     }
120801b2ffceSMarc-André Lureau 
120901b2ffceSMarc-André Lureau     qnum = qobject_to_qnum(ret);
121001b2ffceSMarc-André Lureau     if (!qnum || !qnum_get_try_int(qnum, &retval)) {
1211c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
12127b7b7d18SPaolo Bonzini         retval = -1;
12137b7b7d18SPaolo Bonzini     }
12147b7b7d18SPaolo Bonzini 
1215560f19f1SMarc-André Lureau     qobject_decref(ret);
12167b7b7d18SPaolo Bonzini     return retval;
12177b7b7d18SPaolo Bonzini }
12187b7b7d18SPaolo Bonzini 
12193152779cSMarc-André Lureau void object_property_set_uint(Object *obj, uint64_t value,
12203152779cSMarc-André Lureau                               const char *name, Error **errp)
12213152779cSMarc-André Lureau {
12223152779cSMarc-André Lureau     QNum *qnum = qnum_from_uint(value);
12233152779cSMarc-André Lureau 
12243152779cSMarc-André Lureau     object_property_set_qobject(obj, QOBJECT(qnum), name, errp);
12253152779cSMarc-André Lureau     QDECREF(qnum);
12263152779cSMarc-André Lureau }
12273152779cSMarc-André Lureau 
12283152779cSMarc-André Lureau uint64_t object_property_get_uint(Object *obj, const char *name,
12293152779cSMarc-André Lureau                                   Error **errp)
12303152779cSMarc-André Lureau {
12313152779cSMarc-André Lureau     QObject *ret = object_property_get_qobject(obj, name, errp);
12323152779cSMarc-André Lureau     QNum *qnum;
12333152779cSMarc-André Lureau     uint64_t retval;
12343152779cSMarc-André Lureau 
12353152779cSMarc-André Lureau     if (!ret) {
12363152779cSMarc-André Lureau         return 0;
12373152779cSMarc-André Lureau     }
12383152779cSMarc-André Lureau     qnum = qobject_to_qnum(ret);
12393152779cSMarc-André Lureau     if (!qnum || !qnum_get_try_uint(qnum, &retval)) {
12403152779cSMarc-André Lureau         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "uint");
12413152779cSMarc-André Lureau         retval = 0;
12423152779cSMarc-André Lureau     }
12433152779cSMarc-André Lureau 
12443152779cSMarc-André Lureau     qobject_decref(ret);
12453152779cSMarc-André Lureau     return retval;
12463152779cSMarc-André Lureau }
12473152779cSMarc-André Lureau 
1248a8e3fbedSDaniel P. Berrange typedef struct EnumProperty {
1249f7abe0ecSMarc-André Lureau     const QEnumLookup *lookup;
1250a8e3fbedSDaniel P. Berrange     int (*get)(Object *, Error **);
1251a8e3fbedSDaniel P. Berrange     void (*set)(Object *, int, Error **);
1252a8e3fbedSDaniel P. Berrange } EnumProperty;
1253a8e3fbedSDaniel P. Berrange 
12541f21772dSHu Tao int object_property_get_enum(Object *obj, const char *name,
1255a3590dacSDaniel P. Berrange                              const char *typename, Error **errp)
12561f21772dSHu Tao {
12574715d42eSMarkus Armbruster     Error *err = NULL;
12587a0525c7SEric Blake     Visitor *v;
1259976620acSChen Fan     char *str;
12601f21772dSHu Tao     int ret;
1261a3590dacSDaniel P. Berrange     ObjectProperty *prop = object_property_find(obj, name, errp);
1262a3590dacSDaniel P. Berrange     EnumProperty *enumprop;
1263a3590dacSDaniel P. Berrange 
1264a3590dacSDaniel P. Berrange     if (prop == NULL) {
1265a3590dacSDaniel P. Berrange         return 0;
1266a3590dacSDaniel P. Berrange     }
1267a3590dacSDaniel P. Berrange 
1268a3590dacSDaniel P. Berrange     if (!g_str_equal(prop->type, typename)) {
1269a3590dacSDaniel P. Berrange         error_setg(errp, "Property %s on %s is not '%s' enum type",
1270a3590dacSDaniel P. Berrange                    name, object_class_get_name(
1271a3590dacSDaniel P. Berrange                        object_get_class(obj)), typename);
1272a3590dacSDaniel P. Berrange         return 0;
1273a3590dacSDaniel P. Berrange     }
1274a3590dacSDaniel P. Berrange 
1275a3590dacSDaniel P. Berrange     enumprop = prop->opaque;
12761f21772dSHu Tao 
12773b098d56SEric Blake     v = string_output_visitor_new(false, &str);
1278e7ca5656SEric Blake     object_property_get(obj, v, name, &err);
12794715d42eSMarkus Armbruster     if (err) {
12804715d42eSMarkus Armbruster         error_propagate(errp, err);
1281e7ca5656SEric Blake         visit_free(v);
12824715d42eSMarkus Armbruster         return 0;
12834715d42eSMarkus Armbruster     }
12843b098d56SEric Blake     visit_complete(v, &str);
1285e7ca5656SEric Blake     visit_free(v);
12867a0525c7SEric Blake     v = string_input_visitor_new(str);
1287f7abe0ecSMarc-André Lureau     visit_type_enum(v, name, &ret, enumprop->lookup, errp);
1288976620acSChen Fan 
1289976620acSChen Fan     g_free(str);
12907a0525c7SEric Blake     visit_free(v);
12911f21772dSHu Tao 
12921f21772dSHu Tao     return ret;
12931f21772dSHu Tao }
12941f21772dSHu Tao 
12951f21772dSHu Tao void object_property_get_uint16List(Object *obj, const char *name,
12961f21772dSHu Tao                                     uint16List **list, Error **errp)
12971f21772dSHu Tao {
12984715d42eSMarkus Armbruster     Error *err = NULL;
12997a0525c7SEric Blake     Visitor *v;
1300976620acSChen Fan     char *str;
13011f21772dSHu Tao 
13023b098d56SEric Blake     v = string_output_visitor_new(false, &str);
13033b098d56SEric Blake     object_property_get(obj, v, name, &err);
13044715d42eSMarkus Armbruster     if (err) {
13054715d42eSMarkus Armbruster         error_propagate(errp, err);
13064715d42eSMarkus Armbruster         goto out;
13074715d42eSMarkus Armbruster     }
13083b098d56SEric Blake     visit_complete(v, &str);
13093b098d56SEric Blake     visit_free(v);
13107a0525c7SEric Blake     v = string_input_visitor_new(str);
13117a0525c7SEric Blake     visit_type_uint16List(v, NULL, list, errp);
1312976620acSChen Fan 
1313976620acSChen Fan     g_free(str);
13144715d42eSMarkus Armbruster out:
13153b098d56SEric Blake     visit_free(v);
13161f21772dSHu Tao }
13171f21772dSHu Tao 
1318b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string,
1319b2cd7deeSPaolo Bonzini                            const char *name, Error **errp)
1320b2cd7deeSPaolo Bonzini {
13217a0525c7SEric Blake     Visitor *v = string_input_visitor_new(string);
13227a0525c7SEric Blake     object_property_set(obj, v, name, errp);
13237a0525c7SEric Blake     visit_free(v);
1324b2cd7deeSPaolo Bonzini }
1325b2cd7deeSPaolo Bonzini 
13260b7593e0SPaolo Bonzini char *object_property_print(Object *obj, const char *name, bool human,
1327b2cd7deeSPaolo Bonzini                             Error **errp)
1328b2cd7deeSPaolo Bonzini {
13293b098d56SEric Blake     Visitor *v;
13303a53009fSGonglei     char *string = NULL;
13313a53009fSGonglei     Error *local_err = NULL;
1332b2cd7deeSPaolo Bonzini 
13333b098d56SEric Blake     v = string_output_visitor_new(human, &string);
13343b098d56SEric Blake     object_property_get(obj, v, name, &local_err);
13353a53009fSGonglei     if (local_err) {
13363a53009fSGonglei         error_propagate(errp, local_err);
13373a53009fSGonglei         goto out;
13383a53009fSGonglei     }
13393a53009fSGonglei 
13403b098d56SEric Blake     visit_complete(v, &string);
13413a53009fSGonglei 
13423a53009fSGonglei out:
13433b098d56SEric Blake     visit_free(v);
1344b2cd7deeSPaolo Bonzini     return string;
1345b2cd7deeSPaolo Bonzini }
1346b2cd7deeSPaolo Bonzini 
134757c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp)
134857c9fafeSAnthony Liguori {
134989bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(obj, name, errp);
135057c9fafeSAnthony Liguori     if (prop == NULL) {
135157c9fafeSAnthony Liguori         return NULL;
135257c9fafeSAnthony Liguori     }
135357c9fafeSAnthony Liguori 
135457c9fafeSAnthony Liguori     return prop->type;
135557c9fafeSAnthony Liguori }
135657c9fafeSAnthony Liguori 
135757c9fafeSAnthony Liguori Object *object_get_root(void)
135857c9fafeSAnthony Liguori {
13598b45d447SAnthony Liguori     static Object *root;
136057c9fafeSAnthony Liguori 
13618b45d447SAnthony Liguori     if (!root) {
13628b45d447SAnthony Liguori         root = object_new("container");
136357c9fafeSAnthony Liguori     }
136457c9fafeSAnthony Liguori 
13658b45d447SAnthony Liguori     return root;
136657c9fafeSAnthony Liguori }
136757c9fafeSAnthony Liguori 
1368bc2256c4SDaniel P. Berrange Object *object_get_objects_root(void)
1369bc2256c4SDaniel P. Berrange {
1370bc2256c4SDaniel P. Berrange     return container_get(object_get_root(), "/objects");
1371bc2256c4SDaniel P. Berrange }
1372bc2256c4SDaniel P. Berrange 
1373*7c47c4eaSPeter Xu Object *object_get_internal_root(void)
1374*7c47c4eaSPeter Xu {
1375*7c47c4eaSPeter Xu     static Object *internal_root;
1376*7c47c4eaSPeter Xu 
1377*7c47c4eaSPeter Xu     if (!internal_root) {
1378*7c47c4eaSPeter Xu         internal_root = object_new("container");
1379*7c47c4eaSPeter Xu     }
1380*7c47c4eaSPeter Xu 
1381*7c47c4eaSPeter Xu     return internal_root;
1382*7c47c4eaSPeter Xu }
1383*7c47c4eaSPeter Xu 
1384d7bce999SEric Blake static void object_get_child_property(Object *obj, Visitor *v,
1385d7bce999SEric Blake                                       const char *name, void *opaque,
1386d7bce999SEric Blake                                       Error **errp)
138757c9fafeSAnthony Liguori {
138857c9fafeSAnthony Liguori     Object *child = opaque;
138957c9fafeSAnthony Liguori     gchar *path;
139057c9fafeSAnthony Liguori 
139157c9fafeSAnthony Liguori     path = object_get_canonical_path(child);
139251e72bc1SEric Blake     visit_type_str(v, name, &path, errp);
139357c9fafeSAnthony Liguori     g_free(path);
139457c9fafeSAnthony Liguori }
139557c9fafeSAnthony Liguori 
139664607d08SPaolo Bonzini static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part)
139764607d08SPaolo Bonzini {
139864607d08SPaolo Bonzini     return opaque;
139964607d08SPaolo Bonzini }
140064607d08SPaolo Bonzini 
1401db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name,
1402db85b575SAnthony Liguori                                            void *opaque)
1403db85b575SAnthony Liguori {
1404db85b575SAnthony Liguori     Object *child = opaque;
1405db85b575SAnthony Liguori 
1406bffc687dSPaolo Bonzini     if (child->class->unparent) {
1407bffc687dSPaolo Bonzini         (child->class->unparent)(child);
1408bffc687dSPaolo Bonzini     }
1409bffc687dSPaolo Bonzini     child->parent = NULL;
1410db85b575SAnthony Liguori     object_unref(child);
1411db85b575SAnthony Liguori }
1412db85b575SAnthony Liguori 
141357c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name,
141457c9fafeSAnthony Liguori                                Object *child, Error **errp)
141557c9fafeSAnthony Liguori {
1416b0ed5e9fSPaolo Bonzini     Error *local_err = NULL;
141757c9fafeSAnthony Liguori     gchar *type;
141864607d08SPaolo Bonzini     ObjectProperty *op;
141957c9fafeSAnthony Liguori 
14208faa2f85SPeter Crosthwaite     if (child->parent != NULL) {
14218faa2f85SPeter Crosthwaite         error_setg(errp, "child object is already parented");
14228faa2f85SPeter Crosthwaite         return;
14238faa2f85SPeter Crosthwaite     }
14248faa2f85SPeter Crosthwaite 
142557c9fafeSAnthony Liguori     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
142657c9fafeSAnthony Liguori 
142764607d08SPaolo Bonzini     op = object_property_add(obj, name, type, object_get_child_property, NULL,
1428b0ed5e9fSPaolo Bonzini                              object_finalize_child_property, child, &local_err);
1429b0ed5e9fSPaolo Bonzini     if (local_err) {
1430b0ed5e9fSPaolo Bonzini         error_propagate(errp, local_err);
1431b0ed5e9fSPaolo Bonzini         goto out;
1432b0ed5e9fSPaolo Bonzini     }
143364607d08SPaolo Bonzini 
143464607d08SPaolo Bonzini     op->resolve = object_resolve_child_property;
143557c9fafeSAnthony Liguori     object_ref(child);
143657c9fafeSAnthony Liguori     child->parent = obj;
143757c9fafeSAnthony Liguori 
1438b0ed5e9fSPaolo Bonzini out:
143957c9fafeSAnthony Liguori     g_free(type);
144057c9fafeSAnthony Liguori }
144157c9fafeSAnthony Liguori 
14428f5d58efSIgor Mammedov void object_property_allow_set_link(const Object *obj, const char *name,
144339f72ef9SStefan Hajnoczi                                     Object *val, Error **errp)
144439f72ef9SStefan Hajnoczi {
144539f72ef9SStefan Hajnoczi     /* Allow the link to be set, always */
144639f72ef9SStefan Hajnoczi }
144739f72ef9SStefan Hajnoczi 
14489561fda8SStefan Hajnoczi typedef struct {
14499561fda8SStefan Hajnoczi     Object **child;
14508f5d58efSIgor Mammedov     void (*check)(const Object *, const char *, Object *, Error **);
14519561fda8SStefan Hajnoczi     ObjectPropertyLinkFlags flags;
14529561fda8SStefan Hajnoczi } LinkProperty;
14539561fda8SStefan Hajnoczi 
1454d7bce999SEric Blake static void object_get_link_property(Object *obj, Visitor *v,
1455d7bce999SEric Blake                                      const char *name, void *opaque,
1456d7bce999SEric Blake                                      Error **errp)
145757c9fafeSAnthony Liguori {
14589561fda8SStefan Hajnoczi     LinkProperty *lprop = opaque;
14599561fda8SStefan Hajnoczi     Object **child = lprop->child;
146057c9fafeSAnthony Liguori     gchar *path;
146157c9fafeSAnthony Liguori 
146257c9fafeSAnthony Liguori     if (*child) {
146357c9fafeSAnthony Liguori         path = object_get_canonical_path(*child);
146451e72bc1SEric Blake         visit_type_str(v, name, &path, errp);
146557c9fafeSAnthony Liguori         g_free(path);
146657c9fafeSAnthony Liguori     } else {
146757c9fafeSAnthony Liguori         path = (gchar *)"";
146851e72bc1SEric Blake         visit_type_str(v, name, &path, errp);
146957c9fafeSAnthony Liguori     }
147057c9fafeSAnthony Liguori }
147157c9fafeSAnthony Liguori 
1472f5ec6704SStefan Hajnoczi /*
1473f5ec6704SStefan Hajnoczi  * object_resolve_link:
1474f5ec6704SStefan Hajnoczi  *
1475f5ec6704SStefan Hajnoczi  * Lookup an object and ensure its type matches the link property type.  This
1476f5ec6704SStefan Hajnoczi  * is similar to object_resolve_path() except type verification against the
1477f5ec6704SStefan Hajnoczi  * link property is performed.
1478f5ec6704SStefan Hajnoczi  *
1479f5ec6704SStefan Hajnoczi  * Returns: The matched object or NULL on path lookup failures.
1480f5ec6704SStefan Hajnoczi  */
1481f5ec6704SStefan Hajnoczi static Object *object_resolve_link(Object *obj, const char *name,
1482f5ec6704SStefan Hajnoczi                                    const char *path, Error **errp)
1483f5ec6704SStefan Hajnoczi {
1484f5ec6704SStefan Hajnoczi     const char *type;
1485f5ec6704SStefan Hajnoczi     gchar *target_type;
1486f5ec6704SStefan Hajnoczi     bool ambiguous = false;
1487f5ec6704SStefan Hajnoczi     Object *target;
1488f5ec6704SStefan Hajnoczi 
1489f5ec6704SStefan Hajnoczi     /* Go from link<FOO> to FOO.  */
1490f5ec6704SStefan Hajnoczi     type = object_property_get_type(obj, name, NULL);
1491f5ec6704SStefan Hajnoczi     target_type = g_strndup(&type[5], strlen(type) - 6);
1492f5ec6704SStefan Hajnoczi     target = object_resolve_path_type(path, target_type, &ambiguous);
1493f5ec6704SStefan Hajnoczi 
1494f5ec6704SStefan Hajnoczi     if (ambiguous) {
1495455b0fdeSEric Blake         error_setg(errp, "Path '%s' does not uniquely identify an object",
1496455b0fdeSEric Blake                    path);
1497f5ec6704SStefan Hajnoczi     } else if (!target) {
1498f5ec6704SStefan Hajnoczi         target = object_resolve_path(path, &ambiguous);
1499f5ec6704SStefan Hajnoczi         if (target || ambiguous) {
1500c6bd8c70SMarkus Armbruster             error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
1501f5ec6704SStefan Hajnoczi         } else {
150275158ebbSMarkus Armbruster             error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
150375158ebbSMarkus Armbruster                       "Device '%s' not found", path);
1504f5ec6704SStefan Hajnoczi         }
1505f5ec6704SStefan Hajnoczi         target = NULL;
1506f5ec6704SStefan Hajnoczi     }
1507f5ec6704SStefan Hajnoczi     g_free(target_type);
1508f5ec6704SStefan Hajnoczi 
1509f5ec6704SStefan Hajnoczi     return target;
1510f5ec6704SStefan Hajnoczi }
1511f5ec6704SStefan Hajnoczi 
1512d7bce999SEric Blake static void object_set_link_property(Object *obj, Visitor *v,
1513d7bce999SEric Blake                                      const char *name, void *opaque,
1514d7bce999SEric Blake                                      Error **errp)
151557c9fafeSAnthony Liguori {
1516c6aed983SStefan Hajnoczi     Error *local_err = NULL;
15179561fda8SStefan Hajnoczi     LinkProperty *prop = opaque;
15189561fda8SStefan Hajnoczi     Object **child = prop->child;
1519c6aed983SStefan Hajnoczi     Object *old_target = *child;
1520c6aed983SStefan Hajnoczi     Object *new_target = NULL;
1521c6aed983SStefan Hajnoczi     char *path = NULL;
152257c9fafeSAnthony Liguori 
152351e72bc1SEric Blake     visit_type_str(v, name, &path, &local_err);
152457c9fafeSAnthony Liguori 
1525c6aed983SStefan Hajnoczi     if (!local_err && strcmp(path, "") != 0) {
1526c6aed983SStefan Hajnoczi         new_target = object_resolve_link(obj, name, path, &local_err);
152711e35bfdSPaolo Bonzini     }
152857c9fafeSAnthony Liguori 
152957c9fafeSAnthony Liguori     g_free(path);
1530c6aed983SStefan Hajnoczi     if (local_err) {
1531c6aed983SStefan Hajnoczi         error_propagate(errp, local_err);
1532c6aed983SStefan Hajnoczi         return;
1533c6aed983SStefan Hajnoczi     }
1534f0cdc966SAlexander Barabash 
153539f72ef9SStefan Hajnoczi     prop->check(obj, name, new_target, &local_err);
153639f72ef9SStefan Hajnoczi     if (local_err) {
153739f72ef9SStefan Hajnoczi         error_propagate(errp, local_err);
153839f72ef9SStefan Hajnoczi         return;
153939f72ef9SStefan Hajnoczi     }
154039f72ef9SStefan Hajnoczi 
1541c6aed983SStefan Hajnoczi     object_ref(new_target);
1542c6aed983SStefan Hajnoczi     *child = new_target;
1543f0cdc966SAlexander Barabash     object_unref(old_target);
1544f0cdc966SAlexander Barabash }
154557c9fafeSAnthony Liguori 
154664607d08SPaolo Bonzini static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
154764607d08SPaolo Bonzini {
154864607d08SPaolo Bonzini     LinkProperty *lprop = opaque;
154964607d08SPaolo Bonzini 
155064607d08SPaolo Bonzini     return *lprop->child;
155164607d08SPaolo Bonzini }
155264607d08SPaolo Bonzini 
15539561fda8SStefan Hajnoczi static void object_release_link_property(Object *obj, const char *name,
15549561fda8SStefan Hajnoczi                                          void *opaque)
15559561fda8SStefan Hajnoczi {
15569561fda8SStefan Hajnoczi     LinkProperty *prop = opaque;
15579561fda8SStefan Hajnoczi 
15589561fda8SStefan Hajnoczi     if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) {
15599561fda8SStefan Hajnoczi         object_unref(*prop->child);
15609561fda8SStefan Hajnoczi     }
15619561fda8SStefan Hajnoczi     g_free(prop);
15629561fda8SStefan Hajnoczi }
15639561fda8SStefan Hajnoczi 
156457c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name,
156557c9fafeSAnthony Liguori                               const char *type, Object **child,
15668f5d58efSIgor Mammedov                               void (*check)(const Object *, const char *,
156739f72ef9SStefan Hajnoczi                                             Object *, Error **),
15689561fda8SStefan Hajnoczi                               ObjectPropertyLinkFlags flags,
156957c9fafeSAnthony Liguori                               Error **errp)
157057c9fafeSAnthony Liguori {
15719561fda8SStefan Hajnoczi     Error *local_err = NULL;
15729561fda8SStefan Hajnoczi     LinkProperty *prop = g_malloc(sizeof(*prop));
157357c9fafeSAnthony Liguori     gchar *full_type;
157464607d08SPaolo Bonzini     ObjectProperty *op;
157557c9fafeSAnthony Liguori 
15769561fda8SStefan Hajnoczi     prop->child = child;
157739f72ef9SStefan Hajnoczi     prop->check = check;
15789561fda8SStefan Hajnoczi     prop->flags = flags;
15799561fda8SStefan Hajnoczi 
158057c9fafeSAnthony Liguori     full_type = g_strdup_printf("link<%s>", type);
158157c9fafeSAnthony Liguori 
158264607d08SPaolo Bonzini     op = object_property_add(obj, name, full_type,
158357c9fafeSAnthony Liguori                              object_get_link_property,
158439f72ef9SStefan Hajnoczi                              check ? object_set_link_property : NULL,
15859561fda8SStefan Hajnoczi                              object_release_link_property,
15869561fda8SStefan Hajnoczi                              prop,
15879561fda8SStefan Hajnoczi                              &local_err);
15889561fda8SStefan Hajnoczi     if (local_err) {
15899561fda8SStefan Hajnoczi         error_propagate(errp, local_err);
15909561fda8SStefan Hajnoczi         g_free(prop);
159164607d08SPaolo Bonzini         goto out;
15929561fda8SStefan Hajnoczi     }
159357c9fafeSAnthony Liguori 
159464607d08SPaolo Bonzini     op->resolve = object_resolve_link_property;
159564607d08SPaolo Bonzini 
159664607d08SPaolo Bonzini out:
159757c9fafeSAnthony Liguori     g_free(full_type);
159857c9fafeSAnthony Liguori }
159957c9fafeSAnthony Liguori 
1600fb9e7e33SPaolo Bonzini void object_property_add_const_link(Object *obj, const char *name,
1601fb9e7e33SPaolo Bonzini                                     Object *target, Error **errp)
1602fb9e7e33SPaolo Bonzini {
1603fb9e7e33SPaolo Bonzini     char *link_type;
1604fb9e7e33SPaolo Bonzini     ObjectProperty *op;
1605fb9e7e33SPaolo Bonzini 
1606fb9e7e33SPaolo Bonzini     link_type = g_strdup_printf("link<%s>", object_get_typename(target));
1607fb9e7e33SPaolo Bonzini     op = object_property_add(obj, name, link_type,
1608fb9e7e33SPaolo Bonzini                              object_get_child_property, NULL,
1609fb9e7e33SPaolo Bonzini                              NULL, target, errp);
1610fb9e7e33SPaolo Bonzini     if (op != NULL) {
1611fb9e7e33SPaolo Bonzini         op->resolve = object_resolve_child_property;
1612fb9e7e33SPaolo Bonzini     }
1613fb9e7e33SPaolo Bonzini     g_free(link_type);
1614fb9e7e33SPaolo Bonzini }
1615fb9e7e33SPaolo Bonzini 
161611f590b1SStefan Hajnoczi gchar *object_get_canonical_path_component(Object *obj)
161757c9fafeSAnthony Liguori {
161857c9fafeSAnthony Liguori     ObjectProperty *prop = NULL;
1619b604a854SPavel Fedin     GHashTableIter iter;
162057c9fafeSAnthony Liguori 
162111f590b1SStefan Hajnoczi     g_assert(obj);
162257c9fafeSAnthony Liguori     g_assert(obj->parent != NULL);
162357c9fafeSAnthony Liguori 
1624b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->parent->properties);
1625b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) {
16265d9d3f47SAndreas Färber         if (!object_property_is_child(prop)) {
162757c9fafeSAnthony Liguori             continue;
162857c9fafeSAnthony Liguori         }
162957c9fafeSAnthony Liguori 
163057c9fafeSAnthony Liguori         if (prop->opaque == obj) {
163111f590b1SStefan Hajnoczi             return g_strdup(prop->name);
163257c9fafeSAnthony Liguori         }
163357c9fafeSAnthony Liguori     }
163457c9fafeSAnthony Liguori 
163511f590b1SStefan Hajnoczi     /* obj had a parent but was not a child, should never happen */
163611f590b1SStefan Hajnoczi     g_assert_not_reached();
163711f590b1SStefan Hajnoczi     return NULL;
163811f590b1SStefan Hajnoczi }
163911f590b1SStefan Hajnoczi 
164011f590b1SStefan Hajnoczi gchar *object_get_canonical_path(Object *obj)
164111f590b1SStefan Hajnoczi {
164211f590b1SStefan Hajnoczi     Object *root = object_get_root();
164311f590b1SStefan Hajnoczi     char *newpath, *path = NULL;
164411f590b1SStefan Hajnoczi 
164511f590b1SStefan Hajnoczi     while (obj != root) {
164611f590b1SStefan Hajnoczi         char *component = object_get_canonical_path_component(obj);
164711f590b1SStefan Hajnoczi 
164811f590b1SStefan Hajnoczi         if (path) {
164911f590b1SStefan Hajnoczi             newpath = g_strdup_printf("%s/%s", component, path);
165011f590b1SStefan Hajnoczi             g_free(component);
165111f590b1SStefan Hajnoczi             g_free(path);
165211f590b1SStefan Hajnoczi             path = newpath;
165311f590b1SStefan Hajnoczi         } else {
165411f590b1SStefan Hajnoczi             path = component;
165511f590b1SStefan Hajnoczi         }
165657c9fafeSAnthony Liguori 
165757c9fafeSAnthony Liguori         obj = obj->parent;
165857c9fafeSAnthony Liguori     }
165957c9fafeSAnthony Liguori 
166011f590b1SStefan Hajnoczi     newpath = g_strdup_printf("/%s", path ? path : "");
166157c9fafeSAnthony Liguori     g_free(path);
166257c9fafeSAnthony Liguori 
166357c9fafeSAnthony Liguori     return newpath;
166457c9fafeSAnthony Liguori }
166557c9fafeSAnthony Liguori 
16663e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part)
1667a612b2a6SPaolo Bonzini {
166889bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(parent, part, NULL);
1669a612b2a6SPaolo Bonzini     if (prop == NULL) {
1670a612b2a6SPaolo Bonzini         return NULL;
1671a612b2a6SPaolo Bonzini     }
1672a612b2a6SPaolo Bonzini 
167364607d08SPaolo Bonzini     if (prop->resolve) {
167464607d08SPaolo Bonzini         return prop->resolve(parent, prop->opaque, part);
1675a612b2a6SPaolo Bonzini     } else {
1676a612b2a6SPaolo Bonzini         return NULL;
1677a612b2a6SPaolo Bonzini     }
1678a612b2a6SPaolo Bonzini }
1679a612b2a6SPaolo Bonzini 
168057c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent,
168157c9fafeSAnthony Liguori                                           gchar **parts,
168202fe2db6SPaolo Bonzini                                           const char *typename,
168357c9fafeSAnthony Liguori                                           int index)
168457c9fafeSAnthony Liguori {
168557c9fafeSAnthony Liguori     Object *child;
168657c9fafeSAnthony Liguori 
168757c9fafeSAnthony Liguori     if (parts[index] == NULL) {
168802fe2db6SPaolo Bonzini         return object_dynamic_cast(parent, typename);
168957c9fafeSAnthony Liguori     }
169057c9fafeSAnthony Liguori 
169157c9fafeSAnthony Liguori     if (strcmp(parts[index], "") == 0) {
169202fe2db6SPaolo Bonzini         return object_resolve_abs_path(parent, parts, typename, index + 1);
169357c9fafeSAnthony Liguori     }
169457c9fafeSAnthony Liguori 
1695a612b2a6SPaolo Bonzini     child = object_resolve_path_component(parent, parts[index]);
169657c9fafeSAnthony Liguori     if (!child) {
169757c9fafeSAnthony Liguori         return NULL;
169857c9fafeSAnthony Liguori     }
169957c9fafeSAnthony Liguori 
170002fe2db6SPaolo Bonzini     return object_resolve_abs_path(child, parts, typename, index + 1);
170157c9fafeSAnthony Liguori }
170257c9fafeSAnthony Liguori 
170357c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent,
170457c9fafeSAnthony Liguori                                               gchar **parts,
170502fe2db6SPaolo Bonzini                                               const char *typename,
170657c9fafeSAnthony Liguori                                               bool *ambiguous)
170757c9fafeSAnthony Liguori {
170857c9fafeSAnthony Liguori     Object *obj;
1709b604a854SPavel Fedin     GHashTableIter iter;
171057c9fafeSAnthony Liguori     ObjectProperty *prop;
171157c9fafeSAnthony Liguori 
171202fe2db6SPaolo Bonzini     obj = object_resolve_abs_path(parent, parts, typename, 0);
171357c9fafeSAnthony Liguori 
1714b604a854SPavel Fedin     g_hash_table_iter_init(&iter, parent->properties);
1715b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) {
171657c9fafeSAnthony Liguori         Object *found;
171757c9fafeSAnthony Liguori 
17185d9d3f47SAndreas Färber         if (!object_property_is_child(prop)) {
171957c9fafeSAnthony Liguori             continue;
172057c9fafeSAnthony Liguori         }
172157c9fafeSAnthony Liguori 
172202fe2db6SPaolo Bonzini         found = object_resolve_partial_path(prop->opaque, parts,
172302fe2db6SPaolo Bonzini                                             typename, ambiguous);
172457c9fafeSAnthony Liguori         if (found) {
172557c9fafeSAnthony Liguori             if (obj) {
172657c9fafeSAnthony Liguori                 *ambiguous = true;
172757c9fafeSAnthony Liguori                 return NULL;
172857c9fafeSAnthony Liguori             }
172957c9fafeSAnthony Liguori             obj = found;
173057c9fafeSAnthony Liguori         }
173157c9fafeSAnthony Liguori 
1732ebcc479eSEduardo Habkost         if (*ambiguous) {
173357c9fafeSAnthony Liguori             return NULL;
173457c9fafeSAnthony Liguori         }
173557c9fafeSAnthony Liguori     }
173657c9fafeSAnthony Liguori 
173757c9fafeSAnthony Liguori     return obj;
173857c9fafeSAnthony Liguori }
173957c9fafeSAnthony Liguori 
174002fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename,
1741ebcc479eSEduardo Habkost                                  bool *ambiguousp)
174257c9fafeSAnthony Liguori {
174357c9fafeSAnthony Liguori     Object *obj;
174457c9fafeSAnthony Liguori     gchar **parts;
174557c9fafeSAnthony Liguori 
174657c9fafeSAnthony Liguori     parts = g_strsplit(path, "/", 0);
17472e1103f6SPaolo Bonzini     assert(parts);
174857c9fafeSAnthony Liguori 
17492e1103f6SPaolo Bonzini     if (parts[0] == NULL || strcmp(parts[0], "") != 0) {
1750ebcc479eSEduardo Habkost         bool ambiguous = false;
175102fe2db6SPaolo Bonzini         obj = object_resolve_partial_path(object_get_root(), parts,
1752ebcc479eSEduardo Habkost                                           typename, &ambiguous);
1753ebcc479eSEduardo Habkost         if (ambiguousp) {
1754ebcc479eSEduardo Habkost             *ambiguousp = ambiguous;
1755ebcc479eSEduardo Habkost         }
175657c9fafeSAnthony Liguori     } else {
175702fe2db6SPaolo Bonzini         obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
175857c9fafeSAnthony Liguori     }
175957c9fafeSAnthony Liguori 
176057c9fafeSAnthony Liguori     g_strfreev(parts);
176157c9fafeSAnthony Liguori 
176257c9fafeSAnthony Liguori     return obj;
176357c9fafeSAnthony Liguori }
176457c9fafeSAnthony Liguori 
176502fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous)
176602fe2db6SPaolo Bonzini {
176702fe2db6SPaolo Bonzini     return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
176802fe2db6SPaolo Bonzini }
176902fe2db6SPaolo Bonzini 
177057c9fafeSAnthony Liguori typedef struct StringProperty
177157c9fafeSAnthony Liguori {
177257c9fafeSAnthony Liguori     char *(*get)(Object *, Error **);
177357c9fafeSAnthony Liguori     void (*set)(Object *, const char *, Error **);
177457c9fafeSAnthony Liguori } StringProperty;
177557c9fafeSAnthony Liguori 
1776d7bce999SEric Blake static void property_get_str(Object *obj, Visitor *v, const char *name,
1777d7bce999SEric Blake                              void *opaque, Error **errp)
177857c9fafeSAnthony Liguori {
177957c9fafeSAnthony Liguori     StringProperty *prop = opaque;
178057c9fafeSAnthony Liguori     char *value;
1781e1c8237dSMarkus Armbruster     Error *err = NULL;
178257c9fafeSAnthony Liguori 
1783e1c8237dSMarkus Armbruster     value = prop->get(obj, &err);
1784e1c8237dSMarkus Armbruster     if (err) {
1785e1c8237dSMarkus Armbruster         error_propagate(errp, err);
1786e1c8237dSMarkus Armbruster         return;
1787e1c8237dSMarkus Armbruster     }
1788e1c8237dSMarkus Armbruster 
178951e72bc1SEric Blake     visit_type_str(v, name, &value, errp);
179057c9fafeSAnthony Liguori     g_free(value);
179157c9fafeSAnthony Liguori }
179257c9fafeSAnthony Liguori 
1793d7bce999SEric Blake static void property_set_str(Object *obj, Visitor *v, const char *name,
1794d7bce999SEric Blake                              void *opaque, Error **errp)
179557c9fafeSAnthony Liguori {
179657c9fafeSAnthony Liguori     StringProperty *prop = opaque;
179757c9fafeSAnthony Liguori     char *value;
179857c9fafeSAnthony Liguori     Error *local_err = NULL;
179957c9fafeSAnthony Liguori 
180051e72bc1SEric Blake     visit_type_str(v, name, &value, &local_err);
180157c9fafeSAnthony Liguori     if (local_err) {
180257c9fafeSAnthony Liguori         error_propagate(errp, local_err);
180357c9fafeSAnthony Liguori         return;
180457c9fafeSAnthony Liguori     }
180557c9fafeSAnthony Liguori 
180657c9fafeSAnthony Liguori     prop->set(obj, value, errp);
180757c9fafeSAnthony Liguori     g_free(value);
180857c9fafeSAnthony Liguori }
180957c9fafeSAnthony Liguori 
18107b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name,
181157c9fafeSAnthony Liguori                                  void *opaque)
181257c9fafeSAnthony Liguori {
181357c9fafeSAnthony Liguori     StringProperty *prop = opaque;
181457c9fafeSAnthony Liguori     g_free(prop);
181557c9fafeSAnthony Liguori }
181657c9fafeSAnthony Liguori 
181757c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name,
181857c9fafeSAnthony Liguori                            char *(*get)(Object *, Error **),
181957c9fafeSAnthony Liguori                            void (*set)(Object *, const char *, Error **),
182057c9fafeSAnthony Liguori                            Error **errp)
182157c9fafeSAnthony Liguori {
1822a01aedc8SStefan Hajnoczi     Error *local_err = NULL;
182357c9fafeSAnthony Liguori     StringProperty *prop = g_malloc0(sizeof(*prop));
182457c9fafeSAnthony Liguori 
182557c9fafeSAnthony Liguori     prop->get = get;
182657c9fafeSAnthony Liguori     prop->set = set;
182757c9fafeSAnthony Liguori 
182857c9fafeSAnthony Liguori     object_property_add(obj, name, "string",
18297b7b7d18SPaolo Bonzini                         get ? property_get_str : NULL,
18307b7b7d18SPaolo Bonzini                         set ? property_set_str : NULL,
18317b7b7d18SPaolo Bonzini                         property_release_str,
1832a01aedc8SStefan Hajnoczi                         prop, &local_err);
1833a01aedc8SStefan Hajnoczi     if (local_err) {
1834a01aedc8SStefan Hajnoczi         error_propagate(errp, local_err);
1835a01aedc8SStefan Hajnoczi         g_free(prop);
1836a01aedc8SStefan Hajnoczi     }
183757c9fafeSAnthony Liguori }
1838745549c8SPaolo Bonzini 
183916bf7f52SDaniel P. Berrange void object_class_property_add_str(ObjectClass *klass, const char *name,
184016bf7f52SDaniel P. Berrange                                    char *(*get)(Object *, Error **),
184116bf7f52SDaniel P. Berrange                                    void (*set)(Object *, const char *,
184216bf7f52SDaniel P. Berrange                                                Error **),
184316bf7f52SDaniel P. Berrange                                    Error **errp)
184416bf7f52SDaniel P. Berrange {
184516bf7f52SDaniel P. Berrange     Error *local_err = NULL;
184616bf7f52SDaniel P. Berrange     StringProperty *prop = g_malloc0(sizeof(*prop));
184716bf7f52SDaniel P. Berrange 
184816bf7f52SDaniel P. Berrange     prop->get = get;
184916bf7f52SDaniel P. Berrange     prop->set = set;
185016bf7f52SDaniel P. Berrange 
185116bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "string",
185216bf7f52SDaniel P. Berrange                               get ? property_get_str : NULL,
185316bf7f52SDaniel P. Berrange                               set ? property_set_str : NULL,
185416bf7f52SDaniel P. Berrange                               property_release_str,
185516bf7f52SDaniel P. Berrange                               prop, &local_err);
185616bf7f52SDaniel P. Berrange     if (local_err) {
185716bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
185816bf7f52SDaniel P. Berrange         g_free(prop);
185916bf7f52SDaniel P. Berrange     }
186016bf7f52SDaniel P. Berrange }
186116bf7f52SDaniel P. Berrange 
18620e558843SAnthony Liguori typedef struct BoolProperty
18630e558843SAnthony Liguori {
18640e558843SAnthony Liguori     bool (*get)(Object *, Error **);
18650e558843SAnthony Liguori     void (*set)(Object *, bool, Error **);
18660e558843SAnthony Liguori } BoolProperty;
18670e558843SAnthony Liguori 
1868d7bce999SEric Blake static void property_get_bool(Object *obj, Visitor *v, const char *name,
1869d7bce999SEric Blake                               void *opaque, Error **errp)
18700e558843SAnthony Liguori {
18710e558843SAnthony Liguori     BoolProperty *prop = opaque;
18720e558843SAnthony Liguori     bool value;
18734715d42eSMarkus Armbruster     Error *err = NULL;
18740e558843SAnthony Liguori 
18754715d42eSMarkus Armbruster     value = prop->get(obj, &err);
18764715d42eSMarkus Armbruster     if (err) {
18774715d42eSMarkus Armbruster         error_propagate(errp, err);
18784715d42eSMarkus Armbruster         return;
18794715d42eSMarkus Armbruster     }
18804715d42eSMarkus Armbruster 
188151e72bc1SEric Blake     visit_type_bool(v, name, &value, errp);
18820e558843SAnthony Liguori }
18830e558843SAnthony Liguori 
1884d7bce999SEric Blake static void property_set_bool(Object *obj, Visitor *v, const char *name,
1885d7bce999SEric Blake                               void *opaque, Error **errp)
18860e558843SAnthony Liguori {
18870e558843SAnthony Liguori     BoolProperty *prop = opaque;
18880e558843SAnthony Liguori     bool value;
18890e558843SAnthony Liguori     Error *local_err = NULL;
18900e558843SAnthony Liguori 
189151e72bc1SEric Blake     visit_type_bool(v, name, &value, &local_err);
18920e558843SAnthony Liguori     if (local_err) {
18930e558843SAnthony Liguori         error_propagate(errp, local_err);
18940e558843SAnthony Liguori         return;
18950e558843SAnthony Liguori     }
18960e558843SAnthony Liguori 
18970e558843SAnthony Liguori     prop->set(obj, value, errp);
18980e558843SAnthony Liguori }
18990e558843SAnthony Liguori 
19000e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name,
19010e558843SAnthony Liguori                                   void *opaque)
19020e558843SAnthony Liguori {
19030e558843SAnthony Liguori     BoolProperty *prop = opaque;
19040e558843SAnthony Liguori     g_free(prop);
19050e558843SAnthony Liguori }
19060e558843SAnthony Liguori 
19070e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name,
19080e558843SAnthony Liguori                               bool (*get)(Object *, Error **),
19090e558843SAnthony Liguori                               void (*set)(Object *, bool, Error **),
19100e558843SAnthony Liguori                               Error **errp)
19110e558843SAnthony Liguori {
1912a01aedc8SStefan Hajnoczi     Error *local_err = NULL;
19130e558843SAnthony Liguori     BoolProperty *prop = g_malloc0(sizeof(*prop));
19140e558843SAnthony Liguori 
19150e558843SAnthony Liguori     prop->get = get;
19160e558843SAnthony Liguori     prop->set = set;
19170e558843SAnthony Liguori 
19180e558843SAnthony Liguori     object_property_add(obj, name, "bool",
19190e558843SAnthony Liguori                         get ? property_get_bool : NULL,
19200e558843SAnthony Liguori                         set ? property_set_bool : NULL,
19210e558843SAnthony Liguori                         property_release_bool,
1922a01aedc8SStefan Hajnoczi                         prop, &local_err);
1923a01aedc8SStefan Hajnoczi     if (local_err) {
1924a01aedc8SStefan Hajnoczi         error_propagate(errp, local_err);
1925a01aedc8SStefan Hajnoczi         g_free(prop);
1926a01aedc8SStefan Hajnoczi     }
19270e558843SAnthony Liguori }
19280e558843SAnthony Liguori 
192916bf7f52SDaniel P. Berrange void object_class_property_add_bool(ObjectClass *klass, const char *name,
193016bf7f52SDaniel P. Berrange                                     bool (*get)(Object *, Error **),
193116bf7f52SDaniel P. Berrange                                     void (*set)(Object *, bool, Error **),
193216bf7f52SDaniel P. Berrange                                     Error **errp)
193316bf7f52SDaniel P. Berrange {
193416bf7f52SDaniel P. Berrange     Error *local_err = NULL;
193516bf7f52SDaniel P. Berrange     BoolProperty *prop = g_malloc0(sizeof(*prop));
193616bf7f52SDaniel P. Berrange 
193716bf7f52SDaniel P. Berrange     prop->get = get;
193816bf7f52SDaniel P. Berrange     prop->set = set;
193916bf7f52SDaniel P. Berrange 
194016bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "bool",
194116bf7f52SDaniel P. Berrange                               get ? property_get_bool : NULL,
194216bf7f52SDaniel P. Berrange                               set ? property_set_bool : NULL,
194316bf7f52SDaniel P. Berrange                               property_release_bool,
194416bf7f52SDaniel P. Berrange                               prop, &local_err);
194516bf7f52SDaniel P. Berrange     if (local_err) {
194616bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
194716bf7f52SDaniel P. Berrange         g_free(prop);
194816bf7f52SDaniel P. Berrange     }
194916bf7f52SDaniel P. Berrange }
195016bf7f52SDaniel P. Berrange 
1951d7bce999SEric Blake static void property_get_enum(Object *obj, Visitor *v, const char *name,
1952d7bce999SEric Blake                               void *opaque, Error **errp)
1953a8e3fbedSDaniel P. Berrange {
1954a8e3fbedSDaniel P. Berrange     EnumProperty *prop = opaque;
1955a8e3fbedSDaniel P. Berrange     int value;
19564715d42eSMarkus Armbruster     Error *err = NULL;
1957a8e3fbedSDaniel P. Berrange 
19584715d42eSMarkus Armbruster     value = prop->get(obj, &err);
19594715d42eSMarkus Armbruster     if (err) {
19604715d42eSMarkus Armbruster         error_propagate(errp, err);
19614715d42eSMarkus Armbruster         return;
19624715d42eSMarkus Armbruster     }
19634715d42eSMarkus Armbruster 
1964f7abe0ecSMarc-André Lureau     visit_type_enum(v, name, &value, prop->lookup, errp);
1965a8e3fbedSDaniel P. Berrange }
1966a8e3fbedSDaniel P. Berrange 
1967d7bce999SEric Blake static void property_set_enum(Object *obj, Visitor *v, const char *name,
1968d7bce999SEric Blake                               void *opaque, Error **errp)
1969a8e3fbedSDaniel P. Berrange {
1970a8e3fbedSDaniel P. Berrange     EnumProperty *prop = opaque;
1971a8e3fbedSDaniel P. Berrange     int value;
19724715d42eSMarkus Armbruster     Error *err = NULL;
1973a8e3fbedSDaniel P. Berrange 
1974f7abe0ecSMarc-André Lureau     visit_type_enum(v, name, &value, prop->lookup, &err);
19754715d42eSMarkus Armbruster     if (err) {
19764715d42eSMarkus Armbruster         error_propagate(errp, err);
19774715d42eSMarkus Armbruster         return;
19784715d42eSMarkus Armbruster     }
1979a8e3fbedSDaniel P. Berrange     prop->set(obj, value, errp);
1980a8e3fbedSDaniel P. Berrange }
1981a8e3fbedSDaniel P. Berrange 
1982a8e3fbedSDaniel P. Berrange static void property_release_enum(Object *obj, const char *name,
1983a8e3fbedSDaniel P. Berrange                                   void *opaque)
1984a8e3fbedSDaniel P. Berrange {
1985a8e3fbedSDaniel P. Berrange     EnumProperty *prop = opaque;
1986a8e3fbedSDaniel P. Berrange     g_free(prop);
1987a8e3fbedSDaniel P. Berrange }
1988a8e3fbedSDaniel P. Berrange 
1989a8e3fbedSDaniel P. Berrange void object_property_add_enum(Object *obj, const char *name,
1990a8e3fbedSDaniel P. Berrange                               const char *typename,
1991f7abe0ecSMarc-André Lureau                               const QEnumLookup *lookup,
1992a8e3fbedSDaniel P. Berrange                               int (*get)(Object *, Error **),
1993a8e3fbedSDaniel P. Berrange                               void (*set)(Object *, int, Error **),
1994a8e3fbedSDaniel P. Berrange                               Error **errp)
1995a8e3fbedSDaniel P. Berrange {
1996a8e3fbedSDaniel P. Berrange     Error *local_err = NULL;
1997a8e3fbedSDaniel P. Berrange     EnumProperty *prop = g_malloc(sizeof(*prop));
1998a8e3fbedSDaniel P. Berrange 
1999f7abe0ecSMarc-André Lureau     prop->lookup = lookup;
2000a8e3fbedSDaniel P. Berrange     prop->get = get;
2001a8e3fbedSDaniel P. Berrange     prop->set = set;
2002a8e3fbedSDaniel P. Berrange 
2003a8e3fbedSDaniel P. Berrange     object_property_add(obj, name, typename,
2004a8e3fbedSDaniel P. Berrange                         get ? property_get_enum : NULL,
2005a8e3fbedSDaniel P. Berrange                         set ? property_set_enum : NULL,
2006a8e3fbedSDaniel P. Berrange                         property_release_enum,
2007a8e3fbedSDaniel P. Berrange                         prop, &local_err);
2008a8e3fbedSDaniel P. Berrange     if (local_err) {
2009a8e3fbedSDaniel P. Berrange         error_propagate(errp, local_err);
2010a8e3fbedSDaniel P. Berrange         g_free(prop);
2011a8e3fbedSDaniel P. Berrange     }
2012a8e3fbedSDaniel P. Berrange }
2013a8e3fbedSDaniel P. Berrange 
201416bf7f52SDaniel P. Berrange void object_class_property_add_enum(ObjectClass *klass, const char *name,
201516bf7f52SDaniel P. Berrange                                     const char *typename,
2016f7abe0ecSMarc-André Lureau                                     const QEnumLookup *lookup,
201716bf7f52SDaniel P. Berrange                                     int (*get)(Object *, Error **),
201816bf7f52SDaniel P. Berrange                                     void (*set)(Object *, int, Error **),
201916bf7f52SDaniel P. Berrange                                     Error **errp)
202016bf7f52SDaniel P. Berrange {
202116bf7f52SDaniel P. Berrange     Error *local_err = NULL;
202216bf7f52SDaniel P. Berrange     EnumProperty *prop = g_malloc(sizeof(*prop));
202316bf7f52SDaniel P. Berrange 
2024f7abe0ecSMarc-André Lureau     prop->lookup = lookup;
202516bf7f52SDaniel P. Berrange     prop->get = get;
202616bf7f52SDaniel P. Berrange     prop->set = set;
202716bf7f52SDaniel P. Berrange 
202816bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, typename,
202916bf7f52SDaniel P. Berrange                               get ? property_get_enum : NULL,
203016bf7f52SDaniel P. Berrange                               set ? property_set_enum : NULL,
203116bf7f52SDaniel P. Berrange                               property_release_enum,
203216bf7f52SDaniel P. Berrange                               prop, &local_err);
203316bf7f52SDaniel P. Berrange     if (local_err) {
203416bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
203516bf7f52SDaniel P. Berrange         g_free(prop);
203616bf7f52SDaniel P. Berrange     }
203716bf7f52SDaniel P. Berrange }
203816bf7f52SDaniel P. Berrange 
20398e099d14SDavid Gibson typedef struct TMProperty {
20408e099d14SDavid Gibson     void (*get)(Object *, struct tm *, Error **);
20418e099d14SDavid Gibson } TMProperty;
20428e099d14SDavid Gibson 
2043d7bce999SEric Blake static void property_get_tm(Object *obj, Visitor *v, const char *name,
2044d7bce999SEric Blake                             void *opaque, Error **errp)
20458e099d14SDavid Gibson {
20468e099d14SDavid Gibson     TMProperty *prop = opaque;
20478e099d14SDavid Gibson     Error *err = NULL;
20488e099d14SDavid Gibson     struct tm value;
20498e099d14SDavid Gibson 
20508e099d14SDavid Gibson     prop->get(obj, &value, &err);
20518e099d14SDavid Gibson     if (err) {
20528e099d14SDavid Gibson         goto out;
20538e099d14SDavid Gibson     }
20548e099d14SDavid Gibson 
2055337283dfSEric Blake     visit_start_struct(v, name, NULL, 0, &err);
20568e099d14SDavid Gibson     if (err) {
20578e099d14SDavid Gibson         goto out;
20588e099d14SDavid Gibson     }
205951e72bc1SEric Blake     visit_type_int32(v, "tm_year", &value.tm_year, &err);
20608e099d14SDavid Gibson     if (err) {
20618e099d14SDavid Gibson         goto out_end;
20628e099d14SDavid Gibson     }
206351e72bc1SEric Blake     visit_type_int32(v, "tm_mon", &value.tm_mon, &err);
20648e099d14SDavid Gibson     if (err) {
20658e099d14SDavid Gibson         goto out_end;
20668e099d14SDavid Gibson     }
206751e72bc1SEric Blake     visit_type_int32(v, "tm_mday", &value.tm_mday, &err);
20688e099d14SDavid Gibson     if (err) {
20698e099d14SDavid Gibson         goto out_end;
20708e099d14SDavid Gibson     }
207151e72bc1SEric Blake     visit_type_int32(v, "tm_hour", &value.tm_hour, &err);
20728e099d14SDavid Gibson     if (err) {
20738e099d14SDavid Gibson         goto out_end;
20748e099d14SDavid Gibson     }
207551e72bc1SEric Blake     visit_type_int32(v, "tm_min", &value.tm_min, &err);
20768e099d14SDavid Gibson     if (err) {
20778e099d14SDavid Gibson         goto out_end;
20788e099d14SDavid Gibson     }
207951e72bc1SEric Blake     visit_type_int32(v, "tm_sec", &value.tm_sec, &err);
20808e099d14SDavid Gibson     if (err) {
20818e099d14SDavid Gibson         goto out_end;
20828e099d14SDavid Gibson     }
208315c2f669SEric Blake     visit_check_struct(v, &err);
20848e099d14SDavid Gibson out_end:
20851158bb2aSEric Blake     visit_end_struct(v, NULL);
20868e099d14SDavid Gibson out:
20878e099d14SDavid Gibson     error_propagate(errp, err);
20888e099d14SDavid Gibson 
20898e099d14SDavid Gibson }
20908e099d14SDavid Gibson 
20918e099d14SDavid Gibson static void property_release_tm(Object *obj, const char *name,
20928e099d14SDavid Gibson                                 void *opaque)
20938e099d14SDavid Gibson {
20948e099d14SDavid Gibson     TMProperty *prop = opaque;
20958e099d14SDavid Gibson     g_free(prop);
20968e099d14SDavid Gibson }
20978e099d14SDavid Gibson 
20988e099d14SDavid Gibson void object_property_add_tm(Object *obj, const char *name,
20998e099d14SDavid Gibson                             void (*get)(Object *, struct tm *, Error **),
21008e099d14SDavid Gibson                             Error **errp)
21018e099d14SDavid Gibson {
21028e099d14SDavid Gibson     Error *local_err = NULL;
21038e099d14SDavid Gibson     TMProperty *prop = g_malloc0(sizeof(*prop));
21048e099d14SDavid Gibson 
21058e099d14SDavid Gibson     prop->get = get;
21068e099d14SDavid Gibson 
21078e099d14SDavid Gibson     object_property_add(obj, name, "struct tm",
21088e099d14SDavid Gibson                         get ? property_get_tm : NULL, NULL,
21098e099d14SDavid Gibson                         property_release_tm,
21108e099d14SDavid Gibson                         prop, &local_err);
21118e099d14SDavid Gibson     if (local_err) {
21128e099d14SDavid Gibson         error_propagate(errp, local_err);
21138e099d14SDavid Gibson         g_free(prop);
21148e099d14SDavid Gibson     }
21158e099d14SDavid Gibson }
21168e099d14SDavid Gibson 
211716bf7f52SDaniel P. Berrange void object_class_property_add_tm(ObjectClass *klass, const char *name,
211816bf7f52SDaniel P. Berrange                                   void (*get)(Object *, struct tm *, Error **),
211916bf7f52SDaniel P. Berrange                                   Error **errp)
212016bf7f52SDaniel P. Berrange {
212116bf7f52SDaniel P. Berrange     Error *local_err = NULL;
212216bf7f52SDaniel P. Berrange     TMProperty *prop = g_malloc0(sizeof(*prop));
212316bf7f52SDaniel P. Berrange 
212416bf7f52SDaniel P. Berrange     prop->get = get;
212516bf7f52SDaniel P. Berrange 
212616bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "struct tm",
212716bf7f52SDaniel P. Berrange                               get ? property_get_tm : NULL, NULL,
212816bf7f52SDaniel P. Berrange                               property_release_tm,
212916bf7f52SDaniel P. Berrange                               prop, &local_err);
213016bf7f52SDaniel P. Berrange     if (local_err) {
213116bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
213216bf7f52SDaniel P. Berrange         g_free(prop);
213316bf7f52SDaniel P. Berrange     }
213416bf7f52SDaniel P. Berrange }
213516bf7f52SDaniel P. Berrange 
21362f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp)
21372f262e06SPaolo Bonzini {
21382f262e06SPaolo Bonzini     return g_strdup(object_get_typename(obj));
21392f262e06SPaolo Bonzini }
21402f262e06SPaolo Bonzini 
2141d7bce999SEric Blake static void property_get_uint8_ptr(Object *obj, Visitor *v, const char *name,
2142d7bce999SEric Blake                                    void *opaque, Error **errp)
2143e732ea63SMichael S. Tsirkin {
2144e732ea63SMichael S. Tsirkin     uint8_t value = *(uint8_t *)opaque;
214551e72bc1SEric Blake     visit_type_uint8(v, name, &value, errp);
2146e732ea63SMichael S. Tsirkin }
2147e732ea63SMichael S. Tsirkin 
2148d7bce999SEric Blake static void property_get_uint16_ptr(Object *obj, Visitor *v, const char *name,
2149d7bce999SEric Blake                                     void *opaque, Error **errp)
2150e732ea63SMichael S. Tsirkin {
2151e732ea63SMichael S. Tsirkin     uint16_t value = *(uint16_t *)opaque;
215251e72bc1SEric Blake     visit_type_uint16(v, name, &value, errp);
2153e732ea63SMichael S. Tsirkin }
2154e732ea63SMichael S. Tsirkin 
2155d7bce999SEric Blake static void property_get_uint32_ptr(Object *obj, Visitor *v, const char *name,
2156d7bce999SEric Blake                                     void *opaque, Error **errp)
2157e732ea63SMichael S. Tsirkin {
2158e732ea63SMichael S. Tsirkin     uint32_t value = *(uint32_t *)opaque;
215951e72bc1SEric Blake     visit_type_uint32(v, name, &value, errp);
2160e732ea63SMichael S. Tsirkin }
2161e732ea63SMichael S. Tsirkin 
2162d7bce999SEric Blake static void property_get_uint64_ptr(Object *obj, Visitor *v, const char *name,
2163d7bce999SEric Blake                                     void *opaque, Error **errp)
2164e732ea63SMichael S. Tsirkin {
2165e732ea63SMichael S. Tsirkin     uint64_t value = *(uint64_t *)opaque;
216651e72bc1SEric Blake     visit_type_uint64(v, name, &value, errp);
2167e732ea63SMichael S. Tsirkin }
2168e732ea63SMichael S. Tsirkin 
2169e732ea63SMichael S. Tsirkin void object_property_add_uint8_ptr(Object *obj, const char *name,
2170e732ea63SMichael S. Tsirkin                                    const uint8_t *v, Error **errp)
2171e732ea63SMichael S. Tsirkin {
2172e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint8", property_get_uint8_ptr,
2173e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2174e732ea63SMichael S. Tsirkin }
2175e732ea63SMichael S. Tsirkin 
217616bf7f52SDaniel P. Berrange void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name,
217716bf7f52SDaniel P. Berrange                                          const uint8_t *v, Error **errp)
217816bf7f52SDaniel P. Berrange {
217916bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint8", property_get_uint8_ptr,
218016bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
218116bf7f52SDaniel P. Berrange }
218216bf7f52SDaniel P. Berrange 
2183e732ea63SMichael S. Tsirkin void object_property_add_uint16_ptr(Object *obj, const char *name,
2184e732ea63SMichael S. Tsirkin                                     const uint16_t *v, Error **errp)
2185e732ea63SMichael S. Tsirkin {
2186e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint16", property_get_uint16_ptr,
2187e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2188e732ea63SMichael S. Tsirkin }
2189e732ea63SMichael S. Tsirkin 
219016bf7f52SDaniel P. Berrange void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name,
219116bf7f52SDaniel P. Berrange                                           const uint16_t *v, Error **errp)
219216bf7f52SDaniel P. Berrange {
219316bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint16", property_get_uint16_ptr,
219416bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
219516bf7f52SDaniel P. Berrange }
219616bf7f52SDaniel P. Berrange 
2197e732ea63SMichael S. Tsirkin void object_property_add_uint32_ptr(Object *obj, const char *name,
2198e732ea63SMichael S. Tsirkin                                     const uint32_t *v, Error **errp)
2199e732ea63SMichael S. Tsirkin {
2200e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint32", property_get_uint32_ptr,
2201e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2202e732ea63SMichael S. Tsirkin }
2203e732ea63SMichael S. Tsirkin 
220416bf7f52SDaniel P. Berrange void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name,
220516bf7f52SDaniel P. Berrange                                           const uint32_t *v, Error **errp)
220616bf7f52SDaniel P. Berrange {
220716bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint32", property_get_uint32_ptr,
220816bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
220916bf7f52SDaniel P. Berrange }
221016bf7f52SDaniel P. Berrange 
2211e732ea63SMichael S. Tsirkin void object_property_add_uint64_ptr(Object *obj, const char *name,
2212e732ea63SMichael S. Tsirkin                                     const uint64_t *v, Error **errp)
2213e732ea63SMichael S. Tsirkin {
2214e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint64", property_get_uint64_ptr,
2215e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2216e732ea63SMichael S. Tsirkin }
2217e732ea63SMichael S. Tsirkin 
221816bf7f52SDaniel P. Berrange void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name,
221916bf7f52SDaniel P. Berrange                                           const uint64_t *v, Error **errp)
222016bf7f52SDaniel P. Berrange {
222116bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint64", property_get_uint64_ptr,
222216bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
222316bf7f52SDaniel P. Berrange }
222416bf7f52SDaniel P. Berrange 
2225ef7c7ff6SStefan Hajnoczi typedef struct {
2226ef7c7ff6SStefan Hajnoczi     Object *target_obj;
22271590d266SEduardo Habkost     char *target_name;
2228ef7c7ff6SStefan Hajnoczi } AliasProperty;
2229ef7c7ff6SStefan Hajnoczi 
2230d7bce999SEric Blake static void property_get_alias(Object *obj, Visitor *v, const char *name,
2231d7bce999SEric Blake                                void *opaque, Error **errp)
2232ef7c7ff6SStefan Hajnoczi {
2233ef7c7ff6SStefan Hajnoczi     AliasProperty *prop = opaque;
2234ef7c7ff6SStefan Hajnoczi 
2235ef7c7ff6SStefan Hajnoczi     object_property_get(prop->target_obj, v, prop->target_name, errp);
2236ef7c7ff6SStefan Hajnoczi }
2237ef7c7ff6SStefan Hajnoczi 
2238d7bce999SEric Blake static void property_set_alias(Object *obj, Visitor *v, const char *name,
2239d7bce999SEric Blake                                void *opaque, Error **errp)
2240ef7c7ff6SStefan Hajnoczi {
2241ef7c7ff6SStefan Hajnoczi     AliasProperty *prop = opaque;
2242ef7c7ff6SStefan Hajnoczi 
2243ef7c7ff6SStefan Hajnoczi     object_property_set(prop->target_obj, v, prop->target_name, errp);
2244ef7c7ff6SStefan Hajnoczi }
2245ef7c7ff6SStefan Hajnoczi 
224664607d08SPaolo Bonzini static Object *property_resolve_alias(Object *obj, void *opaque,
224764607d08SPaolo Bonzini                                       const gchar *part)
224864607d08SPaolo Bonzini {
224964607d08SPaolo Bonzini     AliasProperty *prop = opaque;
225064607d08SPaolo Bonzini 
225164607d08SPaolo Bonzini     return object_resolve_path_component(prop->target_obj, prop->target_name);
225264607d08SPaolo Bonzini }
225364607d08SPaolo Bonzini 
2254ef7c7ff6SStefan Hajnoczi static void property_release_alias(Object *obj, const char *name, void *opaque)
2255ef7c7ff6SStefan Hajnoczi {
2256ef7c7ff6SStefan Hajnoczi     AliasProperty *prop = opaque;
2257ef7c7ff6SStefan Hajnoczi 
22581590d266SEduardo Habkost     g_free(prop->target_name);
2259ef7c7ff6SStefan Hajnoczi     g_free(prop);
2260ef7c7ff6SStefan Hajnoczi }
2261ef7c7ff6SStefan Hajnoczi 
2262ef7c7ff6SStefan Hajnoczi void object_property_add_alias(Object *obj, const char *name,
2263ef7c7ff6SStefan Hajnoczi                                Object *target_obj, const char *target_name,
2264ef7c7ff6SStefan Hajnoczi                                Error **errp)
2265ef7c7ff6SStefan Hajnoczi {
2266ef7c7ff6SStefan Hajnoczi     AliasProperty *prop;
226764607d08SPaolo Bonzini     ObjectProperty *op;
2268ef7c7ff6SStefan Hajnoczi     ObjectProperty *target_prop;
2269d190698eSPaolo Bonzini     gchar *prop_type;
22708ae9a9efSGonglei     Error *local_err = NULL;
2271ef7c7ff6SStefan Hajnoczi 
2272ef7c7ff6SStefan Hajnoczi     target_prop = object_property_find(target_obj, target_name, errp);
2273ef7c7ff6SStefan Hajnoczi     if (!target_prop) {
2274ef7c7ff6SStefan Hajnoczi         return;
2275ef7c7ff6SStefan Hajnoczi     }
2276ef7c7ff6SStefan Hajnoczi 
2277d190698eSPaolo Bonzini     if (object_property_is_child(target_prop)) {
2278d190698eSPaolo Bonzini         prop_type = g_strdup_printf("link%s",
2279d190698eSPaolo Bonzini                                     target_prop->type + strlen("child"));
2280d190698eSPaolo Bonzini     } else {
2281d190698eSPaolo Bonzini         prop_type = g_strdup(target_prop->type);
2282d190698eSPaolo Bonzini     }
2283d190698eSPaolo Bonzini 
2284ef7c7ff6SStefan Hajnoczi     prop = g_malloc(sizeof(*prop));
2285ef7c7ff6SStefan Hajnoczi     prop->target_obj = target_obj;
22861590d266SEduardo Habkost     prop->target_name = g_strdup(target_name);
2287ef7c7ff6SStefan Hajnoczi 
2288d190698eSPaolo Bonzini     op = object_property_add(obj, name, prop_type,
2289ef7c7ff6SStefan Hajnoczi                              property_get_alias,
2290ef7c7ff6SStefan Hajnoczi                              property_set_alias,
2291ef7c7ff6SStefan Hajnoczi                              property_release_alias,
22928ae9a9efSGonglei                              prop, &local_err);
22938ae9a9efSGonglei     if (local_err) {
22948ae9a9efSGonglei         error_propagate(errp, local_err);
22958ae9a9efSGonglei         g_free(prop);
22968ae9a9efSGonglei         goto out;
22978ae9a9efSGonglei     }
229864607d08SPaolo Bonzini     op->resolve = property_resolve_alias;
2299d190698eSPaolo Bonzini 
2300a18bb417SAndreas Färber     object_property_set_description(obj, op->name,
230180742642SGonglei                                     target_prop->description,
230280742642SGonglei                                     &error_abort);
230380742642SGonglei 
23048ae9a9efSGonglei out:
2305d190698eSPaolo Bonzini     g_free(prop_type);
2306ef7c7ff6SStefan Hajnoczi }
2307ef7c7ff6SStefan Hajnoczi 
230880742642SGonglei void object_property_set_description(Object *obj, const char *name,
230980742642SGonglei                                      const char *description, Error **errp)
231080742642SGonglei {
231180742642SGonglei     ObjectProperty *op;
231280742642SGonglei 
231380742642SGonglei     op = object_property_find(obj, name, errp);
231480742642SGonglei     if (!op) {
231580742642SGonglei         return;
231680742642SGonglei     }
231780742642SGonglei 
231880742642SGonglei     g_free(op->description);
231980742642SGonglei     op->description = g_strdup(description);
232080742642SGonglei }
232180742642SGonglei 
232216bf7f52SDaniel P. Berrange void object_class_property_set_description(ObjectClass *klass,
232316bf7f52SDaniel P. Berrange                                            const char *name,
232416bf7f52SDaniel P. Berrange                                            const char *description,
232516bf7f52SDaniel P. Berrange                                            Error **errp)
232616bf7f52SDaniel P. Berrange {
232716bf7f52SDaniel P. Berrange     ObjectProperty *op;
232816bf7f52SDaniel P. Berrange 
232916bf7f52SDaniel P. Berrange     op = g_hash_table_lookup(klass->properties, name);
233016bf7f52SDaniel P. Berrange     if (!op) {
233116bf7f52SDaniel P. Berrange         error_setg(errp, "Property '.%s' not found", name);
233216bf7f52SDaniel P. Berrange         return;
233316bf7f52SDaniel P. Berrange     }
233416bf7f52SDaniel P. Berrange 
233516bf7f52SDaniel P. Berrange     g_free(op->description);
233616bf7f52SDaniel P. Berrange     op->description = g_strdup(description);
233716bf7f52SDaniel P. Berrange }
233816bf7f52SDaniel P. Berrange 
23392f262e06SPaolo Bonzini static void object_instance_init(Object *obj)
23402f262e06SPaolo Bonzini {
23412f262e06SPaolo Bonzini     object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);
23422f262e06SPaolo Bonzini }
23432f262e06SPaolo Bonzini 
2344745549c8SPaolo Bonzini static void register_types(void)
2345745549c8SPaolo Bonzini {
2346745549c8SPaolo Bonzini     static TypeInfo interface_info = {
2347745549c8SPaolo Bonzini         .name = TYPE_INTERFACE,
234833e95c63SAnthony Liguori         .class_size = sizeof(InterfaceClass),
2349745549c8SPaolo Bonzini         .abstract = true,
2350745549c8SPaolo Bonzini     };
2351745549c8SPaolo Bonzini 
2352745549c8SPaolo Bonzini     static TypeInfo object_info = {
2353745549c8SPaolo Bonzini         .name = TYPE_OBJECT,
2354745549c8SPaolo Bonzini         .instance_size = sizeof(Object),
23552f262e06SPaolo Bonzini         .instance_init = object_instance_init,
2356745549c8SPaolo Bonzini         .abstract = true,
2357745549c8SPaolo Bonzini     };
2358745549c8SPaolo Bonzini 
2359049cb3cfSPaolo Bonzini     type_interface = type_register_internal(&interface_info);
2360049cb3cfSPaolo Bonzini     type_register_internal(&object_info);
2361745549c8SPaolo Bonzini }
2362745549c8SPaolo Bonzini 
2363745549c8SPaolo Bonzini type_init(register_types)
2364