xref: /qemu/qom/object.c (revision aafb21a0)
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"
19b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h"
20b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h"
21eb815e24SMarkus Armbruster #include "qapi/qapi-builtin-visit.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/qbool.h"
2915280c36SMarkus Armbruster #include "qapi/qmp/qnum.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 
154aa04c9d2SIgor Mammedov void type_register_static_array(const TypeInfo *infos, int nr_infos)
155aa04c9d2SIgor Mammedov {
156aa04c9d2SIgor Mammedov     int i;
157aa04c9d2SIgor Mammedov 
158aa04c9d2SIgor Mammedov     for (i = 0; i < nr_infos; i++) {
159aa04c9d2SIgor Mammedov         type_register_static(&infos[i]);
160aa04c9d2SIgor Mammedov     }
161aa04c9d2SIgor Mammedov }
162aa04c9d2SIgor Mammedov 
1632f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name)
1642f28d2ffSAnthony Liguori {
1652f28d2ffSAnthony Liguori     if (name == NULL) {
1662f28d2ffSAnthony Liguori         return NULL;
1672f28d2ffSAnthony Liguori     }
1682f28d2ffSAnthony Liguori 
1692f28d2ffSAnthony Liguori     return type_table_lookup(name);
1702f28d2ffSAnthony Liguori }
1712f28d2ffSAnthony Liguori 
1722f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type)
1732f28d2ffSAnthony Liguori {
1742f28d2ffSAnthony Liguori     if (!type->parent_type && type->parent) {
1752f28d2ffSAnthony Liguori         type->parent_type = type_get_by_name(type->parent);
1762f28d2ffSAnthony Liguori         g_assert(type->parent_type != NULL);
1772f28d2ffSAnthony Liguori     }
1782f28d2ffSAnthony Liguori 
1792f28d2ffSAnthony Liguori     return type->parent_type;
1802f28d2ffSAnthony Liguori }
1812f28d2ffSAnthony Liguori 
1822f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type)
1832f28d2ffSAnthony Liguori {
1842f28d2ffSAnthony Liguori     return (type->parent != NULL);
1852f28d2ffSAnthony Liguori }
1862f28d2ffSAnthony Liguori 
1872f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti)
1882f28d2ffSAnthony Liguori {
1892f28d2ffSAnthony Liguori     if (ti->class_size) {
1902f28d2ffSAnthony Liguori         return ti->class_size;
1912f28d2ffSAnthony Liguori     }
1922f28d2ffSAnthony Liguori 
1932f28d2ffSAnthony Liguori     if (type_has_parent(ti)) {
1942f28d2ffSAnthony Liguori         return type_class_get_size(type_get_parent(ti));
1952f28d2ffSAnthony Liguori     }
1962f28d2ffSAnthony Liguori 
1972f28d2ffSAnthony Liguori     return sizeof(ObjectClass);
1982f28d2ffSAnthony Liguori }
1992f28d2ffSAnthony Liguori 
200aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti)
201aca59af6SIgor Mitsyanko {
202aca59af6SIgor Mitsyanko     if (ti->instance_size) {
203aca59af6SIgor Mitsyanko         return ti->instance_size;
204aca59af6SIgor Mitsyanko     }
205aca59af6SIgor Mitsyanko 
206aca59af6SIgor Mitsyanko     if (type_has_parent(ti)) {
207aca59af6SIgor Mitsyanko         return type_object_get_size(type_get_parent(ti));
208aca59af6SIgor Mitsyanko     }
209aca59af6SIgor Mitsyanko 
210aca59af6SIgor Mitsyanko     return 0;
211aca59af6SIgor Mitsyanko }
212aca59af6SIgor Mitsyanko 
2133f97b53aSBharata B Rao size_t object_type_get_instance_size(const char *typename)
2143f97b53aSBharata B Rao {
2153f97b53aSBharata B Rao     TypeImpl *type = type_get_by_name(typename);
2163f97b53aSBharata B Rao 
2173f97b53aSBharata B Rao     g_assert(type != NULL);
2183f97b53aSBharata B Rao     return type_object_get_size(type);
2193f97b53aSBharata B Rao }
2203f97b53aSBharata B Rao 
22133e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
2222f28d2ffSAnthony Liguori {
22333e95c63SAnthony Liguori     assert(target_type);
2242f28d2ffSAnthony Liguori 
225b30d8054SCao jin     /* Check if target_type is a direct ancestor of type */
22633e95c63SAnthony Liguori     while (type) {
22733e95c63SAnthony Liguori         if (type == target_type) {
22833e95c63SAnthony Liguori             return true;
22933e95c63SAnthony Liguori         }
23033e95c63SAnthony Liguori 
23133e95c63SAnthony Liguori         type = type_get_parent(type);
23233e95c63SAnthony Liguori     }
23333e95c63SAnthony Liguori 
23433e95c63SAnthony Liguori     return false;
23533e95c63SAnthony Liguori }
23633e95c63SAnthony Liguori 
23733e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti);
23833e95c63SAnthony Liguori 
239b061dc41SPaolo Bonzini static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type,
240b061dc41SPaolo Bonzini                                       TypeImpl *parent_type)
24133e95c63SAnthony Liguori {
24233e95c63SAnthony Liguori     InterfaceClass *new_iface;
24333e95c63SAnthony Liguori     TypeInfo info = { };
24433e95c63SAnthony Liguori     TypeImpl *iface_impl;
24533e95c63SAnthony Liguori 
246b061dc41SPaolo Bonzini     info.parent = parent_type->name;
247b061dc41SPaolo Bonzini     info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name);
24833e95c63SAnthony Liguori     info.abstract = true;
24933e95c63SAnthony Liguori 
250b061dc41SPaolo Bonzini     iface_impl = type_new(&info);
251b061dc41SPaolo Bonzini     iface_impl->parent_type = parent_type;
25233e95c63SAnthony Liguori     type_initialize(iface_impl);
25333e95c63SAnthony Liguori     g_free((char *)info.name);
25433e95c63SAnthony Liguori 
25533e95c63SAnthony Liguori     new_iface = (InterfaceClass *)iface_impl->class;
25633e95c63SAnthony Liguori     new_iface->concrete_class = ti->class;
257b061dc41SPaolo Bonzini     new_iface->interface_type = interface_type;
25833e95c63SAnthony Liguori 
25933e95c63SAnthony Liguori     ti->class->interfaces = g_slist_append(ti->class->interfaces,
26033e95c63SAnthony Liguori                                            iface_impl->class);
2612f28d2ffSAnthony Liguori }
2622f28d2ffSAnthony Liguori 
26316bf7f52SDaniel P. Berrange static void object_property_free(gpointer data)
26416bf7f52SDaniel P. Berrange {
26516bf7f52SDaniel P. Berrange     ObjectProperty *prop = data;
26616bf7f52SDaniel P. Berrange 
26716bf7f52SDaniel P. Berrange     g_free(prop->name);
26816bf7f52SDaniel P. Berrange     g_free(prop->type);
26916bf7f52SDaniel P. Berrange     g_free(prop->description);
27016bf7f52SDaniel P. Berrange     g_free(prop);
27116bf7f52SDaniel P. Berrange }
27216bf7f52SDaniel P. Berrange 
273ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti)
2742f28d2ffSAnthony Liguori {
275745549c8SPaolo Bonzini     TypeImpl *parent;
2762f28d2ffSAnthony Liguori 
2772f28d2ffSAnthony Liguori     if (ti->class) {
2782f28d2ffSAnthony Liguori         return;
2792f28d2ffSAnthony Liguori     }
2802f28d2ffSAnthony Liguori 
2812f28d2ffSAnthony Liguori     ti->class_size = type_class_get_size(ti);
282aca59af6SIgor Mitsyanko     ti->instance_size = type_object_get_size(ti);
2831c6d75d5SEduardo Habkost     /* Any type with zero instance_size is implicitly abstract.
2841c6d75d5SEduardo Habkost      * This means interface types are all abstract.
2851c6d75d5SEduardo Habkost      */
2861c6d75d5SEduardo Habkost     if (ti->instance_size == 0) {
2871c6d75d5SEduardo Habkost         ti->abstract = true;
2881c6d75d5SEduardo Habkost     }
2892f28d2ffSAnthony Liguori 
2902f28d2ffSAnthony Liguori     ti->class = g_malloc0(ti->class_size);
2912f28d2ffSAnthony Liguori 
292745549c8SPaolo Bonzini     parent = type_get_parent(ti);
293745549c8SPaolo Bonzini     if (parent) {
294ac451033SIgor Mitsyanko         type_initialize(parent);
29533e95c63SAnthony Liguori         GSList *e;
29633e95c63SAnthony Liguori         int i;
2972f28d2ffSAnthony Liguori 
2988438a135SAndreas Färber         g_assert_cmpint(parent->class_size, <=, ti->class_size);
299745549c8SPaolo Bonzini         memcpy(ti->class, parent->class, parent->class_size);
3003e407de4SPeter Crosthwaite         ti->class->interfaces = NULL;
30116bf7f52SDaniel P. Berrange         ti->class->properties = g_hash_table_new_full(
30216bf7f52SDaniel P. Berrange             g_str_hash, g_str_equal, g_free, object_property_free);
30333e95c63SAnthony Liguori 
30433e95c63SAnthony Liguori         for (e = parent->class->interfaces; e; e = e->next) {
305b061dc41SPaolo Bonzini             InterfaceClass *iface = e->data;
306b061dc41SPaolo Bonzini             ObjectClass *klass = OBJECT_CLASS(iface);
307b061dc41SPaolo Bonzini 
308b061dc41SPaolo Bonzini             type_initialize_interface(ti, iface->interface_type, klass->type);
30933e95c63SAnthony Liguori         }
31033e95c63SAnthony Liguori 
31133e95c63SAnthony Liguori         for (i = 0; i < ti->num_interfaces; i++) {
31233e95c63SAnthony Liguori             TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
31333e95c63SAnthony Liguori             for (e = ti->class->interfaces; e; e = e->next) {
31433e95c63SAnthony Liguori                 TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
31533e95c63SAnthony Liguori 
31633e95c63SAnthony Liguori                 if (type_is_ancestor(target_type, t)) {
31733e95c63SAnthony Liguori                     break;
31833e95c63SAnthony Liguori                 }
31933e95c63SAnthony Liguori             }
32033e95c63SAnthony Liguori 
32133e95c63SAnthony Liguori             if (e) {
32233e95c63SAnthony Liguori                 continue;
32333e95c63SAnthony Liguori             }
32433e95c63SAnthony Liguori 
325b061dc41SPaolo Bonzini             type_initialize_interface(ti, t, t);
32633e95c63SAnthony Liguori         }
32716bf7f52SDaniel P. Berrange     } else {
32816bf7f52SDaniel P. Berrange         ti->class->properties = g_hash_table_new_full(
32916bf7f52SDaniel P. Berrange             g_str_hash, g_str_equal, g_free, object_property_free);
330745549c8SPaolo Bonzini     }
3312f28d2ffSAnthony Liguori 
332745549c8SPaolo Bonzini     ti->class->type = ti;
3333b50e311SPaolo Bonzini 
3343b50e311SPaolo Bonzini     while (parent) {
3353b50e311SPaolo Bonzini         if (parent->class_base_init) {
3363b50e311SPaolo Bonzini             parent->class_base_init(ti->class, ti->class_data);
3373b50e311SPaolo Bonzini         }
3383b50e311SPaolo Bonzini         parent = type_get_parent(parent);
3393b50e311SPaolo Bonzini     }
3402f28d2ffSAnthony Liguori 
3412f28d2ffSAnthony Liguori     if (ti->class_init) {
3422f28d2ffSAnthony Liguori         ti->class_init(ti->class, ti->class_data);
3432f28d2ffSAnthony Liguori     }
3442f28d2ffSAnthony Liguori }
3452f28d2ffSAnthony Liguori 
3462f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti)
3472f28d2ffSAnthony Liguori {
3482f28d2ffSAnthony Liguori     if (type_has_parent(ti)) {
3492f28d2ffSAnthony Liguori         object_init_with_type(obj, type_get_parent(ti));
3502f28d2ffSAnthony Liguori     }
3512f28d2ffSAnthony Liguori 
3522f28d2ffSAnthony Liguori     if (ti->instance_init) {
3532f28d2ffSAnthony Liguori         ti->instance_init(obj);
3542f28d2ffSAnthony Liguori     }
3552f28d2ffSAnthony Liguori }
3562f28d2ffSAnthony Liguori 
3578231c2ddSEduardo Habkost static void object_post_init_with_type(Object *obj, TypeImpl *ti)
3588231c2ddSEduardo Habkost {
3598231c2ddSEduardo Habkost     if (ti->instance_post_init) {
3608231c2ddSEduardo Habkost         ti->instance_post_init(obj);
3618231c2ddSEduardo Habkost     }
3628231c2ddSEduardo Habkost 
3638231c2ddSEduardo Habkost     if (type_has_parent(ti)) {
3648231c2ddSEduardo Habkost         object_post_init_with_type(obj, type_get_parent(ti));
3658231c2ddSEduardo Habkost     }
3668231c2ddSEduardo Habkost }
3678231c2ddSEduardo Habkost 
36863f7b10bSMarc-André Lureau static void object_initialize_with_type(void *data, size_t size, TypeImpl *type)
3692f28d2ffSAnthony Liguori {
3702f28d2ffSAnthony Liguori     Object *obj = data;
3712f28d2ffSAnthony Liguori 
3722f28d2ffSAnthony Liguori     g_assert(type != NULL);
373ac451033SIgor Mitsyanko     type_initialize(type);
374aca59af6SIgor Mitsyanko 
3758438a135SAndreas Färber     g_assert_cmpint(type->instance_size, >=, sizeof(Object));
3762f28d2ffSAnthony Liguori     g_assert(type->abstract == false);
3778438a135SAndreas Färber     g_assert_cmpint(size, >=, type->instance_size);
3782f28d2ffSAnthony Liguori 
3792f28d2ffSAnthony Liguori     memset(obj, 0, type->instance_size);
3802f28d2ffSAnthony Liguori     obj->class = type->class;
381764b6312SPaolo Bonzini     object_ref(obj);
382b604a854SPavel Fedin     obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
383b604a854SPavel Fedin                                             NULL, object_property_free);
3842f28d2ffSAnthony Liguori     object_init_with_type(obj, type);
3858231c2ddSEduardo Habkost     object_post_init_with_type(obj, type);
3862f28d2ffSAnthony Liguori }
3872f28d2ffSAnthony Liguori 
388213f0c4fSAndreas Färber void object_initialize(void *data, size_t size, const char *typename)
3892f28d2ffSAnthony Liguori {
3902f28d2ffSAnthony Liguori     TypeImpl *type = type_get_by_name(typename);
3912f28d2ffSAnthony Liguori 
3925b9237f6SAndreas Färber     object_initialize_with_type(data, size, type);
3932f28d2ffSAnthony Liguori }
3942f28d2ffSAnthony Liguori 
3955d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop)
3965d9d3f47SAndreas Färber {
3975d9d3f47SAndreas Färber     return strstart(prop->type, "child<", NULL);
3985d9d3f47SAndreas Färber }
3995d9d3f47SAndreas Färber 
40057c9fafeSAnthony Liguori static void object_property_del_all(Object *obj)
40157c9fafeSAnthony Liguori {
402b604a854SPavel Fedin     ObjectProperty *prop;
403b604a854SPavel Fedin     GHashTableIter iter;
404b604a854SPavel Fedin     gpointer key, value;
405b604a854SPavel Fedin     bool released;
40657c9fafeSAnthony Liguori 
407b604a854SPavel Fedin     do {
408b604a854SPavel Fedin         released = false;
409b604a854SPavel Fedin         g_hash_table_iter_init(&iter, obj->properties);
410b604a854SPavel Fedin         while (g_hash_table_iter_next(&iter, &key, &value)) {
411b604a854SPavel Fedin             prop = value;
41257c9fafeSAnthony Liguori             if (prop->release) {
41357c9fafeSAnthony Liguori                 prop->release(obj, prop->name, prop->opaque);
414b604a854SPavel Fedin                 prop->release = NULL;
415b604a854SPavel Fedin                 released = true;
416b604a854SPavel Fedin                 break;
41757c9fafeSAnthony Liguori             }
418b604a854SPavel Fedin             g_hash_table_iter_remove(&iter);
419b604a854SPavel Fedin         }
420b604a854SPavel Fedin     } while (released);
42157c9fafeSAnthony Liguori 
422b604a854SPavel Fedin     g_hash_table_unref(obj->properties);
42357c9fafeSAnthony Liguori }
42457c9fafeSAnthony Liguori 
42557c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp)
42657c9fafeSAnthony Liguori {
42757c9fafeSAnthony Liguori     ObjectProperty *prop;
428b604a854SPavel Fedin     GHashTableIter iter;
429b604a854SPavel Fedin     gpointer key, value;
43057c9fafeSAnthony Liguori 
431b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->properties);
432b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, &key, &value)) {
433b604a854SPavel Fedin         prop = value;
4345d9d3f47SAndreas Färber         if (object_property_is_child(prop) && prop->opaque == child) {
435b604a854SPavel Fedin             if (prop->release) {
436b604a854SPavel Fedin                 prop->release(obj, prop->name, prop->opaque);
437b604a854SPavel Fedin                 prop->release = NULL;
438b604a854SPavel Fedin             }
439b604a854SPavel Fedin             break;
440b604a854SPavel Fedin         }
441b604a854SPavel Fedin     }
442b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->properties);
443b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, &key, &value)) {
444b604a854SPavel Fedin         prop = value;
445b604a854SPavel Fedin         if (object_property_is_child(prop) && prop->opaque == child) {
446b604a854SPavel Fedin             g_hash_table_iter_remove(&iter);
4476c1fdcf9SPaolo Bonzini             break;
44857c9fafeSAnthony Liguori         }
44957c9fafeSAnthony Liguori     }
45057c9fafeSAnthony Liguori }
45157c9fafeSAnthony Liguori 
45257c9fafeSAnthony Liguori void object_unparent(Object *obj)
45357c9fafeSAnthony Liguori {
454e998fa8dSMichael S. Tsirkin     if (obj->parent) {
455e998fa8dSMichael S. Tsirkin         object_property_del_child(obj->parent, obj, NULL);
456e998fa8dSMichael S. Tsirkin     }
45757c9fafeSAnthony Liguori }
45857c9fafeSAnthony Liguori 
4592f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type)
4602f28d2ffSAnthony Liguori {
4612f28d2ffSAnthony Liguori     if (type->instance_finalize) {
4622f28d2ffSAnthony Liguori         type->instance_finalize(obj);
4632f28d2ffSAnthony Liguori     }
4642f28d2ffSAnthony Liguori 
4652f28d2ffSAnthony Liguori     if (type_has_parent(type)) {
4662f28d2ffSAnthony Liguori         object_deinit(obj, type_get_parent(type));
4672f28d2ffSAnthony Liguori     }
4682f28d2ffSAnthony Liguori }
4692f28d2ffSAnthony Liguori 
470339c2708SPaolo Bonzini static void object_finalize(void *data)
4712f28d2ffSAnthony Liguori {
4722f28d2ffSAnthony Liguori     Object *obj = data;
4732f28d2ffSAnthony Liguori     TypeImpl *ti = obj->class->type;
4742f28d2ffSAnthony Liguori 
47557c9fafeSAnthony Liguori     object_property_del_all(obj);
47676a6e1ccSPaolo Bonzini     object_deinit(obj, ti);
477db85b575SAnthony Liguori 
4788438a135SAndreas Färber     g_assert_cmpint(obj->ref, ==, 0);
479fde9bf44SPaolo Bonzini     if (obj->free) {
480fde9bf44SPaolo Bonzini         obj->free(obj);
481fde9bf44SPaolo Bonzini     }
4822f28d2ffSAnthony Liguori }
4832f28d2ffSAnthony Liguori 
48463f7b10bSMarc-André Lureau static Object *object_new_with_type(Type type)
4852f28d2ffSAnthony Liguori {
4862f28d2ffSAnthony Liguori     Object *obj;
4872f28d2ffSAnthony Liguori 
4882f28d2ffSAnthony Liguori     g_assert(type != NULL);
489ac451033SIgor Mitsyanko     type_initialize(type);
4902f28d2ffSAnthony Liguori 
4912f28d2ffSAnthony Liguori     obj = g_malloc(type->instance_size);
4925b9237f6SAndreas Färber     object_initialize_with_type(obj, type->instance_size, type);
493fde9bf44SPaolo Bonzini     obj->free = g_free;
4942f28d2ffSAnthony Liguori 
4952f28d2ffSAnthony Liguori     return obj;
4962f28d2ffSAnthony Liguori }
4972f28d2ffSAnthony Liguori 
4982f28d2ffSAnthony Liguori Object *object_new(const char *typename)
4992f28d2ffSAnthony Liguori {
5002f28d2ffSAnthony Liguori     TypeImpl *ti = type_get_by_name(typename);
5012f28d2ffSAnthony Liguori 
5022f28d2ffSAnthony Liguori     return object_new_with_type(ti);
5032f28d2ffSAnthony Liguori }
5042f28d2ffSAnthony Liguori 
505a31bdae5SDaniel P. Berrange 
506a31bdae5SDaniel P. Berrange Object *object_new_with_props(const char *typename,
507a31bdae5SDaniel P. Berrange                               Object *parent,
508a31bdae5SDaniel P. Berrange                               const char *id,
509a31bdae5SDaniel P. Berrange                               Error **errp,
510a31bdae5SDaniel P. Berrange                               ...)
511a31bdae5SDaniel P. Berrange {
512a31bdae5SDaniel P. Berrange     va_list vargs;
513a31bdae5SDaniel P. Berrange     Object *obj;
514a31bdae5SDaniel P. Berrange 
515a31bdae5SDaniel P. Berrange     va_start(vargs, errp);
516a31bdae5SDaniel P. Berrange     obj = object_new_with_propv(typename, parent, id, errp, vargs);
517a31bdae5SDaniel P. Berrange     va_end(vargs);
518a31bdae5SDaniel P. Berrange 
519a31bdae5SDaniel P. Berrange     return obj;
520a31bdae5SDaniel P. Berrange }
521a31bdae5SDaniel P. Berrange 
522a31bdae5SDaniel P. Berrange 
523a31bdae5SDaniel P. Berrange Object *object_new_with_propv(const char *typename,
524a31bdae5SDaniel P. Berrange                               Object *parent,
525a31bdae5SDaniel P. Berrange                               const char *id,
526a31bdae5SDaniel P. Berrange                               Error **errp,
527a31bdae5SDaniel P. Berrange                               va_list vargs)
528a31bdae5SDaniel P. Berrange {
529a31bdae5SDaniel P. Berrange     Object *obj;
530a31bdae5SDaniel P. Berrange     ObjectClass *klass;
531a31bdae5SDaniel P. Berrange     Error *local_err = NULL;
532a31bdae5SDaniel P. Berrange 
533a31bdae5SDaniel P. Berrange     klass = object_class_by_name(typename);
534a31bdae5SDaniel P. Berrange     if (!klass) {
535a31bdae5SDaniel P. Berrange         error_setg(errp, "invalid object type: %s", typename);
536a31bdae5SDaniel P. Berrange         return NULL;
537a31bdae5SDaniel P. Berrange     }
538a31bdae5SDaniel P. Berrange 
539a31bdae5SDaniel P. Berrange     if (object_class_is_abstract(klass)) {
540a31bdae5SDaniel P. Berrange         error_setg(errp, "object type '%s' is abstract", typename);
541a31bdae5SDaniel P. Berrange         return NULL;
542a31bdae5SDaniel P. Berrange     }
543a31bdae5SDaniel P. Berrange     obj = object_new(typename);
544a31bdae5SDaniel P. Berrange 
545a31bdae5SDaniel P. Berrange     if (object_set_propv(obj, &local_err, vargs) < 0) {
546a31bdae5SDaniel P. Berrange         goto error;
547a31bdae5SDaniel P. Berrange     }
548a31bdae5SDaniel P. Berrange 
549a31bdae5SDaniel P. Berrange     object_property_add_child(parent, id, obj, &local_err);
550a31bdae5SDaniel P. Berrange     if (local_err) {
551a31bdae5SDaniel P. Berrange         goto error;
552a31bdae5SDaniel P. Berrange     }
553a31bdae5SDaniel P. Berrange 
554a31bdae5SDaniel P. Berrange     if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
555a31bdae5SDaniel P. Berrange         user_creatable_complete(obj, &local_err);
556a31bdae5SDaniel P. Berrange         if (local_err) {
557a31bdae5SDaniel P. Berrange             object_unparent(obj);
558a31bdae5SDaniel P. Berrange             goto error;
559a31bdae5SDaniel P. Berrange         }
560a31bdae5SDaniel P. Berrange     }
561a31bdae5SDaniel P. Berrange 
562a31bdae5SDaniel P. Berrange     object_unref(OBJECT(obj));
563a31bdae5SDaniel P. Berrange     return obj;
564a31bdae5SDaniel P. Berrange 
565a31bdae5SDaniel P. Berrange  error:
566a31bdae5SDaniel P. Berrange     error_propagate(errp, local_err);
567a31bdae5SDaniel P. Berrange     object_unref(obj);
568a31bdae5SDaniel P. Berrange     return NULL;
569a31bdae5SDaniel P. Berrange }
570a31bdae5SDaniel P. Berrange 
571a31bdae5SDaniel P. Berrange 
572a31bdae5SDaniel P. Berrange int object_set_props(Object *obj,
573a31bdae5SDaniel P. Berrange                      Error **errp,
574a31bdae5SDaniel P. Berrange                      ...)
575a31bdae5SDaniel P. Berrange {
576a31bdae5SDaniel P. Berrange     va_list vargs;
577a31bdae5SDaniel P. Berrange     int ret;
578a31bdae5SDaniel P. Berrange 
579a31bdae5SDaniel P. Berrange     va_start(vargs, errp);
580a31bdae5SDaniel P. Berrange     ret = object_set_propv(obj, errp, vargs);
581a31bdae5SDaniel P. Berrange     va_end(vargs);
582a31bdae5SDaniel P. Berrange 
583a31bdae5SDaniel P. Berrange     return ret;
584a31bdae5SDaniel P. Berrange }
585a31bdae5SDaniel P. Berrange 
586a31bdae5SDaniel P. Berrange 
587a31bdae5SDaniel P. Berrange int object_set_propv(Object *obj,
588a31bdae5SDaniel P. Berrange                      Error **errp,
589a31bdae5SDaniel P. Berrange                      va_list vargs)
590a31bdae5SDaniel P. Berrange {
591a31bdae5SDaniel P. Berrange     const char *propname;
592a31bdae5SDaniel P. Berrange     Error *local_err = NULL;
593a31bdae5SDaniel P. Berrange 
594a31bdae5SDaniel P. Berrange     propname = va_arg(vargs, char *);
595a31bdae5SDaniel P. Berrange     while (propname != NULL) {
596a31bdae5SDaniel P. Berrange         const char *value = va_arg(vargs, char *);
597a31bdae5SDaniel P. Berrange 
598a31bdae5SDaniel P. Berrange         g_assert(value != NULL);
599a31bdae5SDaniel P. Berrange         object_property_parse(obj, value, propname, &local_err);
600a31bdae5SDaniel P. Berrange         if (local_err) {
601a31bdae5SDaniel P. Berrange             error_propagate(errp, local_err);
602a31bdae5SDaniel P. Berrange             return -1;
603a31bdae5SDaniel P. Berrange         }
604a31bdae5SDaniel P. Berrange         propname = va_arg(vargs, char *);
605a31bdae5SDaniel P. Berrange     }
606a31bdae5SDaniel P. Berrange 
607a31bdae5SDaniel P. Berrange     return 0;
608a31bdae5SDaniel P. Berrange }
609a31bdae5SDaniel P. Berrange 
610a31bdae5SDaniel P. Berrange 
6112f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename)
6122f28d2ffSAnthony Liguori {
613b7f43fe4SPaolo Bonzini     if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) {
614acc4af3fSPaolo Bonzini         return obj;
615acc4af3fSPaolo Bonzini     }
616acc4af3fSPaolo Bonzini 
6172f28d2ffSAnthony Liguori     return NULL;
6182f28d2ffSAnthony Liguori }
6192f28d2ffSAnthony Liguori 
620be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename,
621be17f18bSPaolo Bonzini                                    const char *file, int line, const char *func)
6222f28d2ffSAnthony Liguori {
623fa131d94SPaolo Bonzini     trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)",
624fa131d94SPaolo Bonzini                                      typename, file, line, func);
625fa131d94SPaolo Bonzini 
6263556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG
62703587328SAnthony Liguori     int i;
62803587328SAnthony Liguori     Object *inst;
62903587328SAnthony Liguori 
63095916abcSPeter Crosthwaite     for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) {
631b6b3ccfdSAlex Bennée         if (atomic_read(&obj->class->object_cast_cache[i]) == typename) {
63203587328SAnthony Liguori             goto out;
63303587328SAnthony Liguori         }
63403587328SAnthony Liguori     }
63503587328SAnthony Liguori 
63603587328SAnthony Liguori     inst = object_dynamic_cast(obj, typename);
6372f28d2ffSAnthony Liguori 
638b7f43fe4SPaolo Bonzini     if (!inst && obj) {
639be17f18bSPaolo Bonzini         fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
640be17f18bSPaolo Bonzini                 file, line, func, obj, typename);
6412f28d2ffSAnthony Liguori         abort();
6422f28d2ffSAnthony Liguori     }
6432f28d2ffSAnthony Liguori 
6443556c233SPaolo Bonzini     assert(obj == inst);
64503587328SAnthony Liguori 
64695916abcSPeter Crosthwaite     if (obj && obj == inst) {
64703587328SAnthony Liguori         for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
648b6b3ccfdSAlex Bennée             atomic_set(&obj->class->object_cast_cache[i - 1],
649b6b3ccfdSAlex Bennée                        atomic_read(&obj->class->object_cast_cache[i]));
65003587328SAnthony Liguori         }
651b6b3ccfdSAlex Bennée         atomic_set(&obj->class->object_cast_cache[i - 1], typename);
65203587328SAnthony Liguori     }
65303587328SAnthony Liguori 
65403587328SAnthony Liguori out:
6553556c233SPaolo Bonzini #endif
6563556c233SPaolo Bonzini     return obj;
6572f28d2ffSAnthony Liguori }
6582f28d2ffSAnthony Liguori 
6592f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class,
6602f28d2ffSAnthony Liguori                                        const char *typename)
6612f28d2ffSAnthony Liguori {
66233e95c63SAnthony Liguori     ObjectClass *ret = NULL;
663bf0fda34SPaolo Bonzini     TypeImpl *target_type;
664bf0fda34SPaolo Bonzini     TypeImpl *type;
6652f28d2ffSAnthony Liguori 
666bf0fda34SPaolo Bonzini     if (!class) {
667bf0fda34SPaolo Bonzini         return NULL;
668bf0fda34SPaolo Bonzini     }
669bf0fda34SPaolo Bonzini 
670793c96b5SPaolo Bonzini     /* A simple fast path that can trigger a lot for leaf classes.  */
671bf0fda34SPaolo Bonzini     type = class->type;
672793c96b5SPaolo Bonzini     if (type->name == typename) {
673793c96b5SPaolo Bonzini         return class;
674793c96b5SPaolo Bonzini     }
675793c96b5SPaolo Bonzini 
676bf0fda34SPaolo Bonzini     target_type = type_get_by_name(typename);
6779ab880b3SAlexander Graf     if (!target_type) {
6789ab880b3SAlexander Graf         /* target class type unknown, so fail the cast */
6799ab880b3SAlexander Graf         return NULL;
6809ab880b3SAlexander Graf     }
6819ab880b3SAlexander Graf 
68200e2ceaeSPeter Crosthwaite     if (type->class->interfaces &&
68300e2ceaeSPeter Crosthwaite             type_is_ancestor(target_type, type_interface)) {
68433e95c63SAnthony Liguori         int found = 0;
68533e95c63SAnthony Liguori         GSList *i;
68633e95c63SAnthony Liguori 
68733e95c63SAnthony Liguori         for (i = class->interfaces; i; i = i->next) {
68833e95c63SAnthony Liguori             ObjectClass *target_class = i->data;
68933e95c63SAnthony Liguori 
69033e95c63SAnthony Liguori             if (type_is_ancestor(target_class->type, target_type)) {
69133e95c63SAnthony Liguori                 ret = target_class;
69233e95c63SAnthony Liguori                 found++;
69333e95c63SAnthony Liguori             }
6942f28d2ffSAnthony Liguori          }
6952f28d2ffSAnthony Liguori 
69633e95c63SAnthony Liguori         /* The match was ambiguous, don't allow a cast */
69733e95c63SAnthony Liguori         if (found > 1) {
69833e95c63SAnthony Liguori             ret = NULL;
69933e95c63SAnthony Liguori         }
70033e95c63SAnthony Liguori     } else if (type_is_ancestor(type, target_type)) {
70133e95c63SAnthony Liguori         ret = class;
7022f28d2ffSAnthony Liguori     }
7032f28d2ffSAnthony Liguori 
70433e95c63SAnthony Liguori     return ret;
7052f28d2ffSAnthony Liguori }
7062f28d2ffSAnthony Liguori 
7072f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
708be17f18bSPaolo Bonzini                                               const char *typename,
709be17f18bSPaolo Bonzini                                               const char *file, int line,
710be17f18bSPaolo Bonzini                                               const char *func)
7112f28d2ffSAnthony Liguori {
712fa131d94SPaolo Bonzini     ObjectClass *ret;
7132f28d2ffSAnthony Liguori 
714fa131d94SPaolo Bonzini     trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)",
715fa131d94SPaolo Bonzini                                            typename, file, line, func);
716fa131d94SPaolo Bonzini 
71703587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG
71803587328SAnthony Liguori     int i;
71903587328SAnthony Liguori 
7209d6a3d58SPeter Crosthwaite     for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) {
721b6b3ccfdSAlex Bennée         if (atomic_read(&class->class_cast_cache[i]) == typename) {
72203587328SAnthony Liguori             ret = class;
72303587328SAnthony Liguori             goto out;
72403587328SAnthony Liguori         }
72503587328SAnthony Liguori     }
72603587328SAnthony Liguori #else
7279d6a3d58SPeter Crosthwaite     if (!class || !class->interfaces) {
7283556c233SPaolo Bonzini         return class;
7293556c233SPaolo Bonzini     }
7303556c233SPaolo Bonzini #endif
7313556c233SPaolo Bonzini 
732fa131d94SPaolo Bonzini     ret = object_class_dynamic_cast(class, typename);
733bf0fda34SPaolo Bonzini     if (!ret && class) {
734be17f18bSPaolo Bonzini         fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n",
735be17f18bSPaolo Bonzini                 file, line, func, class, typename);
7362f28d2ffSAnthony Liguori         abort();
7372f28d2ffSAnthony Liguori     }
7382f28d2ffSAnthony Liguori 
73903587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG
7409d6a3d58SPeter Crosthwaite     if (class && ret == class) {
74103587328SAnthony Liguori         for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
742b6b3ccfdSAlex Bennée             atomic_set(&class->class_cast_cache[i - 1],
743b6b3ccfdSAlex Bennée                        atomic_read(&class->class_cast_cache[i]));
74403587328SAnthony Liguori         }
745b6b3ccfdSAlex Bennée         atomic_set(&class->class_cast_cache[i - 1], typename);
74603587328SAnthony Liguori     }
74703587328SAnthony Liguori out:
74803587328SAnthony Liguori #endif
7492f28d2ffSAnthony Liguori     return ret;
7502f28d2ffSAnthony Liguori }
7512f28d2ffSAnthony Liguori 
7528f5d58efSIgor Mammedov const char *object_get_typename(const Object *obj)
7532f28d2ffSAnthony Liguori {
7542f28d2ffSAnthony Liguori     return obj->class->type->name;
7552f28d2ffSAnthony Liguori }
7562f28d2ffSAnthony Liguori 
7572f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj)
7582f28d2ffSAnthony Liguori {
7592f28d2ffSAnthony Liguori     return obj->class;
7602f28d2ffSAnthony Liguori }
7612f28d2ffSAnthony Liguori 
76217862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass)
76317862378SAndreas Färber {
76417862378SAndreas Färber     return klass->type->abstract;
76517862378SAndreas Färber }
76617862378SAndreas Färber 
7672f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass)
7682f28d2ffSAnthony Liguori {
7692f28d2ffSAnthony Liguori     return klass->type->name;
7702f28d2ffSAnthony Liguori }
7712f28d2ffSAnthony Liguori 
7722f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename)
7732f28d2ffSAnthony Liguori {
7742f28d2ffSAnthony Liguori     TypeImpl *type = type_get_by_name(typename);
7752f28d2ffSAnthony Liguori 
7762f28d2ffSAnthony Liguori     if (!type) {
7772f28d2ffSAnthony Liguori         return NULL;
7782f28d2ffSAnthony Liguori     }
7792f28d2ffSAnthony Liguori 
780ac451033SIgor Mitsyanko     type_initialize(type);
7812f28d2ffSAnthony Liguori 
7822f28d2ffSAnthony Liguori     return type->class;
7832f28d2ffSAnthony Liguori }
7842f28d2ffSAnthony Liguori 
785e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class)
786e7cce67fSPaolo Bonzini {
787e7cce67fSPaolo Bonzini     TypeImpl *type = type_get_parent(class->type);
788e7cce67fSPaolo Bonzini 
789e7cce67fSPaolo Bonzini     if (!type) {
790e7cce67fSPaolo Bonzini         return NULL;
791e7cce67fSPaolo Bonzini     }
792e7cce67fSPaolo Bonzini 
793e7cce67fSPaolo Bonzini     type_initialize(type);
794e7cce67fSPaolo Bonzini 
795e7cce67fSPaolo Bonzini     return type->class;
796e7cce67fSPaolo Bonzini }
797e7cce67fSPaolo Bonzini 
7982f28d2ffSAnthony Liguori typedef struct OCFData
7992f28d2ffSAnthony Liguori {
8002f28d2ffSAnthony Liguori     void (*fn)(ObjectClass *klass, void *opaque);
80193c511a1SAnthony Liguori     const char *implements_type;
80293c511a1SAnthony Liguori     bool include_abstract;
8032f28d2ffSAnthony Liguori     void *opaque;
8042f28d2ffSAnthony Liguori } OCFData;
8052f28d2ffSAnthony Liguori 
8062f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value,
8072f28d2ffSAnthony Liguori                                        gpointer opaque)
8082f28d2ffSAnthony Liguori {
8092f28d2ffSAnthony Liguori     OCFData *data = opaque;
8102f28d2ffSAnthony Liguori     TypeImpl *type = value;
81193c511a1SAnthony Liguori     ObjectClass *k;
8122f28d2ffSAnthony Liguori 
813ac451033SIgor Mitsyanko     type_initialize(type);
81493c511a1SAnthony Liguori     k = type->class;
8152f28d2ffSAnthony Liguori 
81693c511a1SAnthony Liguori     if (!data->include_abstract && type->abstract) {
81793c511a1SAnthony Liguori         return;
81893c511a1SAnthony Liguori     }
81993c511a1SAnthony Liguori 
82093c511a1SAnthony Liguori     if (data->implements_type &&
82193c511a1SAnthony Liguori         !object_class_dynamic_cast(k, data->implements_type)) {
82293c511a1SAnthony Liguori         return;
82393c511a1SAnthony Liguori     }
82493c511a1SAnthony Liguori 
82593c511a1SAnthony Liguori     data->fn(k, data->opaque);
8262f28d2ffSAnthony Liguori }
8272f28d2ffSAnthony Liguori 
8282f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
82993c511a1SAnthony Liguori                           const char *implements_type, bool include_abstract,
8302f28d2ffSAnthony Liguori                           void *opaque)
8312f28d2ffSAnthony Liguori {
83293c511a1SAnthony Liguori     OCFData data = { fn, implements_type, include_abstract, opaque };
8332f28d2ffSAnthony Liguori 
834f54c19caSHervé Poussineau     enumerating_types = true;
8352f28d2ffSAnthony Liguori     g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
836f54c19caSHervé Poussineau     enumerating_types = false;
8372f28d2ffSAnthony Liguori }
83857c9fafeSAnthony Liguori 
839d714b8deSPeter Crosthwaite static int do_object_child_foreach(Object *obj,
840d714b8deSPeter Crosthwaite                                    int (*fn)(Object *child, void *opaque),
841d714b8deSPeter Crosthwaite                                    void *opaque, bool recurse)
84232efc535SPaolo Bonzini {
843b604a854SPavel Fedin     GHashTableIter iter;
844b604a854SPavel Fedin     ObjectProperty *prop;
84532efc535SPaolo Bonzini     int ret = 0;
84632efc535SPaolo Bonzini 
847b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->properties);
848b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) {
84932efc535SPaolo Bonzini         if (object_property_is_child(prop)) {
850d714b8deSPeter Crosthwaite             Object *child = prop->opaque;
851d714b8deSPeter Crosthwaite 
852d714b8deSPeter Crosthwaite             ret = fn(child, opaque);
85332efc535SPaolo Bonzini             if (ret != 0) {
85432efc535SPaolo Bonzini                 break;
85532efc535SPaolo Bonzini             }
856d714b8deSPeter Crosthwaite             if (recurse) {
857d714b8deSPeter Crosthwaite                 do_object_child_foreach(child, fn, opaque, true);
858d714b8deSPeter Crosthwaite             }
85932efc535SPaolo Bonzini         }
86032efc535SPaolo Bonzini     }
86132efc535SPaolo Bonzini     return ret;
86232efc535SPaolo Bonzini }
86332efc535SPaolo Bonzini 
864d714b8deSPeter Crosthwaite int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque),
865d714b8deSPeter Crosthwaite                          void *opaque)
866d714b8deSPeter Crosthwaite {
867d714b8deSPeter Crosthwaite     return do_object_child_foreach(obj, fn, opaque, false);
868d714b8deSPeter Crosthwaite }
869d714b8deSPeter Crosthwaite 
870d714b8deSPeter Crosthwaite int object_child_foreach_recursive(Object *obj,
871d714b8deSPeter Crosthwaite                                    int (*fn)(Object *child, void *opaque),
872d714b8deSPeter Crosthwaite                                    void *opaque)
873d714b8deSPeter Crosthwaite {
874d714b8deSPeter Crosthwaite     return do_object_child_foreach(obj, fn, opaque, true);
875d714b8deSPeter Crosthwaite }
876d714b8deSPeter Crosthwaite 
877418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque)
878418ba9e5SAndreas Färber {
879418ba9e5SAndreas Färber     GSList **list = opaque;
880418ba9e5SAndreas Färber 
881418ba9e5SAndreas Färber     *list = g_slist_prepend(*list, klass);
882418ba9e5SAndreas Färber }
883418ba9e5SAndreas Färber 
884418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type,
885418ba9e5SAndreas Färber                               bool include_abstract)
886418ba9e5SAndreas Färber {
887418ba9e5SAndreas Färber     GSList *list = NULL;
888418ba9e5SAndreas Färber 
889418ba9e5SAndreas Färber     object_class_foreach(object_class_get_list_tramp,
890418ba9e5SAndreas Färber                          implements_type, include_abstract, &list);
891418ba9e5SAndreas Färber     return list;
892418ba9e5SAndreas Färber }
893418ba9e5SAndreas Färber 
89447c66009SPaolo Bonzini static gint object_class_cmp(gconstpointer a, gconstpointer b)
89547c66009SPaolo Bonzini {
89647c66009SPaolo Bonzini     return strcasecmp(object_class_get_name((ObjectClass *)a),
89747c66009SPaolo Bonzini                       object_class_get_name((ObjectClass *)b));
89847c66009SPaolo Bonzini }
89947c66009SPaolo Bonzini 
90047c66009SPaolo Bonzini GSList *object_class_get_list_sorted(const char *implements_type,
90147c66009SPaolo Bonzini                                      bool include_abstract)
90247c66009SPaolo Bonzini {
90347c66009SPaolo Bonzini     return g_slist_sort(object_class_get_list(implements_type, include_abstract),
90447c66009SPaolo Bonzini                         object_class_cmp);
90547c66009SPaolo Bonzini }
90647c66009SPaolo Bonzini 
90757c9fafeSAnthony Liguori void object_ref(Object *obj)
90857c9fafeSAnthony Liguori {
9098ffad850SPeter Crosthwaite     if (!obj) {
9108ffad850SPeter Crosthwaite         return;
9118ffad850SPeter Crosthwaite     }
912f08c03f3SJan Kiszka     atomic_inc(&obj->ref);
91357c9fafeSAnthony Liguori }
91457c9fafeSAnthony Liguori 
91557c9fafeSAnthony Liguori void object_unref(Object *obj)
91657c9fafeSAnthony Liguori {
9178ffad850SPeter Crosthwaite     if (!obj) {
9188ffad850SPeter Crosthwaite         return;
9198ffad850SPeter Crosthwaite     }
9208438a135SAndreas Färber     g_assert_cmpint(obj->ref, >, 0);
92157c9fafeSAnthony Liguori 
92257c9fafeSAnthony Liguori     /* parent always holds a reference to its children */
923f08c03f3SJan Kiszka     if (atomic_fetch_dec(&obj->ref) == 1) {
92457c9fafeSAnthony Liguori         object_finalize(obj);
92557c9fafeSAnthony Liguori     }
92657c9fafeSAnthony Liguori }
92757c9fafeSAnthony Liguori 
92864607d08SPaolo Bonzini ObjectProperty *
92964607d08SPaolo Bonzini object_property_add(Object *obj, const char *name, const char *type,
93057c9fafeSAnthony Liguori                     ObjectPropertyAccessor *get,
93157c9fafeSAnthony Liguori                     ObjectPropertyAccessor *set,
93257c9fafeSAnthony Liguori                     ObjectPropertyRelease *release,
93357c9fafeSAnthony Liguori                     void *opaque, Error **errp)
93457c9fafeSAnthony Liguori {
93554852b03SPeter Maydell     ObjectProperty *prop;
93633965904SPeter Crosthwaite     size_t name_len = strlen(name);
93733965904SPeter Crosthwaite 
93833965904SPeter Crosthwaite     if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) {
93933965904SPeter Crosthwaite         int i;
94033965904SPeter Crosthwaite         ObjectProperty *ret;
94133965904SPeter Crosthwaite         char *name_no_array = g_strdup(name);
94233965904SPeter Crosthwaite 
94333965904SPeter Crosthwaite         name_no_array[name_len - 3] = '\0';
94433965904SPeter Crosthwaite         for (i = 0; ; ++i) {
94533965904SPeter Crosthwaite             char *full_name = g_strdup_printf("%s[%d]", name_no_array, i);
94633965904SPeter Crosthwaite 
94733965904SPeter Crosthwaite             ret = object_property_add(obj, full_name, type, get, set,
94833965904SPeter Crosthwaite                                       release, opaque, NULL);
94933965904SPeter Crosthwaite             g_free(full_name);
95033965904SPeter Crosthwaite             if (ret) {
95133965904SPeter Crosthwaite                 break;
95233965904SPeter Crosthwaite             }
95333965904SPeter Crosthwaite         }
95433965904SPeter Crosthwaite         g_free(name_no_array);
95533965904SPeter Crosthwaite         return ret;
95633965904SPeter Crosthwaite     }
95754852b03SPeter Maydell 
95816bf7f52SDaniel P. Berrange     if (object_property_find(obj, name, NULL) != NULL) {
95954852b03SPeter Maydell         error_setg(errp, "attempt to add duplicate property '%s'"
96054852b03SPeter Maydell                    " to object (type '%s')", name,
96154852b03SPeter Maydell                    object_get_typename(obj));
96264607d08SPaolo Bonzini         return NULL;
96354852b03SPeter Maydell     }
96454852b03SPeter Maydell 
96554852b03SPeter Maydell     prop = g_malloc0(sizeof(*prop));
96657c9fafeSAnthony Liguori 
96757c9fafeSAnthony Liguori     prop->name = g_strdup(name);
96857c9fafeSAnthony Liguori     prop->type = g_strdup(type);
96957c9fafeSAnthony Liguori 
97057c9fafeSAnthony Liguori     prop->get = get;
97157c9fafeSAnthony Liguori     prop->set = set;
97257c9fafeSAnthony Liguori     prop->release = release;
97357c9fafeSAnthony Liguori     prop->opaque = opaque;
97457c9fafeSAnthony Liguori 
975b604a854SPavel Fedin     g_hash_table_insert(obj->properties, prop->name, prop);
97664607d08SPaolo Bonzini     return prop;
97757c9fafeSAnthony Liguori }
97857c9fafeSAnthony Liguori 
97916bf7f52SDaniel P. Berrange ObjectProperty *
98016bf7f52SDaniel P. Berrange object_class_property_add(ObjectClass *klass,
98116bf7f52SDaniel P. Berrange                           const char *name,
98216bf7f52SDaniel P. Berrange                           const char *type,
98316bf7f52SDaniel P. Berrange                           ObjectPropertyAccessor *get,
98416bf7f52SDaniel P. Berrange                           ObjectPropertyAccessor *set,
98516bf7f52SDaniel P. Berrange                           ObjectPropertyRelease *release,
98616bf7f52SDaniel P. Berrange                           void *opaque,
98716bf7f52SDaniel P. Berrange                           Error **errp)
98816bf7f52SDaniel P. Berrange {
98916bf7f52SDaniel P. Berrange     ObjectProperty *prop;
99016bf7f52SDaniel P. Berrange 
99116bf7f52SDaniel P. Berrange     if (object_class_property_find(klass, name, NULL) != NULL) {
99216bf7f52SDaniel P. Berrange         error_setg(errp, "attempt to add duplicate property '%s'"
99316bf7f52SDaniel P. Berrange                    " to object (type '%s')", name,
99416bf7f52SDaniel P. Berrange                    object_class_get_name(klass));
99516bf7f52SDaniel P. Berrange         return NULL;
99616bf7f52SDaniel P. Berrange     }
99716bf7f52SDaniel P. Berrange 
99816bf7f52SDaniel P. Berrange     prop = g_malloc0(sizeof(*prop));
99916bf7f52SDaniel P. Berrange 
100016bf7f52SDaniel P. Berrange     prop->name = g_strdup(name);
100116bf7f52SDaniel P. Berrange     prop->type = g_strdup(type);
100216bf7f52SDaniel P. Berrange 
100316bf7f52SDaniel P. Berrange     prop->get = get;
100416bf7f52SDaniel P. Berrange     prop->set = set;
100516bf7f52SDaniel P. Berrange     prop->release = release;
100616bf7f52SDaniel P. Berrange     prop->opaque = opaque;
100716bf7f52SDaniel P. Berrange 
100816bf7f52SDaniel P. Berrange     g_hash_table_insert(klass->properties, g_strdup(name), prop);
100916bf7f52SDaniel P. Berrange 
101016bf7f52SDaniel P. Berrange     return prop;
101116bf7f52SDaniel P. Berrange }
101216bf7f52SDaniel P. Berrange 
101389bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name,
101489bfe000SPaolo Bonzini                                      Error **errp)
101557c9fafeSAnthony Liguori {
101657c9fafeSAnthony Liguori     ObjectProperty *prop;
101716bf7f52SDaniel P. Berrange     ObjectClass *klass = object_get_class(obj);
101816bf7f52SDaniel P. Berrange 
101916bf7f52SDaniel P. Berrange     prop = object_class_property_find(klass, name, NULL);
102016bf7f52SDaniel P. Berrange     if (prop) {
102116bf7f52SDaniel P. Berrange         return prop;
102216bf7f52SDaniel P. Berrange     }
102357c9fafeSAnthony Liguori 
1024b604a854SPavel Fedin     prop = g_hash_table_lookup(obj->properties, name);
1025b604a854SPavel Fedin     if (prop) {
102657c9fafeSAnthony Liguori         return prop;
102757c9fafeSAnthony Liguori     }
102857c9fafeSAnthony Liguori 
1029f231b88dSCole Robinson     error_setg(errp, "Property '.%s' not found", name);
103057c9fafeSAnthony Liguori     return NULL;
103157c9fafeSAnthony Liguori }
103257c9fafeSAnthony Liguori 
10337746abd8SDaniel P. Berrange void object_property_iter_init(ObjectPropertyIterator *iter,
10347746abd8SDaniel P. Berrange                                Object *obj)
1035a00c9482SDaniel P. Berrange {
10367746abd8SDaniel P. Berrange     g_hash_table_iter_init(&iter->iter, obj->properties);
10377746abd8SDaniel P. Berrange     iter->nextclass = object_get_class(obj);
1038a00c9482SDaniel P. Berrange }
1039a00c9482SDaniel P. Berrange 
1040a00c9482SDaniel P. Berrange ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter)
1041a00c9482SDaniel P. Berrange {
1042b604a854SPavel Fedin     gpointer key, val;
104316bf7f52SDaniel P. Berrange     while (!g_hash_table_iter_next(&iter->iter, &key, &val)) {
104416bf7f52SDaniel P. Berrange         if (!iter->nextclass) {
1045b604a854SPavel Fedin             return NULL;
1046a00c9482SDaniel P. Berrange         }
104716bf7f52SDaniel P. Berrange         g_hash_table_iter_init(&iter->iter, iter->nextclass->properties);
104816bf7f52SDaniel P. Berrange         iter->nextclass = object_class_get_parent(iter->nextclass);
104916bf7f52SDaniel P. Berrange     }
1050b604a854SPavel Fedin     return val;
1051a00c9482SDaniel P. Berrange }
1052a00c9482SDaniel P. Berrange 
1053961c47bbSAlexey Kardashevskiy void object_class_property_iter_init(ObjectPropertyIterator *iter,
1054961c47bbSAlexey Kardashevskiy                                      ObjectClass *klass)
1055961c47bbSAlexey Kardashevskiy {
1056961c47bbSAlexey Kardashevskiy     g_hash_table_iter_init(&iter->iter, klass->properties);
1057961c47bbSAlexey Kardashevskiy     iter->nextclass = klass;
1058961c47bbSAlexey Kardashevskiy }
1059961c47bbSAlexey Kardashevskiy 
106016bf7f52SDaniel P. Berrange ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
106116bf7f52SDaniel P. Berrange                                            Error **errp)
106216bf7f52SDaniel P. Berrange {
106316bf7f52SDaniel P. Berrange     ObjectProperty *prop;
106416bf7f52SDaniel P. Berrange     ObjectClass *parent_klass;
106516bf7f52SDaniel P. Berrange 
106616bf7f52SDaniel P. Berrange     parent_klass = object_class_get_parent(klass);
106716bf7f52SDaniel P. Berrange     if (parent_klass) {
106816bf7f52SDaniel P. Berrange         prop = object_class_property_find(parent_klass, name, NULL);
106916bf7f52SDaniel P. Berrange         if (prop) {
107016bf7f52SDaniel P. Berrange             return prop;
107116bf7f52SDaniel P. Berrange         }
107216bf7f52SDaniel P. Berrange     }
107316bf7f52SDaniel P. Berrange 
107416bf7f52SDaniel P. Berrange     prop = g_hash_table_lookup(klass->properties, name);
107516bf7f52SDaniel P. Berrange     if (!prop) {
107616bf7f52SDaniel P. Berrange         error_setg(errp, "Property '.%s' not found", name);
107716bf7f52SDaniel P. Berrange     }
107816bf7f52SDaniel P. Berrange     return prop;
107916bf7f52SDaniel P. Berrange }
108016bf7f52SDaniel P. Berrange 
108157c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp)
108257c9fafeSAnthony Liguori {
1083b604a854SPavel Fedin     ObjectProperty *prop = g_hash_table_lookup(obj->properties, name);
1084b604a854SPavel Fedin 
1085b604a854SPavel Fedin     if (!prop) {
1086b604a854SPavel Fedin         error_setg(errp, "Property '.%s' not found", name);
10870866aca1SAnthony Liguori         return;
10880866aca1SAnthony Liguori     }
108957c9fafeSAnthony Liguori 
10900866aca1SAnthony Liguori     if (prop->release) {
10910866aca1SAnthony Liguori         prop->release(obj, name, prop->opaque);
10920866aca1SAnthony Liguori     }
1093b604a854SPavel Fedin     g_hash_table_remove(obj->properties, name);
109457c9fafeSAnthony Liguori }
109557c9fafeSAnthony Liguori 
109657c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name,
109757c9fafeSAnthony Liguori                          Error **errp)
109857c9fafeSAnthony Liguori {
109989bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(obj, name, errp);
110057c9fafeSAnthony Liguori     if (prop == NULL) {
110157c9fafeSAnthony Liguori         return;
110257c9fafeSAnthony Liguori     }
110357c9fafeSAnthony Liguori 
110457c9fafeSAnthony Liguori     if (!prop->get) {
1105c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_PERMISSION_DENIED);
110657c9fafeSAnthony Liguori     } else {
1107d7bce999SEric Blake         prop->get(obj, v, name, prop->opaque, errp);
110857c9fafeSAnthony Liguori     }
110957c9fafeSAnthony Liguori }
111057c9fafeSAnthony Liguori 
111157c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name,
111257c9fafeSAnthony Liguori                          Error **errp)
111357c9fafeSAnthony Liguori {
111489bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(obj, name, errp);
111557c9fafeSAnthony Liguori     if (prop == NULL) {
111657c9fafeSAnthony Liguori         return;
111757c9fafeSAnthony Liguori     }
111857c9fafeSAnthony Liguori 
111957c9fafeSAnthony Liguori     if (!prop->set) {
1120c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_PERMISSION_DENIED);
112157c9fafeSAnthony Liguori     } else {
1122d7bce999SEric Blake         prop->set(obj, v, name, prop->opaque, errp);
112357c9fafeSAnthony Liguori     }
112457c9fafeSAnthony Liguori }
112557c9fafeSAnthony Liguori 
11267b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value,
11277b7b7d18SPaolo Bonzini                              const char *name, Error **errp)
11287b7b7d18SPaolo Bonzini {
11297b7b7d18SPaolo Bonzini     QString *qstr = qstring_from_str(value);
11307b7b7d18SPaolo Bonzini     object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
11317b7b7d18SPaolo Bonzini 
11327b7b7d18SPaolo Bonzini     QDECREF(qstr);
11337b7b7d18SPaolo Bonzini }
11347b7b7d18SPaolo Bonzini 
11357b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name,
11367b7b7d18SPaolo Bonzini                               Error **errp)
11377b7b7d18SPaolo Bonzini {
11387b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
11397b7b7d18SPaolo Bonzini     char *retval;
11407b7b7d18SPaolo Bonzini 
11417b7b7d18SPaolo Bonzini     if (!ret) {
11427b7b7d18SPaolo Bonzini         return NULL;
11437b7b7d18SPaolo Bonzini     }
1144*aafb21a0SPeter Xu 
1145*aafb21a0SPeter Xu     retval = g_strdup(qobject_get_try_str(ret));
1146*aafb21a0SPeter Xu     if (!retval) {
1147c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
11487b7b7d18SPaolo Bonzini     }
11497b7b7d18SPaolo Bonzini 
1150560f19f1SMarc-André Lureau     qobject_decref(ret);
11517b7b7d18SPaolo Bonzini     return retval;
11527b7b7d18SPaolo Bonzini }
11537b7b7d18SPaolo Bonzini 
11541d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value,
11551d9c5a12SPaolo Bonzini                               const char *name, Error **errp)
11561d9c5a12SPaolo Bonzini {
1157d3c49316SPeter Crosthwaite     if (value) {
11582d3aa28cSVlad Yasevich         gchar *path = object_get_canonical_path(value);
11592d3aa28cSVlad Yasevich         object_property_set_str(obj, path, name, errp);
11602d3aa28cSVlad Yasevich         g_free(path);
1161d3c49316SPeter Crosthwaite     } else {
1162d3c49316SPeter Crosthwaite         object_property_set_str(obj, "", name, errp);
1163d3c49316SPeter Crosthwaite     }
11641d9c5a12SPaolo Bonzini }
11651d9c5a12SPaolo Bonzini 
11661d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name,
11671d9c5a12SPaolo Bonzini                                  Error **errp)
11681d9c5a12SPaolo Bonzini {
11691d9c5a12SPaolo Bonzini     char *str = object_property_get_str(obj, name, errp);
11701d9c5a12SPaolo Bonzini     Object *target = NULL;
11711d9c5a12SPaolo Bonzini 
11721d9c5a12SPaolo Bonzini     if (str && *str) {
11731d9c5a12SPaolo Bonzini         target = object_resolve_path(str, NULL);
11741d9c5a12SPaolo Bonzini         if (!target) {
117575158ebbSMarkus Armbruster             error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
117675158ebbSMarkus Armbruster                       "Device '%s' not found", str);
11771d9c5a12SPaolo Bonzini         }
11781d9c5a12SPaolo Bonzini     }
11791d9c5a12SPaolo Bonzini 
11801d9c5a12SPaolo Bonzini     g_free(str);
11811d9c5a12SPaolo Bonzini     return target;
11821d9c5a12SPaolo Bonzini }
11831d9c5a12SPaolo Bonzini 
11847b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value,
11857b7b7d18SPaolo Bonzini                               const char *name, Error **errp)
11867b7b7d18SPaolo Bonzini {
1187fc48ffc3SEric Blake     QBool *qbool = qbool_from_bool(value);
11887b7b7d18SPaolo Bonzini     object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
11897b7b7d18SPaolo Bonzini 
11907b7b7d18SPaolo Bonzini     QDECREF(qbool);
11917b7b7d18SPaolo Bonzini }
11927b7b7d18SPaolo Bonzini 
11937b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name,
11947b7b7d18SPaolo Bonzini                               Error **errp)
11957b7b7d18SPaolo Bonzini {
11967b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
11977b7b7d18SPaolo Bonzini     QBool *qbool;
11987b7b7d18SPaolo Bonzini     bool retval;
11997b7b7d18SPaolo Bonzini 
12007b7b7d18SPaolo Bonzini     if (!ret) {
12017b7b7d18SPaolo Bonzini         return false;
12027b7b7d18SPaolo Bonzini     }
12037dc847ebSMax Reitz     qbool = qobject_to(QBool, ret);
12047b7b7d18SPaolo Bonzini     if (!qbool) {
1205c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
12067b7b7d18SPaolo Bonzini         retval = false;
12077b7b7d18SPaolo Bonzini     } else {
1208fc48ffc3SEric Blake         retval = qbool_get_bool(qbool);
12097b7b7d18SPaolo Bonzini     }
12107b7b7d18SPaolo Bonzini 
1211560f19f1SMarc-André Lureau     qobject_decref(ret);
12127b7b7d18SPaolo Bonzini     return retval;
12137b7b7d18SPaolo Bonzini }
12147b7b7d18SPaolo Bonzini 
12157b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value,
12167b7b7d18SPaolo Bonzini                              const char *name, Error **errp)
12177b7b7d18SPaolo Bonzini {
121801b2ffceSMarc-André Lureau     QNum *qnum = qnum_from_int(value);
121901b2ffceSMarc-André Lureau     object_property_set_qobject(obj, QOBJECT(qnum), name, errp);
12207b7b7d18SPaolo Bonzini 
122101b2ffceSMarc-André Lureau     QDECREF(qnum);
12227b7b7d18SPaolo Bonzini }
12237b7b7d18SPaolo Bonzini 
12247b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name,
12257b7b7d18SPaolo Bonzini                                 Error **errp)
12267b7b7d18SPaolo Bonzini {
12277b7b7d18SPaolo Bonzini     QObject *ret = object_property_get_qobject(obj, name, errp);
122801b2ffceSMarc-André Lureau     QNum *qnum;
12297b7b7d18SPaolo Bonzini     int64_t retval;
12307b7b7d18SPaolo Bonzini 
12317b7b7d18SPaolo Bonzini     if (!ret) {
12327b7b7d18SPaolo Bonzini         return -1;
12337b7b7d18SPaolo Bonzini     }
123401b2ffceSMarc-André Lureau 
12357dc847ebSMax Reitz     qnum = qobject_to(QNum, ret);
123601b2ffceSMarc-André Lureau     if (!qnum || !qnum_get_try_int(qnum, &retval)) {
1237c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
12387b7b7d18SPaolo Bonzini         retval = -1;
12397b7b7d18SPaolo Bonzini     }
12407b7b7d18SPaolo Bonzini 
1241560f19f1SMarc-André Lureau     qobject_decref(ret);
12427b7b7d18SPaolo Bonzini     return retval;
12437b7b7d18SPaolo Bonzini }
12447b7b7d18SPaolo Bonzini 
12453152779cSMarc-André Lureau void object_property_set_uint(Object *obj, uint64_t value,
12463152779cSMarc-André Lureau                               const char *name, Error **errp)
12473152779cSMarc-André Lureau {
12483152779cSMarc-André Lureau     QNum *qnum = qnum_from_uint(value);
12493152779cSMarc-André Lureau 
12503152779cSMarc-André Lureau     object_property_set_qobject(obj, QOBJECT(qnum), name, errp);
12513152779cSMarc-André Lureau     QDECREF(qnum);
12523152779cSMarc-André Lureau }
12533152779cSMarc-André Lureau 
12543152779cSMarc-André Lureau uint64_t object_property_get_uint(Object *obj, const char *name,
12553152779cSMarc-André Lureau                                   Error **errp)
12563152779cSMarc-André Lureau {
12573152779cSMarc-André Lureau     QObject *ret = object_property_get_qobject(obj, name, errp);
12583152779cSMarc-André Lureau     QNum *qnum;
12593152779cSMarc-André Lureau     uint64_t retval;
12603152779cSMarc-André Lureau 
12613152779cSMarc-André Lureau     if (!ret) {
12623152779cSMarc-André Lureau         return 0;
12633152779cSMarc-André Lureau     }
12647dc847ebSMax Reitz     qnum = qobject_to(QNum, ret);
12653152779cSMarc-André Lureau     if (!qnum || !qnum_get_try_uint(qnum, &retval)) {
12663152779cSMarc-André Lureau         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "uint");
12673152779cSMarc-André Lureau         retval = 0;
12683152779cSMarc-André Lureau     }
12693152779cSMarc-André Lureau 
12703152779cSMarc-André Lureau     qobject_decref(ret);
12713152779cSMarc-André Lureau     return retval;
12723152779cSMarc-André Lureau }
12733152779cSMarc-André Lureau 
1274a8e3fbedSDaniel P. Berrange typedef struct EnumProperty {
1275f7abe0ecSMarc-André Lureau     const QEnumLookup *lookup;
1276a8e3fbedSDaniel P. Berrange     int (*get)(Object *, Error **);
1277a8e3fbedSDaniel P. Berrange     void (*set)(Object *, int, Error **);
1278a8e3fbedSDaniel P. Berrange } EnumProperty;
1279a8e3fbedSDaniel P. Berrange 
12801f21772dSHu Tao int object_property_get_enum(Object *obj, const char *name,
1281a3590dacSDaniel P. Berrange                              const char *typename, Error **errp)
12821f21772dSHu Tao {
12834715d42eSMarkus Armbruster     Error *err = NULL;
12847a0525c7SEric Blake     Visitor *v;
1285976620acSChen Fan     char *str;
12861f21772dSHu Tao     int ret;
1287a3590dacSDaniel P. Berrange     ObjectProperty *prop = object_property_find(obj, name, errp);
1288a3590dacSDaniel P. Berrange     EnumProperty *enumprop;
1289a3590dacSDaniel P. Berrange 
1290a3590dacSDaniel P. Berrange     if (prop == NULL) {
1291a3590dacSDaniel P. Berrange         return 0;
1292a3590dacSDaniel P. Berrange     }
1293a3590dacSDaniel P. Berrange 
1294a3590dacSDaniel P. Berrange     if (!g_str_equal(prop->type, typename)) {
1295a3590dacSDaniel P. Berrange         error_setg(errp, "Property %s on %s is not '%s' enum type",
1296a3590dacSDaniel P. Berrange                    name, object_class_get_name(
1297a3590dacSDaniel P. Berrange                        object_get_class(obj)), typename);
1298a3590dacSDaniel P. Berrange         return 0;
1299a3590dacSDaniel P. Berrange     }
1300a3590dacSDaniel P. Berrange 
1301a3590dacSDaniel P. Berrange     enumprop = prop->opaque;
13021f21772dSHu Tao 
13033b098d56SEric Blake     v = string_output_visitor_new(false, &str);
1304e7ca5656SEric Blake     object_property_get(obj, v, name, &err);
13054715d42eSMarkus Armbruster     if (err) {
13064715d42eSMarkus Armbruster         error_propagate(errp, err);
1307e7ca5656SEric Blake         visit_free(v);
13084715d42eSMarkus Armbruster         return 0;
13094715d42eSMarkus Armbruster     }
13103b098d56SEric Blake     visit_complete(v, &str);
1311e7ca5656SEric Blake     visit_free(v);
13127a0525c7SEric Blake     v = string_input_visitor_new(str);
1313f7abe0ecSMarc-André Lureau     visit_type_enum(v, name, &ret, enumprop->lookup, errp);
1314976620acSChen Fan 
1315976620acSChen Fan     g_free(str);
13167a0525c7SEric Blake     visit_free(v);
13171f21772dSHu Tao 
13181f21772dSHu Tao     return ret;
13191f21772dSHu Tao }
13201f21772dSHu Tao 
13211f21772dSHu Tao void object_property_get_uint16List(Object *obj, const char *name,
13221f21772dSHu Tao                                     uint16List **list, Error **errp)
13231f21772dSHu Tao {
13244715d42eSMarkus Armbruster     Error *err = NULL;
13257a0525c7SEric Blake     Visitor *v;
1326976620acSChen Fan     char *str;
13271f21772dSHu Tao 
13283b098d56SEric Blake     v = string_output_visitor_new(false, &str);
13293b098d56SEric Blake     object_property_get(obj, v, name, &err);
13304715d42eSMarkus Armbruster     if (err) {
13314715d42eSMarkus Armbruster         error_propagate(errp, err);
13324715d42eSMarkus Armbruster         goto out;
13334715d42eSMarkus Armbruster     }
13343b098d56SEric Blake     visit_complete(v, &str);
13353b098d56SEric Blake     visit_free(v);
13367a0525c7SEric Blake     v = string_input_visitor_new(str);
13377a0525c7SEric Blake     visit_type_uint16List(v, NULL, list, errp);
1338976620acSChen Fan 
1339976620acSChen Fan     g_free(str);
13404715d42eSMarkus Armbruster out:
13413b098d56SEric Blake     visit_free(v);
13421f21772dSHu Tao }
13431f21772dSHu Tao 
1344b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string,
1345b2cd7deeSPaolo Bonzini                            const char *name, Error **errp)
1346b2cd7deeSPaolo Bonzini {
13477a0525c7SEric Blake     Visitor *v = string_input_visitor_new(string);
13487a0525c7SEric Blake     object_property_set(obj, v, name, errp);
13497a0525c7SEric Blake     visit_free(v);
1350b2cd7deeSPaolo Bonzini }
1351b2cd7deeSPaolo Bonzini 
13520b7593e0SPaolo Bonzini char *object_property_print(Object *obj, const char *name, bool human,
1353b2cd7deeSPaolo Bonzini                             Error **errp)
1354b2cd7deeSPaolo Bonzini {
13553b098d56SEric Blake     Visitor *v;
13563a53009fSGonglei     char *string = NULL;
13573a53009fSGonglei     Error *local_err = NULL;
1358b2cd7deeSPaolo Bonzini 
13593b098d56SEric Blake     v = string_output_visitor_new(human, &string);
13603b098d56SEric Blake     object_property_get(obj, v, name, &local_err);
13613a53009fSGonglei     if (local_err) {
13623a53009fSGonglei         error_propagate(errp, local_err);
13633a53009fSGonglei         goto out;
13643a53009fSGonglei     }
13653a53009fSGonglei 
13663b098d56SEric Blake     visit_complete(v, &string);
13673a53009fSGonglei 
13683a53009fSGonglei out:
13693b098d56SEric Blake     visit_free(v);
1370b2cd7deeSPaolo Bonzini     return string;
1371b2cd7deeSPaolo Bonzini }
1372b2cd7deeSPaolo Bonzini 
137357c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp)
137457c9fafeSAnthony Liguori {
137589bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(obj, name, errp);
137657c9fafeSAnthony Liguori     if (prop == NULL) {
137757c9fafeSAnthony Liguori         return NULL;
137857c9fafeSAnthony Liguori     }
137957c9fafeSAnthony Liguori 
138057c9fafeSAnthony Liguori     return prop->type;
138157c9fafeSAnthony Liguori }
138257c9fafeSAnthony Liguori 
138357c9fafeSAnthony Liguori Object *object_get_root(void)
138457c9fafeSAnthony Liguori {
13858b45d447SAnthony Liguori     static Object *root;
138657c9fafeSAnthony Liguori 
13878b45d447SAnthony Liguori     if (!root) {
13888b45d447SAnthony Liguori         root = object_new("container");
138957c9fafeSAnthony Liguori     }
139057c9fafeSAnthony Liguori 
13918b45d447SAnthony Liguori     return root;
139257c9fafeSAnthony Liguori }
139357c9fafeSAnthony Liguori 
1394bc2256c4SDaniel P. Berrange Object *object_get_objects_root(void)
1395bc2256c4SDaniel P. Berrange {
1396bc2256c4SDaniel P. Berrange     return container_get(object_get_root(), "/objects");
1397bc2256c4SDaniel P. Berrange }
1398bc2256c4SDaniel P. Berrange 
13997c47c4eaSPeter Xu Object *object_get_internal_root(void)
14007c47c4eaSPeter Xu {
14017c47c4eaSPeter Xu     static Object *internal_root;
14027c47c4eaSPeter Xu 
14037c47c4eaSPeter Xu     if (!internal_root) {
14047c47c4eaSPeter Xu         internal_root = object_new("container");
14057c47c4eaSPeter Xu     }
14067c47c4eaSPeter Xu 
14077c47c4eaSPeter Xu     return internal_root;
14087c47c4eaSPeter Xu }
14097c47c4eaSPeter Xu 
1410d7bce999SEric Blake static void object_get_child_property(Object *obj, Visitor *v,
1411d7bce999SEric Blake                                       const char *name, void *opaque,
1412d7bce999SEric Blake                                       Error **errp)
141357c9fafeSAnthony Liguori {
141457c9fafeSAnthony Liguori     Object *child = opaque;
141557c9fafeSAnthony Liguori     gchar *path;
141657c9fafeSAnthony Liguori 
141757c9fafeSAnthony Liguori     path = object_get_canonical_path(child);
141851e72bc1SEric Blake     visit_type_str(v, name, &path, errp);
141957c9fafeSAnthony Liguori     g_free(path);
142057c9fafeSAnthony Liguori }
142157c9fafeSAnthony Liguori 
142264607d08SPaolo Bonzini static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part)
142364607d08SPaolo Bonzini {
142464607d08SPaolo Bonzini     return opaque;
142564607d08SPaolo Bonzini }
142664607d08SPaolo Bonzini 
1427db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name,
1428db85b575SAnthony Liguori                                            void *opaque)
1429db85b575SAnthony Liguori {
1430db85b575SAnthony Liguori     Object *child = opaque;
1431db85b575SAnthony Liguori 
1432bffc687dSPaolo Bonzini     if (child->class->unparent) {
1433bffc687dSPaolo Bonzini         (child->class->unparent)(child);
1434bffc687dSPaolo Bonzini     }
1435bffc687dSPaolo Bonzini     child->parent = NULL;
1436db85b575SAnthony Liguori     object_unref(child);
1437db85b575SAnthony Liguori }
1438db85b575SAnthony Liguori 
143957c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name,
144057c9fafeSAnthony Liguori                                Object *child, Error **errp)
144157c9fafeSAnthony Liguori {
1442b0ed5e9fSPaolo Bonzini     Error *local_err = NULL;
144357c9fafeSAnthony Liguori     gchar *type;
144464607d08SPaolo Bonzini     ObjectProperty *op;
144557c9fafeSAnthony Liguori 
14468faa2f85SPeter Crosthwaite     if (child->parent != NULL) {
14478faa2f85SPeter Crosthwaite         error_setg(errp, "child object is already parented");
14488faa2f85SPeter Crosthwaite         return;
14498faa2f85SPeter Crosthwaite     }
14508faa2f85SPeter Crosthwaite 
145157c9fafeSAnthony Liguori     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
145257c9fafeSAnthony Liguori 
145364607d08SPaolo Bonzini     op = object_property_add(obj, name, type, object_get_child_property, NULL,
1454b0ed5e9fSPaolo Bonzini                              object_finalize_child_property, child, &local_err);
1455b0ed5e9fSPaolo Bonzini     if (local_err) {
1456b0ed5e9fSPaolo Bonzini         error_propagate(errp, local_err);
1457b0ed5e9fSPaolo Bonzini         goto out;
1458b0ed5e9fSPaolo Bonzini     }
145964607d08SPaolo Bonzini 
146064607d08SPaolo Bonzini     op->resolve = object_resolve_child_property;
146157c9fafeSAnthony Liguori     object_ref(child);
146257c9fafeSAnthony Liguori     child->parent = obj;
146357c9fafeSAnthony Liguori 
1464b0ed5e9fSPaolo Bonzini out:
146557c9fafeSAnthony Liguori     g_free(type);
146657c9fafeSAnthony Liguori }
146757c9fafeSAnthony Liguori 
14688f5d58efSIgor Mammedov void object_property_allow_set_link(const Object *obj, const char *name,
146939f72ef9SStefan Hajnoczi                                     Object *val, Error **errp)
147039f72ef9SStefan Hajnoczi {
147139f72ef9SStefan Hajnoczi     /* Allow the link to be set, always */
147239f72ef9SStefan Hajnoczi }
147339f72ef9SStefan Hajnoczi 
14749561fda8SStefan Hajnoczi typedef struct {
14759561fda8SStefan Hajnoczi     Object **child;
14768f5d58efSIgor Mammedov     void (*check)(const Object *, const char *, Object *, Error **);
14779561fda8SStefan Hajnoczi     ObjectPropertyLinkFlags flags;
14789561fda8SStefan Hajnoczi } LinkProperty;
14799561fda8SStefan Hajnoczi 
1480d7bce999SEric Blake static void object_get_link_property(Object *obj, Visitor *v,
1481d7bce999SEric Blake                                      const char *name, void *opaque,
1482d7bce999SEric Blake                                      Error **errp)
148357c9fafeSAnthony Liguori {
14849561fda8SStefan Hajnoczi     LinkProperty *lprop = opaque;
14859561fda8SStefan Hajnoczi     Object **child = lprop->child;
148657c9fafeSAnthony Liguori     gchar *path;
148757c9fafeSAnthony Liguori 
148857c9fafeSAnthony Liguori     if (*child) {
148957c9fafeSAnthony Liguori         path = object_get_canonical_path(*child);
149051e72bc1SEric Blake         visit_type_str(v, name, &path, errp);
149157c9fafeSAnthony Liguori         g_free(path);
149257c9fafeSAnthony Liguori     } else {
149357c9fafeSAnthony Liguori         path = (gchar *)"";
149451e72bc1SEric Blake         visit_type_str(v, name, &path, errp);
149557c9fafeSAnthony Liguori     }
149657c9fafeSAnthony Liguori }
149757c9fafeSAnthony Liguori 
1498f5ec6704SStefan Hajnoczi /*
1499f5ec6704SStefan Hajnoczi  * object_resolve_link:
1500f5ec6704SStefan Hajnoczi  *
1501f5ec6704SStefan Hajnoczi  * Lookup an object and ensure its type matches the link property type.  This
1502f5ec6704SStefan Hajnoczi  * is similar to object_resolve_path() except type verification against the
1503f5ec6704SStefan Hajnoczi  * link property is performed.
1504f5ec6704SStefan Hajnoczi  *
1505f5ec6704SStefan Hajnoczi  * Returns: The matched object or NULL on path lookup failures.
1506f5ec6704SStefan Hajnoczi  */
1507f5ec6704SStefan Hajnoczi static Object *object_resolve_link(Object *obj, const char *name,
1508f5ec6704SStefan Hajnoczi                                    const char *path, Error **errp)
1509f5ec6704SStefan Hajnoczi {
1510f5ec6704SStefan Hajnoczi     const char *type;
1511f5ec6704SStefan Hajnoczi     gchar *target_type;
1512f5ec6704SStefan Hajnoczi     bool ambiguous = false;
1513f5ec6704SStefan Hajnoczi     Object *target;
1514f5ec6704SStefan Hajnoczi 
1515f5ec6704SStefan Hajnoczi     /* Go from link<FOO> to FOO.  */
1516f5ec6704SStefan Hajnoczi     type = object_property_get_type(obj, name, NULL);
1517f5ec6704SStefan Hajnoczi     target_type = g_strndup(&type[5], strlen(type) - 6);
1518f5ec6704SStefan Hajnoczi     target = object_resolve_path_type(path, target_type, &ambiguous);
1519f5ec6704SStefan Hajnoczi 
1520f5ec6704SStefan Hajnoczi     if (ambiguous) {
1521455b0fdeSEric Blake         error_setg(errp, "Path '%s' does not uniquely identify an object",
1522455b0fdeSEric Blake                    path);
1523f5ec6704SStefan Hajnoczi     } else if (!target) {
1524f5ec6704SStefan Hajnoczi         target = object_resolve_path(path, &ambiguous);
1525f5ec6704SStefan Hajnoczi         if (target || ambiguous) {
1526c6bd8c70SMarkus Armbruster             error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
1527f5ec6704SStefan Hajnoczi         } else {
152875158ebbSMarkus Armbruster             error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
152975158ebbSMarkus Armbruster                       "Device '%s' not found", path);
1530f5ec6704SStefan Hajnoczi         }
1531f5ec6704SStefan Hajnoczi         target = NULL;
1532f5ec6704SStefan Hajnoczi     }
1533f5ec6704SStefan Hajnoczi     g_free(target_type);
1534f5ec6704SStefan Hajnoczi 
1535f5ec6704SStefan Hajnoczi     return target;
1536f5ec6704SStefan Hajnoczi }
1537f5ec6704SStefan Hajnoczi 
1538d7bce999SEric Blake static void object_set_link_property(Object *obj, Visitor *v,
1539d7bce999SEric Blake                                      const char *name, void *opaque,
1540d7bce999SEric Blake                                      Error **errp)
154157c9fafeSAnthony Liguori {
1542c6aed983SStefan Hajnoczi     Error *local_err = NULL;
15439561fda8SStefan Hajnoczi     LinkProperty *prop = opaque;
15449561fda8SStefan Hajnoczi     Object **child = prop->child;
1545c6aed983SStefan Hajnoczi     Object *old_target = *child;
1546c6aed983SStefan Hajnoczi     Object *new_target = NULL;
1547c6aed983SStefan Hajnoczi     char *path = NULL;
154857c9fafeSAnthony Liguori 
154951e72bc1SEric Blake     visit_type_str(v, name, &path, &local_err);
155057c9fafeSAnthony Liguori 
1551c6aed983SStefan Hajnoczi     if (!local_err && strcmp(path, "") != 0) {
1552c6aed983SStefan Hajnoczi         new_target = object_resolve_link(obj, name, path, &local_err);
155311e35bfdSPaolo Bonzini     }
155457c9fafeSAnthony Liguori 
155557c9fafeSAnthony Liguori     g_free(path);
1556c6aed983SStefan Hajnoczi     if (local_err) {
1557c6aed983SStefan Hajnoczi         error_propagate(errp, local_err);
1558c6aed983SStefan Hajnoczi         return;
1559c6aed983SStefan Hajnoczi     }
1560f0cdc966SAlexander Barabash 
156139f72ef9SStefan Hajnoczi     prop->check(obj, name, new_target, &local_err);
156239f72ef9SStefan Hajnoczi     if (local_err) {
156339f72ef9SStefan Hajnoczi         error_propagate(errp, local_err);
156439f72ef9SStefan Hajnoczi         return;
156539f72ef9SStefan Hajnoczi     }
156639f72ef9SStefan Hajnoczi 
1567c6aed983SStefan Hajnoczi     object_ref(new_target);
1568c6aed983SStefan Hajnoczi     *child = new_target;
1569f0cdc966SAlexander Barabash     object_unref(old_target);
1570f0cdc966SAlexander Barabash }
157157c9fafeSAnthony Liguori 
157264607d08SPaolo Bonzini static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
157364607d08SPaolo Bonzini {
157464607d08SPaolo Bonzini     LinkProperty *lprop = opaque;
157564607d08SPaolo Bonzini 
157664607d08SPaolo Bonzini     return *lprop->child;
157764607d08SPaolo Bonzini }
157864607d08SPaolo Bonzini 
15799561fda8SStefan Hajnoczi static void object_release_link_property(Object *obj, const char *name,
15809561fda8SStefan Hajnoczi                                          void *opaque)
15819561fda8SStefan Hajnoczi {
15829561fda8SStefan Hajnoczi     LinkProperty *prop = opaque;
15839561fda8SStefan Hajnoczi 
15849561fda8SStefan Hajnoczi     if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) {
15859561fda8SStefan Hajnoczi         object_unref(*prop->child);
15869561fda8SStefan Hajnoczi     }
15879561fda8SStefan Hajnoczi     g_free(prop);
15889561fda8SStefan Hajnoczi }
15899561fda8SStefan Hajnoczi 
159057c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name,
159157c9fafeSAnthony Liguori                               const char *type, Object **child,
15928f5d58efSIgor Mammedov                               void (*check)(const Object *, const char *,
159339f72ef9SStefan Hajnoczi                                             Object *, Error **),
15949561fda8SStefan Hajnoczi                               ObjectPropertyLinkFlags flags,
159557c9fafeSAnthony Liguori                               Error **errp)
159657c9fafeSAnthony Liguori {
15979561fda8SStefan Hajnoczi     Error *local_err = NULL;
15989561fda8SStefan Hajnoczi     LinkProperty *prop = g_malloc(sizeof(*prop));
159957c9fafeSAnthony Liguori     gchar *full_type;
160064607d08SPaolo Bonzini     ObjectProperty *op;
160157c9fafeSAnthony Liguori 
16029561fda8SStefan Hajnoczi     prop->child = child;
160339f72ef9SStefan Hajnoczi     prop->check = check;
16049561fda8SStefan Hajnoczi     prop->flags = flags;
16059561fda8SStefan Hajnoczi 
160657c9fafeSAnthony Liguori     full_type = g_strdup_printf("link<%s>", type);
160757c9fafeSAnthony Liguori 
160864607d08SPaolo Bonzini     op = object_property_add(obj, name, full_type,
160957c9fafeSAnthony Liguori                              object_get_link_property,
161039f72ef9SStefan Hajnoczi                              check ? object_set_link_property : NULL,
16119561fda8SStefan Hajnoczi                              object_release_link_property,
16129561fda8SStefan Hajnoczi                              prop,
16139561fda8SStefan Hajnoczi                              &local_err);
16149561fda8SStefan Hajnoczi     if (local_err) {
16159561fda8SStefan Hajnoczi         error_propagate(errp, local_err);
16169561fda8SStefan Hajnoczi         g_free(prop);
161764607d08SPaolo Bonzini         goto out;
16189561fda8SStefan Hajnoczi     }
161957c9fafeSAnthony Liguori 
162064607d08SPaolo Bonzini     op->resolve = object_resolve_link_property;
162164607d08SPaolo Bonzini 
162264607d08SPaolo Bonzini out:
162357c9fafeSAnthony Liguori     g_free(full_type);
162457c9fafeSAnthony Liguori }
162557c9fafeSAnthony Liguori 
1626fb9e7e33SPaolo Bonzini void object_property_add_const_link(Object *obj, const char *name,
1627fb9e7e33SPaolo Bonzini                                     Object *target, Error **errp)
1628fb9e7e33SPaolo Bonzini {
1629fb9e7e33SPaolo Bonzini     char *link_type;
1630fb9e7e33SPaolo Bonzini     ObjectProperty *op;
1631fb9e7e33SPaolo Bonzini 
1632fb9e7e33SPaolo Bonzini     link_type = g_strdup_printf("link<%s>", object_get_typename(target));
1633fb9e7e33SPaolo Bonzini     op = object_property_add(obj, name, link_type,
1634fb9e7e33SPaolo Bonzini                              object_get_child_property, NULL,
1635fb9e7e33SPaolo Bonzini                              NULL, target, errp);
1636fb9e7e33SPaolo Bonzini     if (op != NULL) {
1637fb9e7e33SPaolo Bonzini         op->resolve = object_resolve_child_property;
1638fb9e7e33SPaolo Bonzini     }
1639fb9e7e33SPaolo Bonzini     g_free(link_type);
1640fb9e7e33SPaolo Bonzini }
1641fb9e7e33SPaolo Bonzini 
164211f590b1SStefan Hajnoczi gchar *object_get_canonical_path_component(Object *obj)
164357c9fafeSAnthony Liguori {
164457c9fafeSAnthony Liguori     ObjectProperty *prop = NULL;
1645b604a854SPavel Fedin     GHashTableIter iter;
164657c9fafeSAnthony Liguori 
164711f590b1SStefan Hajnoczi     g_assert(obj);
164857c9fafeSAnthony Liguori     g_assert(obj->parent != NULL);
164957c9fafeSAnthony Liguori 
1650b604a854SPavel Fedin     g_hash_table_iter_init(&iter, obj->parent->properties);
1651b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) {
16525d9d3f47SAndreas Färber         if (!object_property_is_child(prop)) {
165357c9fafeSAnthony Liguori             continue;
165457c9fafeSAnthony Liguori         }
165557c9fafeSAnthony Liguori 
165657c9fafeSAnthony Liguori         if (prop->opaque == obj) {
165711f590b1SStefan Hajnoczi             return g_strdup(prop->name);
165857c9fafeSAnthony Liguori         }
165957c9fafeSAnthony Liguori     }
166057c9fafeSAnthony Liguori 
166111f590b1SStefan Hajnoczi     /* obj had a parent but was not a child, should never happen */
166211f590b1SStefan Hajnoczi     g_assert_not_reached();
166311f590b1SStefan Hajnoczi     return NULL;
166411f590b1SStefan Hajnoczi }
166511f590b1SStefan Hajnoczi 
166611f590b1SStefan Hajnoczi gchar *object_get_canonical_path(Object *obj)
166711f590b1SStefan Hajnoczi {
166811f590b1SStefan Hajnoczi     Object *root = object_get_root();
166911f590b1SStefan Hajnoczi     char *newpath, *path = NULL;
167011f590b1SStefan Hajnoczi 
167111f590b1SStefan Hajnoczi     while (obj != root) {
167211f590b1SStefan Hajnoczi         char *component = object_get_canonical_path_component(obj);
167311f590b1SStefan Hajnoczi 
167411f590b1SStefan Hajnoczi         if (path) {
167511f590b1SStefan Hajnoczi             newpath = g_strdup_printf("%s/%s", component, path);
167611f590b1SStefan Hajnoczi             g_free(component);
167711f590b1SStefan Hajnoczi             g_free(path);
167811f590b1SStefan Hajnoczi             path = newpath;
167911f590b1SStefan Hajnoczi         } else {
168011f590b1SStefan Hajnoczi             path = component;
168111f590b1SStefan Hajnoczi         }
168257c9fafeSAnthony Liguori 
168357c9fafeSAnthony Liguori         obj = obj->parent;
168457c9fafeSAnthony Liguori     }
168557c9fafeSAnthony Liguori 
168611f590b1SStefan Hajnoczi     newpath = g_strdup_printf("/%s", path ? path : "");
168757c9fafeSAnthony Liguori     g_free(path);
168857c9fafeSAnthony Liguori 
168957c9fafeSAnthony Liguori     return newpath;
169057c9fafeSAnthony Liguori }
169157c9fafeSAnthony Liguori 
16923e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part)
1693a612b2a6SPaolo Bonzini {
169489bfe000SPaolo Bonzini     ObjectProperty *prop = object_property_find(parent, part, NULL);
1695a612b2a6SPaolo Bonzini     if (prop == NULL) {
1696a612b2a6SPaolo Bonzini         return NULL;
1697a612b2a6SPaolo Bonzini     }
1698a612b2a6SPaolo Bonzini 
169964607d08SPaolo Bonzini     if (prop->resolve) {
170064607d08SPaolo Bonzini         return prop->resolve(parent, prop->opaque, part);
1701a612b2a6SPaolo Bonzini     } else {
1702a612b2a6SPaolo Bonzini         return NULL;
1703a612b2a6SPaolo Bonzini     }
1704a612b2a6SPaolo Bonzini }
1705a612b2a6SPaolo Bonzini 
170657c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent,
170757c9fafeSAnthony Liguori                                           gchar **parts,
170802fe2db6SPaolo Bonzini                                           const char *typename,
170957c9fafeSAnthony Liguori                                           int index)
171057c9fafeSAnthony Liguori {
171157c9fafeSAnthony Liguori     Object *child;
171257c9fafeSAnthony Liguori 
171357c9fafeSAnthony Liguori     if (parts[index] == NULL) {
171402fe2db6SPaolo Bonzini         return object_dynamic_cast(parent, typename);
171557c9fafeSAnthony Liguori     }
171657c9fafeSAnthony Liguori 
171757c9fafeSAnthony Liguori     if (strcmp(parts[index], "") == 0) {
171802fe2db6SPaolo Bonzini         return object_resolve_abs_path(parent, parts, typename, index + 1);
171957c9fafeSAnthony Liguori     }
172057c9fafeSAnthony Liguori 
1721a612b2a6SPaolo Bonzini     child = object_resolve_path_component(parent, parts[index]);
172257c9fafeSAnthony Liguori     if (!child) {
172357c9fafeSAnthony Liguori         return NULL;
172457c9fafeSAnthony Liguori     }
172557c9fafeSAnthony Liguori 
172602fe2db6SPaolo Bonzini     return object_resolve_abs_path(child, parts, typename, index + 1);
172757c9fafeSAnthony Liguori }
172857c9fafeSAnthony Liguori 
172957c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent,
173057c9fafeSAnthony Liguori                                               gchar **parts,
173102fe2db6SPaolo Bonzini                                               const char *typename,
173257c9fafeSAnthony Liguori                                               bool *ambiguous)
173357c9fafeSAnthony Liguori {
173457c9fafeSAnthony Liguori     Object *obj;
1735b604a854SPavel Fedin     GHashTableIter iter;
173657c9fafeSAnthony Liguori     ObjectProperty *prop;
173757c9fafeSAnthony Liguori 
173802fe2db6SPaolo Bonzini     obj = object_resolve_abs_path(parent, parts, typename, 0);
173957c9fafeSAnthony Liguori 
1740b604a854SPavel Fedin     g_hash_table_iter_init(&iter, parent->properties);
1741b604a854SPavel Fedin     while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) {
174257c9fafeSAnthony Liguori         Object *found;
174357c9fafeSAnthony Liguori 
17445d9d3f47SAndreas Färber         if (!object_property_is_child(prop)) {
174557c9fafeSAnthony Liguori             continue;
174657c9fafeSAnthony Liguori         }
174757c9fafeSAnthony Liguori 
174802fe2db6SPaolo Bonzini         found = object_resolve_partial_path(prop->opaque, parts,
174902fe2db6SPaolo Bonzini                                             typename, ambiguous);
175057c9fafeSAnthony Liguori         if (found) {
175157c9fafeSAnthony Liguori             if (obj) {
175257c9fafeSAnthony Liguori                 *ambiguous = true;
175357c9fafeSAnthony Liguori                 return NULL;
175457c9fafeSAnthony Liguori             }
175557c9fafeSAnthony Liguori             obj = found;
175657c9fafeSAnthony Liguori         }
175757c9fafeSAnthony Liguori 
1758ebcc479eSEduardo Habkost         if (*ambiguous) {
175957c9fafeSAnthony Liguori             return NULL;
176057c9fafeSAnthony Liguori         }
176157c9fafeSAnthony Liguori     }
176257c9fafeSAnthony Liguori 
176357c9fafeSAnthony Liguori     return obj;
176457c9fafeSAnthony Liguori }
176557c9fafeSAnthony Liguori 
176602fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename,
1767ebcc479eSEduardo Habkost                                  bool *ambiguousp)
176857c9fafeSAnthony Liguori {
176957c9fafeSAnthony Liguori     Object *obj;
177057c9fafeSAnthony Liguori     gchar **parts;
177157c9fafeSAnthony Liguori 
177257c9fafeSAnthony Liguori     parts = g_strsplit(path, "/", 0);
17732e1103f6SPaolo Bonzini     assert(parts);
177457c9fafeSAnthony Liguori 
17752e1103f6SPaolo Bonzini     if (parts[0] == NULL || strcmp(parts[0], "") != 0) {
1776ebcc479eSEduardo Habkost         bool ambiguous = false;
177702fe2db6SPaolo Bonzini         obj = object_resolve_partial_path(object_get_root(), parts,
1778ebcc479eSEduardo Habkost                                           typename, &ambiguous);
1779ebcc479eSEduardo Habkost         if (ambiguousp) {
1780ebcc479eSEduardo Habkost             *ambiguousp = ambiguous;
1781ebcc479eSEduardo Habkost         }
178257c9fafeSAnthony Liguori     } else {
178302fe2db6SPaolo Bonzini         obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
178457c9fafeSAnthony Liguori     }
178557c9fafeSAnthony Liguori 
178657c9fafeSAnthony Liguori     g_strfreev(parts);
178757c9fafeSAnthony Liguori 
178857c9fafeSAnthony Liguori     return obj;
178957c9fafeSAnthony Liguori }
179057c9fafeSAnthony Liguori 
179102fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous)
179202fe2db6SPaolo Bonzini {
179302fe2db6SPaolo Bonzini     return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
179402fe2db6SPaolo Bonzini }
179502fe2db6SPaolo Bonzini 
179657c9fafeSAnthony Liguori typedef struct StringProperty
179757c9fafeSAnthony Liguori {
179857c9fafeSAnthony Liguori     char *(*get)(Object *, Error **);
179957c9fafeSAnthony Liguori     void (*set)(Object *, const char *, Error **);
180057c9fafeSAnthony Liguori } StringProperty;
180157c9fafeSAnthony Liguori 
1802d7bce999SEric Blake static void property_get_str(Object *obj, Visitor *v, const char *name,
1803d7bce999SEric Blake                              void *opaque, Error **errp)
180457c9fafeSAnthony Liguori {
180557c9fafeSAnthony Liguori     StringProperty *prop = opaque;
180657c9fafeSAnthony Liguori     char *value;
1807e1c8237dSMarkus Armbruster     Error *err = NULL;
180857c9fafeSAnthony Liguori 
1809e1c8237dSMarkus Armbruster     value = prop->get(obj, &err);
1810e1c8237dSMarkus Armbruster     if (err) {
1811e1c8237dSMarkus Armbruster         error_propagate(errp, err);
1812e1c8237dSMarkus Armbruster         return;
1813e1c8237dSMarkus Armbruster     }
1814e1c8237dSMarkus Armbruster 
181551e72bc1SEric Blake     visit_type_str(v, name, &value, errp);
181657c9fafeSAnthony Liguori     g_free(value);
181757c9fafeSAnthony Liguori }
181857c9fafeSAnthony Liguori 
1819d7bce999SEric Blake static void property_set_str(Object *obj, Visitor *v, const char *name,
1820d7bce999SEric Blake                              void *opaque, Error **errp)
182157c9fafeSAnthony Liguori {
182257c9fafeSAnthony Liguori     StringProperty *prop = opaque;
182357c9fafeSAnthony Liguori     char *value;
182457c9fafeSAnthony Liguori     Error *local_err = NULL;
182557c9fafeSAnthony Liguori 
182651e72bc1SEric Blake     visit_type_str(v, name, &value, &local_err);
182757c9fafeSAnthony Liguori     if (local_err) {
182857c9fafeSAnthony Liguori         error_propagate(errp, local_err);
182957c9fafeSAnthony Liguori         return;
183057c9fafeSAnthony Liguori     }
183157c9fafeSAnthony Liguori 
183257c9fafeSAnthony Liguori     prop->set(obj, value, errp);
183357c9fafeSAnthony Liguori     g_free(value);
183457c9fafeSAnthony Liguori }
183557c9fafeSAnthony Liguori 
18367b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name,
183757c9fafeSAnthony Liguori                                  void *opaque)
183857c9fafeSAnthony Liguori {
183957c9fafeSAnthony Liguori     StringProperty *prop = opaque;
184057c9fafeSAnthony Liguori     g_free(prop);
184157c9fafeSAnthony Liguori }
184257c9fafeSAnthony Liguori 
184357c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name,
184457c9fafeSAnthony Liguori                            char *(*get)(Object *, Error **),
184557c9fafeSAnthony Liguori                            void (*set)(Object *, const char *, Error **),
184657c9fafeSAnthony Liguori                            Error **errp)
184757c9fafeSAnthony Liguori {
1848a01aedc8SStefan Hajnoczi     Error *local_err = NULL;
184957c9fafeSAnthony Liguori     StringProperty *prop = g_malloc0(sizeof(*prop));
185057c9fafeSAnthony Liguori 
185157c9fafeSAnthony Liguori     prop->get = get;
185257c9fafeSAnthony Liguori     prop->set = set;
185357c9fafeSAnthony Liguori 
185457c9fafeSAnthony Liguori     object_property_add(obj, name, "string",
18557b7b7d18SPaolo Bonzini                         get ? property_get_str : NULL,
18567b7b7d18SPaolo Bonzini                         set ? property_set_str : NULL,
18577b7b7d18SPaolo Bonzini                         property_release_str,
1858a01aedc8SStefan Hajnoczi                         prop, &local_err);
1859a01aedc8SStefan Hajnoczi     if (local_err) {
1860a01aedc8SStefan Hajnoczi         error_propagate(errp, local_err);
1861a01aedc8SStefan Hajnoczi         g_free(prop);
1862a01aedc8SStefan Hajnoczi     }
186357c9fafeSAnthony Liguori }
1864745549c8SPaolo Bonzini 
186516bf7f52SDaniel P. Berrange void object_class_property_add_str(ObjectClass *klass, const char *name,
186616bf7f52SDaniel P. Berrange                                    char *(*get)(Object *, Error **),
186716bf7f52SDaniel P. Berrange                                    void (*set)(Object *, const char *,
186816bf7f52SDaniel P. Berrange                                                Error **),
186916bf7f52SDaniel P. Berrange                                    Error **errp)
187016bf7f52SDaniel P. Berrange {
187116bf7f52SDaniel P. Berrange     Error *local_err = NULL;
187216bf7f52SDaniel P. Berrange     StringProperty *prop = g_malloc0(sizeof(*prop));
187316bf7f52SDaniel P. Berrange 
187416bf7f52SDaniel P. Berrange     prop->get = get;
187516bf7f52SDaniel P. Berrange     prop->set = set;
187616bf7f52SDaniel P. Berrange 
187716bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "string",
187816bf7f52SDaniel P. Berrange                               get ? property_get_str : NULL,
187916bf7f52SDaniel P. Berrange                               set ? property_set_str : NULL,
188016bf7f52SDaniel P. Berrange                               property_release_str,
188116bf7f52SDaniel P. Berrange                               prop, &local_err);
188216bf7f52SDaniel P. Berrange     if (local_err) {
188316bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
188416bf7f52SDaniel P. Berrange         g_free(prop);
188516bf7f52SDaniel P. Berrange     }
188616bf7f52SDaniel P. Berrange }
188716bf7f52SDaniel P. Berrange 
18880e558843SAnthony Liguori typedef struct BoolProperty
18890e558843SAnthony Liguori {
18900e558843SAnthony Liguori     bool (*get)(Object *, Error **);
18910e558843SAnthony Liguori     void (*set)(Object *, bool, Error **);
18920e558843SAnthony Liguori } BoolProperty;
18930e558843SAnthony Liguori 
1894d7bce999SEric Blake static void property_get_bool(Object *obj, Visitor *v, const char *name,
1895d7bce999SEric Blake                               void *opaque, Error **errp)
18960e558843SAnthony Liguori {
18970e558843SAnthony Liguori     BoolProperty *prop = opaque;
18980e558843SAnthony Liguori     bool value;
18994715d42eSMarkus Armbruster     Error *err = NULL;
19000e558843SAnthony Liguori 
19014715d42eSMarkus Armbruster     value = prop->get(obj, &err);
19024715d42eSMarkus Armbruster     if (err) {
19034715d42eSMarkus Armbruster         error_propagate(errp, err);
19044715d42eSMarkus Armbruster         return;
19054715d42eSMarkus Armbruster     }
19064715d42eSMarkus Armbruster 
190751e72bc1SEric Blake     visit_type_bool(v, name, &value, errp);
19080e558843SAnthony Liguori }
19090e558843SAnthony Liguori 
1910d7bce999SEric Blake static void property_set_bool(Object *obj, Visitor *v, const char *name,
1911d7bce999SEric Blake                               void *opaque, Error **errp)
19120e558843SAnthony Liguori {
19130e558843SAnthony Liguori     BoolProperty *prop = opaque;
19140e558843SAnthony Liguori     bool value;
19150e558843SAnthony Liguori     Error *local_err = NULL;
19160e558843SAnthony Liguori 
191751e72bc1SEric Blake     visit_type_bool(v, name, &value, &local_err);
19180e558843SAnthony Liguori     if (local_err) {
19190e558843SAnthony Liguori         error_propagate(errp, local_err);
19200e558843SAnthony Liguori         return;
19210e558843SAnthony Liguori     }
19220e558843SAnthony Liguori 
19230e558843SAnthony Liguori     prop->set(obj, value, errp);
19240e558843SAnthony Liguori }
19250e558843SAnthony Liguori 
19260e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name,
19270e558843SAnthony Liguori                                   void *opaque)
19280e558843SAnthony Liguori {
19290e558843SAnthony Liguori     BoolProperty *prop = opaque;
19300e558843SAnthony Liguori     g_free(prop);
19310e558843SAnthony Liguori }
19320e558843SAnthony Liguori 
19330e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name,
19340e558843SAnthony Liguori                               bool (*get)(Object *, Error **),
19350e558843SAnthony Liguori                               void (*set)(Object *, bool, Error **),
19360e558843SAnthony Liguori                               Error **errp)
19370e558843SAnthony Liguori {
1938a01aedc8SStefan Hajnoczi     Error *local_err = NULL;
19390e558843SAnthony Liguori     BoolProperty *prop = g_malloc0(sizeof(*prop));
19400e558843SAnthony Liguori 
19410e558843SAnthony Liguori     prop->get = get;
19420e558843SAnthony Liguori     prop->set = set;
19430e558843SAnthony Liguori 
19440e558843SAnthony Liguori     object_property_add(obj, name, "bool",
19450e558843SAnthony Liguori                         get ? property_get_bool : NULL,
19460e558843SAnthony Liguori                         set ? property_set_bool : NULL,
19470e558843SAnthony Liguori                         property_release_bool,
1948a01aedc8SStefan Hajnoczi                         prop, &local_err);
1949a01aedc8SStefan Hajnoczi     if (local_err) {
1950a01aedc8SStefan Hajnoczi         error_propagate(errp, local_err);
1951a01aedc8SStefan Hajnoczi         g_free(prop);
1952a01aedc8SStefan Hajnoczi     }
19530e558843SAnthony Liguori }
19540e558843SAnthony Liguori 
195516bf7f52SDaniel P. Berrange void object_class_property_add_bool(ObjectClass *klass, const char *name,
195616bf7f52SDaniel P. Berrange                                     bool (*get)(Object *, Error **),
195716bf7f52SDaniel P. Berrange                                     void (*set)(Object *, bool, Error **),
195816bf7f52SDaniel P. Berrange                                     Error **errp)
195916bf7f52SDaniel P. Berrange {
196016bf7f52SDaniel P. Berrange     Error *local_err = NULL;
196116bf7f52SDaniel P. Berrange     BoolProperty *prop = g_malloc0(sizeof(*prop));
196216bf7f52SDaniel P. Berrange 
196316bf7f52SDaniel P. Berrange     prop->get = get;
196416bf7f52SDaniel P. Berrange     prop->set = set;
196516bf7f52SDaniel P. Berrange 
196616bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "bool",
196716bf7f52SDaniel P. Berrange                               get ? property_get_bool : NULL,
196816bf7f52SDaniel P. Berrange                               set ? property_set_bool : NULL,
196916bf7f52SDaniel P. Berrange                               property_release_bool,
197016bf7f52SDaniel P. Berrange                               prop, &local_err);
197116bf7f52SDaniel P. Berrange     if (local_err) {
197216bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
197316bf7f52SDaniel P. Berrange         g_free(prop);
197416bf7f52SDaniel P. Berrange     }
197516bf7f52SDaniel P. Berrange }
197616bf7f52SDaniel P. Berrange 
1977d7bce999SEric Blake static void property_get_enum(Object *obj, Visitor *v, const char *name,
1978d7bce999SEric Blake                               void *opaque, Error **errp)
1979a8e3fbedSDaniel P. Berrange {
1980a8e3fbedSDaniel P. Berrange     EnumProperty *prop = opaque;
1981a8e3fbedSDaniel P. Berrange     int value;
19824715d42eSMarkus Armbruster     Error *err = NULL;
1983a8e3fbedSDaniel P. Berrange 
19844715d42eSMarkus Armbruster     value = prop->get(obj, &err);
19854715d42eSMarkus Armbruster     if (err) {
19864715d42eSMarkus Armbruster         error_propagate(errp, err);
19874715d42eSMarkus Armbruster         return;
19884715d42eSMarkus Armbruster     }
19894715d42eSMarkus Armbruster 
1990f7abe0ecSMarc-André Lureau     visit_type_enum(v, name, &value, prop->lookup, errp);
1991a8e3fbedSDaniel P. Berrange }
1992a8e3fbedSDaniel P. Berrange 
1993d7bce999SEric Blake static void property_set_enum(Object *obj, Visitor *v, const char *name,
1994d7bce999SEric Blake                               void *opaque, Error **errp)
1995a8e3fbedSDaniel P. Berrange {
1996a8e3fbedSDaniel P. Berrange     EnumProperty *prop = opaque;
1997a8e3fbedSDaniel P. Berrange     int value;
19984715d42eSMarkus Armbruster     Error *err = NULL;
1999a8e3fbedSDaniel P. Berrange 
2000f7abe0ecSMarc-André Lureau     visit_type_enum(v, name, &value, prop->lookup, &err);
20014715d42eSMarkus Armbruster     if (err) {
20024715d42eSMarkus Armbruster         error_propagate(errp, err);
20034715d42eSMarkus Armbruster         return;
20044715d42eSMarkus Armbruster     }
2005a8e3fbedSDaniel P. Berrange     prop->set(obj, value, errp);
2006a8e3fbedSDaniel P. Berrange }
2007a8e3fbedSDaniel P. Berrange 
2008a8e3fbedSDaniel P. Berrange static void property_release_enum(Object *obj, const char *name,
2009a8e3fbedSDaniel P. Berrange                                   void *opaque)
2010a8e3fbedSDaniel P. Berrange {
2011a8e3fbedSDaniel P. Berrange     EnumProperty *prop = opaque;
2012a8e3fbedSDaniel P. Berrange     g_free(prop);
2013a8e3fbedSDaniel P. Berrange }
2014a8e3fbedSDaniel P. Berrange 
2015a8e3fbedSDaniel P. Berrange void object_property_add_enum(Object *obj, const char *name,
2016a8e3fbedSDaniel P. Berrange                               const char *typename,
2017f7abe0ecSMarc-André Lureau                               const QEnumLookup *lookup,
2018a8e3fbedSDaniel P. Berrange                               int (*get)(Object *, Error **),
2019a8e3fbedSDaniel P. Berrange                               void (*set)(Object *, int, Error **),
2020a8e3fbedSDaniel P. Berrange                               Error **errp)
2021a8e3fbedSDaniel P. Berrange {
2022a8e3fbedSDaniel P. Berrange     Error *local_err = NULL;
2023a8e3fbedSDaniel P. Berrange     EnumProperty *prop = g_malloc(sizeof(*prop));
2024a8e3fbedSDaniel P. Berrange 
2025f7abe0ecSMarc-André Lureau     prop->lookup = lookup;
2026a8e3fbedSDaniel P. Berrange     prop->get = get;
2027a8e3fbedSDaniel P. Berrange     prop->set = set;
2028a8e3fbedSDaniel P. Berrange 
2029a8e3fbedSDaniel P. Berrange     object_property_add(obj, name, typename,
2030a8e3fbedSDaniel P. Berrange                         get ? property_get_enum : NULL,
2031a8e3fbedSDaniel P. Berrange                         set ? property_set_enum : NULL,
2032a8e3fbedSDaniel P. Berrange                         property_release_enum,
2033a8e3fbedSDaniel P. Berrange                         prop, &local_err);
2034a8e3fbedSDaniel P. Berrange     if (local_err) {
2035a8e3fbedSDaniel P. Berrange         error_propagate(errp, local_err);
2036a8e3fbedSDaniel P. Berrange         g_free(prop);
2037a8e3fbedSDaniel P. Berrange     }
2038a8e3fbedSDaniel P. Berrange }
2039a8e3fbedSDaniel P. Berrange 
204016bf7f52SDaniel P. Berrange void object_class_property_add_enum(ObjectClass *klass, const char *name,
204116bf7f52SDaniel P. Berrange                                     const char *typename,
2042f7abe0ecSMarc-André Lureau                                     const QEnumLookup *lookup,
204316bf7f52SDaniel P. Berrange                                     int (*get)(Object *, Error **),
204416bf7f52SDaniel P. Berrange                                     void (*set)(Object *, int, Error **),
204516bf7f52SDaniel P. Berrange                                     Error **errp)
204616bf7f52SDaniel P. Berrange {
204716bf7f52SDaniel P. Berrange     Error *local_err = NULL;
204816bf7f52SDaniel P. Berrange     EnumProperty *prop = g_malloc(sizeof(*prop));
204916bf7f52SDaniel P. Berrange 
2050f7abe0ecSMarc-André Lureau     prop->lookup = lookup;
205116bf7f52SDaniel P. Berrange     prop->get = get;
205216bf7f52SDaniel P. Berrange     prop->set = set;
205316bf7f52SDaniel P. Berrange 
205416bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, typename,
205516bf7f52SDaniel P. Berrange                               get ? property_get_enum : NULL,
205616bf7f52SDaniel P. Berrange                               set ? property_set_enum : NULL,
205716bf7f52SDaniel P. Berrange                               property_release_enum,
205816bf7f52SDaniel P. Berrange                               prop, &local_err);
205916bf7f52SDaniel P. Berrange     if (local_err) {
206016bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
206116bf7f52SDaniel P. Berrange         g_free(prop);
206216bf7f52SDaniel P. Berrange     }
206316bf7f52SDaniel P. Berrange }
206416bf7f52SDaniel P. Berrange 
20658e099d14SDavid Gibson typedef struct TMProperty {
20668e099d14SDavid Gibson     void (*get)(Object *, struct tm *, Error **);
20678e099d14SDavid Gibson } TMProperty;
20688e099d14SDavid Gibson 
2069d7bce999SEric Blake static void property_get_tm(Object *obj, Visitor *v, const char *name,
2070d7bce999SEric Blake                             void *opaque, Error **errp)
20718e099d14SDavid Gibson {
20728e099d14SDavid Gibson     TMProperty *prop = opaque;
20738e099d14SDavid Gibson     Error *err = NULL;
20748e099d14SDavid Gibson     struct tm value;
20758e099d14SDavid Gibson 
20768e099d14SDavid Gibson     prop->get(obj, &value, &err);
20778e099d14SDavid Gibson     if (err) {
20788e099d14SDavid Gibson         goto out;
20798e099d14SDavid Gibson     }
20808e099d14SDavid Gibson 
2081337283dfSEric Blake     visit_start_struct(v, name, NULL, 0, &err);
20828e099d14SDavid Gibson     if (err) {
20838e099d14SDavid Gibson         goto out;
20848e099d14SDavid Gibson     }
208551e72bc1SEric Blake     visit_type_int32(v, "tm_year", &value.tm_year, &err);
20868e099d14SDavid Gibson     if (err) {
20878e099d14SDavid Gibson         goto out_end;
20888e099d14SDavid Gibson     }
208951e72bc1SEric Blake     visit_type_int32(v, "tm_mon", &value.tm_mon, &err);
20908e099d14SDavid Gibson     if (err) {
20918e099d14SDavid Gibson         goto out_end;
20928e099d14SDavid Gibson     }
209351e72bc1SEric Blake     visit_type_int32(v, "tm_mday", &value.tm_mday, &err);
20948e099d14SDavid Gibson     if (err) {
20958e099d14SDavid Gibson         goto out_end;
20968e099d14SDavid Gibson     }
209751e72bc1SEric Blake     visit_type_int32(v, "tm_hour", &value.tm_hour, &err);
20988e099d14SDavid Gibson     if (err) {
20998e099d14SDavid Gibson         goto out_end;
21008e099d14SDavid Gibson     }
210151e72bc1SEric Blake     visit_type_int32(v, "tm_min", &value.tm_min, &err);
21028e099d14SDavid Gibson     if (err) {
21038e099d14SDavid Gibson         goto out_end;
21048e099d14SDavid Gibson     }
210551e72bc1SEric Blake     visit_type_int32(v, "tm_sec", &value.tm_sec, &err);
21068e099d14SDavid Gibson     if (err) {
21078e099d14SDavid Gibson         goto out_end;
21088e099d14SDavid Gibson     }
210915c2f669SEric Blake     visit_check_struct(v, &err);
21108e099d14SDavid Gibson out_end:
21111158bb2aSEric Blake     visit_end_struct(v, NULL);
21128e099d14SDavid Gibson out:
21138e099d14SDavid Gibson     error_propagate(errp, err);
21148e099d14SDavid Gibson 
21158e099d14SDavid Gibson }
21168e099d14SDavid Gibson 
21178e099d14SDavid Gibson static void property_release_tm(Object *obj, const char *name,
21188e099d14SDavid Gibson                                 void *opaque)
21198e099d14SDavid Gibson {
21208e099d14SDavid Gibson     TMProperty *prop = opaque;
21218e099d14SDavid Gibson     g_free(prop);
21228e099d14SDavid Gibson }
21238e099d14SDavid Gibson 
21248e099d14SDavid Gibson void object_property_add_tm(Object *obj, const char *name,
21258e099d14SDavid Gibson                             void (*get)(Object *, struct tm *, Error **),
21268e099d14SDavid Gibson                             Error **errp)
21278e099d14SDavid Gibson {
21288e099d14SDavid Gibson     Error *local_err = NULL;
21298e099d14SDavid Gibson     TMProperty *prop = g_malloc0(sizeof(*prop));
21308e099d14SDavid Gibson 
21318e099d14SDavid Gibson     prop->get = get;
21328e099d14SDavid Gibson 
21338e099d14SDavid Gibson     object_property_add(obj, name, "struct tm",
21348e099d14SDavid Gibson                         get ? property_get_tm : NULL, NULL,
21358e099d14SDavid Gibson                         property_release_tm,
21368e099d14SDavid Gibson                         prop, &local_err);
21378e099d14SDavid Gibson     if (local_err) {
21388e099d14SDavid Gibson         error_propagate(errp, local_err);
21398e099d14SDavid Gibson         g_free(prop);
21408e099d14SDavid Gibson     }
21418e099d14SDavid Gibson }
21428e099d14SDavid Gibson 
214316bf7f52SDaniel P. Berrange void object_class_property_add_tm(ObjectClass *klass, const char *name,
214416bf7f52SDaniel P. Berrange                                   void (*get)(Object *, struct tm *, Error **),
214516bf7f52SDaniel P. Berrange                                   Error **errp)
214616bf7f52SDaniel P. Berrange {
214716bf7f52SDaniel P. Berrange     Error *local_err = NULL;
214816bf7f52SDaniel P. Berrange     TMProperty *prop = g_malloc0(sizeof(*prop));
214916bf7f52SDaniel P. Berrange 
215016bf7f52SDaniel P. Berrange     prop->get = get;
215116bf7f52SDaniel P. Berrange 
215216bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "struct tm",
215316bf7f52SDaniel P. Berrange                               get ? property_get_tm : NULL, NULL,
215416bf7f52SDaniel P. Berrange                               property_release_tm,
215516bf7f52SDaniel P. Berrange                               prop, &local_err);
215616bf7f52SDaniel P. Berrange     if (local_err) {
215716bf7f52SDaniel P. Berrange         error_propagate(errp, local_err);
215816bf7f52SDaniel P. Berrange         g_free(prop);
215916bf7f52SDaniel P. Berrange     }
216016bf7f52SDaniel P. Berrange }
216116bf7f52SDaniel P. Berrange 
21622f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp)
21632f262e06SPaolo Bonzini {
21642f262e06SPaolo Bonzini     return g_strdup(object_get_typename(obj));
21652f262e06SPaolo Bonzini }
21662f262e06SPaolo Bonzini 
2167d7bce999SEric Blake static void property_get_uint8_ptr(Object *obj, Visitor *v, const char *name,
2168d7bce999SEric Blake                                    void *opaque, Error **errp)
2169e732ea63SMichael S. Tsirkin {
2170e732ea63SMichael S. Tsirkin     uint8_t value = *(uint8_t *)opaque;
217151e72bc1SEric Blake     visit_type_uint8(v, name, &value, errp);
2172e732ea63SMichael S. Tsirkin }
2173e732ea63SMichael S. Tsirkin 
2174d7bce999SEric Blake static void property_get_uint16_ptr(Object *obj, Visitor *v, const char *name,
2175d7bce999SEric Blake                                     void *opaque, Error **errp)
2176e732ea63SMichael S. Tsirkin {
2177e732ea63SMichael S. Tsirkin     uint16_t value = *(uint16_t *)opaque;
217851e72bc1SEric Blake     visit_type_uint16(v, name, &value, errp);
2179e732ea63SMichael S. Tsirkin }
2180e732ea63SMichael S. Tsirkin 
2181d7bce999SEric Blake static void property_get_uint32_ptr(Object *obj, Visitor *v, const char *name,
2182d7bce999SEric Blake                                     void *opaque, Error **errp)
2183e732ea63SMichael S. Tsirkin {
2184e732ea63SMichael S. Tsirkin     uint32_t value = *(uint32_t *)opaque;
218551e72bc1SEric Blake     visit_type_uint32(v, name, &value, errp);
2186e732ea63SMichael S. Tsirkin }
2187e732ea63SMichael S. Tsirkin 
2188d7bce999SEric Blake static void property_get_uint64_ptr(Object *obj, Visitor *v, const char *name,
2189d7bce999SEric Blake                                     void *opaque, Error **errp)
2190e732ea63SMichael S. Tsirkin {
2191e732ea63SMichael S. Tsirkin     uint64_t value = *(uint64_t *)opaque;
219251e72bc1SEric Blake     visit_type_uint64(v, name, &value, errp);
2193e732ea63SMichael S. Tsirkin }
2194e732ea63SMichael S. Tsirkin 
2195e732ea63SMichael S. Tsirkin void object_property_add_uint8_ptr(Object *obj, const char *name,
2196e732ea63SMichael S. Tsirkin                                    const uint8_t *v, Error **errp)
2197e732ea63SMichael S. Tsirkin {
2198e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint8", property_get_uint8_ptr,
2199e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2200e732ea63SMichael S. Tsirkin }
2201e732ea63SMichael S. Tsirkin 
220216bf7f52SDaniel P. Berrange void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name,
220316bf7f52SDaniel P. Berrange                                          const uint8_t *v, Error **errp)
220416bf7f52SDaniel P. Berrange {
220516bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint8", property_get_uint8_ptr,
220616bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
220716bf7f52SDaniel P. Berrange }
220816bf7f52SDaniel P. Berrange 
2209e732ea63SMichael S. Tsirkin void object_property_add_uint16_ptr(Object *obj, const char *name,
2210e732ea63SMichael S. Tsirkin                                     const uint16_t *v, Error **errp)
2211e732ea63SMichael S. Tsirkin {
2212e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint16", property_get_uint16_ptr,
2213e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2214e732ea63SMichael S. Tsirkin }
2215e732ea63SMichael S. Tsirkin 
221616bf7f52SDaniel P. Berrange void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name,
221716bf7f52SDaniel P. Berrange                                           const uint16_t *v, Error **errp)
221816bf7f52SDaniel P. Berrange {
221916bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint16", property_get_uint16_ptr,
222016bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
222116bf7f52SDaniel P. Berrange }
222216bf7f52SDaniel P. Berrange 
2223e732ea63SMichael S. Tsirkin void object_property_add_uint32_ptr(Object *obj, const char *name,
2224e732ea63SMichael S. Tsirkin                                     const uint32_t *v, Error **errp)
2225e732ea63SMichael S. Tsirkin {
2226e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint32", property_get_uint32_ptr,
2227e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2228e732ea63SMichael S. Tsirkin }
2229e732ea63SMichael S. Tsirkin 
223016bf7f52SDaniel P. Berrange void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name,
223116bf7f52SDaniel P. Berrange                                           const uint32_t *v, Error **errp)
223216bf7f52SDaniel P. Berrange {
223316bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint32", property_get_uint32_ptr,
223416bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
223516bf7f52SDaniel P. Berrange }
223616bf7f52SDaniel P. Berrange 
2237e732ea63SMichael S. Tsirkin void object_property_add_uint64_ptr(Object *obj, const char *name,
2238e732ea63SMichael S. Tsirkin                                     const uint64_t *v, Error **errp)
2239e732ea63SMichael S. Tsirkin {
2240e732ea63SMichael S. Tsirkin     object_property_add(obj, name, "uint64", property_get_uint64_ptr,
2241e732ea63SMichael S. Tsirkin                         NULL, NULL, (void *)v, errp);
2242e732ea63SMichael S. Tsirkin }
2243e732ea63SMichael S. Tsirkin 
224416bf7f52SDaniel P. Berrange void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name,
224516bf7f52SDaniel P. Berrange                                           const uint64_t *v, Error **errp)
224616bf7f52SDaniel P. Berrange {
224716bf7f52SDaniel P. Berrange     object_class_property_add(klass, name, "uint64", property_get_uint64_ptr,
224816bf7f52SDaniel P. Berrange                               NULL, NULL, (void *)v, errp);
224916bf7f52SDaniel P. Berrange }
225016bf7f52SDaniel P. Berrange 
2251ef7c7ff6SStefan Hajnoczi typedef struct {
2252ef7c7ff6SStefan Hajnoczi     Object *target_obj;
22531590d266SEduardo Habkost     char *target_name;
2254ef7c7ff6SStefan Hajnoczi } AliasProperty;
2255ef7c7ff6SStefan Hajnoczi 
2256d7bce999SEric Blake static void property_get_alias(Object *obj, Visitor *v, const char *name,
2257d7bce999SEric Blake                                void *opaque, Error **errp)
2258ef7c7ff6SStefan Hajnoczi {
2259ef7c7ff6SStefan Hajnoczi     AliasProperty *prop = opaque;
2260ef7c7ff6SStefan Hajnoczi 
2261ef7c7ff6SStefan Hajnoczi     object_property_get(prop->target_obj, v, prop->target_name, errp);
2262ef7c7ff6SStefan Hajnoczi }
2263ef7c7ff6SStefan Hajnoczi 
2264d7bce999SEric Blake static void property_set_alias(Object *obj, Visitor *v, const char *name,
2265d7bce999SEric Blake                                void *opaque, Error **errp)
2266ef7c7ff6SStefan Hajnoczi {
2267ef7c7ff6SStefan Hajnoczi     AliasProperty *prop = opaque;
2268ef7c7ff6SStefan Hajnoczi 
2269ef7c7ff6SStefan Hajnoczi     object_property_set(prop->target_obj, v, prop->target_name, errp);
2270ef7c7ff6SStefan Hajnoczi }
2271ef7c7ff6SStefan Hajnoczi 
227264607d08SPaolo Bonzini static Object *property_resolve_alias(Object *obj, void *opaque,
227364607d08SPaolo Bonzini                                       const gchar *part)
227464607d08SPaolo Bonzini {
227564607d08SPaolo Bonzini     AliasProperty *prop = opaque;
227664607d08SPaolo Bonzini 
227764607d08SPaolo Bonzini     return object_resolve_path_component(prop->target_obj, prop->target_name);
227864607d08SPaolo Bonzini }
227964607d08SPaolo Bonzini 
2280ef7c7ff6SStefan Hajnoczi static void property_release_alias(Object *obj, const char *name, void *opaque)
2281ef7c7ff6SStefan Hajnoczi {
2282ef7c7ff6SStefan Hajnoczi     AliasProperty *prop = opaque;
2283ef7c7ff6SStefan Hajnoczi 
22841590d266SEduardo Habkost     g_free(prop->target_name);
2285ef7c7ff6SStefan Hajnoczi     g_free(prop);
2286ef7c7ff6SStefan Hajnoczi }
2287ef7c7ff6SStefan Hajnoczi 
2288ef7c7ff6SStefan Hajnoczi void object_property_add_alias(Object *obj, const char *name,
2289ef7c7ff6SStefan Hajnoczi                                Object *target_obj, const char *target_name,
2290ef7c7ff6SStefan Hajnoczi                                Error **errp)
2291ef7c7ff6SStefan Hajnoczi {
2292ef7c7ff6SStefan Hajnoczi     AliasProperty *prop;
229364607d08SPaolo Bonzini     ObjectProperty *op;
2294ef7c7ff6SStefan Hajnoczi     ObjectProperty *target_prop;
2295d190698eSPaolo Bonzini     gchar *prop_type;
22968ae9a9efSGonglei     Error *local_err = NULL;
2297ef7c7ff6SStefan Hajnoczi 
2298ef7c7ff6SStefan Hajnoczi     target_prop = object_property_find(target_obj, target_name, errp);
2299ef7c7ff6SStefan Hajnoczi     if (!target_prop) {
2300ef7c7ff6SStefan Hajnoczi         return;
2301ef7c7ff6SStefan Hajnoczi     }
2302ef7c7ff6SStefan Hajnoczi 
2303d190698eSPaolo Bonzini     if (object_property_is_child(target_prop)) {
2304d190698eSPaolo Bonzini         prop_type = g_strdup_printf("link%s",
2305d190698eSPaolo Bonzini                                     target_prop->type + strlen("child"));
2306d190698eSPaolo Bonzini     } else {
2307d190698eSPaolo Bonzini         prop_type = g_strdup(target_prop->type);
2308d190698eSPaolo Bonzini     }
2309d190698eSPaolo Bonzini 
2310ef7c7ff6SStefan Hajnoczi     prop = g_malloc(sizeof(*prop));
2311ef7c7ff6SStefan Hajnoczi     prop->target_obj = target_obj;
23121590d266SEduardo Habkost     prop->target_name = g_strdup(target_name);
2313ef7c7ff6SStefan Hajnoczi 
2314d190698eSPaolo Bonzini     op = object_property_add(obj, name, prop_type,
2315ef7c7ff6SStefan Hajnoczi                              property_get_alias,
2316ef7c7ff6SStefan Hajnoczi                              property_set_alias,
2317ef7c7ff6SStefan Hajnoczi                              property_release_alias,
23188ae9a9efSGonglei                              prop, &local_err);
23198ae9a9efSGonglei     if (local_err) {
23208ae9a9efSGonglei         error_propagate(errp, local_err);
23218ae9a9efSGonglei         g_free(prop);
23228ae9a9efSGonglei         goto out;
23238ae9a9efSGonglei     }
232464607d08SPaolo Bonzini     op->resolve = property_resolve_alias;
2325d190698eSPaolo Bonzini 
2326a18bb417SAndreas Färber     object_property_set_description(obj, op->name,
232780742642SGonglei                                     target_prop->description,
232880742642SGonglei                                     &error_abort);
232980742642SGonglei 
23308ae9a9efSGonglei out:
2331d190698eSPaolo Bonzini     g_free(prop_type);
2332ef7c7ff6SStefan Hajnoczi }
2333ef7c7ff6SStefan Hajnoczi 
233480742642SGonglei void object_property_set_description(Object *obj, const char *name,
233580742642SGonglei                                      const char *description, Error **errp)
233680742642SGonglei {
233780742642SGonglei     ObjectProperty *op;
233880742642SGonglei 
233980742642SGonglei     op = object_property_find(obj, name, errp);
234080742642SGonglei     if (!op) {
234180742642SGonglei         return;
234280742642SGonglei     }
234380742642SGonglei 
234480742642SGonglei     g_free(op->description);
234580742642SGonglei     op->description = g_strdup(description);
234680742642SGonglei }
234780742642SGonglei 
234816bf7f52SDaniel P. Berrange void object_class_property_set_description(ObjectClass *klass,
234916bf7f52SDaniel P. Berrange                                            const char *name,
235016bf7f52SDaniel P. Berrange                                            const char *description,
235116bf7f52SDaniel P. Berrange                                            Error **errp)
235216bf7f52SDaniel P. Berrange {
235316bf7f52SDaniel P. Berrange     ObjectProperty *op;
235416bf7f52SDaniel P. Berrange 
235516bf7f52SDaniel P. Berrange     op = g_hash_table_lookup(klass->properties, name);
235616bf7f52SDaniel P. Berrange     if (!op) {
235716bf7f52SDaniel P. Berrange         error_setg(errp, "Property '.%s' not found", name);
235816bf7f52SDaniel P. Berrange         return;
235916bf7f52SDaniel P. Berrange     }
236016bf7f52SDaniel P. Berrange 
236116bf7f52SDaniel P. Berrange     g_free(op->description);
236216bf7f52SDaniel P. Berrange     op->description = g_strdup(description);
236316bf7f52SDaniel P. Berrange }
236416bf7f52SDaniel P. Berrange 
23652f262e06SPaolo Bonzini static void object_instance_init(Object *obj)
23662f262e06SPaolo Bonzini {
23672f262e06SPaolo Bonzini     object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);
23682f262e06SPaolo Bonzini }
23692f262e06SPaolo Bonzini 
2370745549c8SPaolo Bonzini static void register_types(void)
2371745549c8SPaolo Bonzini {
2372745549c8SPaolo Bonzini     static TypeInfo interface_info = {
2373745549c8SPaolo Bonzini         .name = TYPE_INTERFACE,
237433e95c63SAnthony Liguori         .class_size = sizeof(InterfaceClass),
2375745549c8SPaolo Bonzini         .abstract = true,
2376745549c8SPaolo Bonzini     };
2377745549c8SPaolo Bonzini 
2378745549c8SPaolo Bonzini     static TypeInfo object_info = {
2379745549c8SPaolo Bonzini         .name = TYPE_OBJECT,
2380745549c8SPaolo Bonzini         .instance_size = sizeof(Object),
23812f262e06SPaolo Bonzini         .instance_init = object_instance_init,
2382745549c8SPaolo Bonzini         .abstract = true,
2383745549c8SPaolo Bonzini     };
2384745549c8SPaolo Bonzini 
2385049cb3cfSPaolo Bonzini     type_interface = type_register_internal(&interface_info);
2386049cb3cfSPaolo Bonzini     type_register_internal(&object_info);
2387745549c8SPaolo Bonzini }
2388745549c8SPaolo Bonzini 
2389745549c8SPaolo Bonzini type_init(register_types)
2390