12f28d2ffSAnthony Liguori /* 22f28d2ffSAnthony Liguori * QEMU Object Model 32f28d2ffSAnthony Liguori * 42f28d2ffSAnthony Liguori * Copyright IBM, Corp. 2011 52f28d2ffSAnthony Liguori * 62f28d2ffSAnthony Liguori * Authors: 72f28d2ffSAnthony Liguori * Anthony Liguori <aliguori@us.ibm.com> 82f28d2ffSAnthony Liguori * 92f28d2ffSAnthony Liguori * This work is licensed under the terms of the GNU GPL, version 2 or later. 102f28d2ffSAnthony Liguori * See the COPYING file in the top-level directory. 112f28d2ffSAnthony Liguori */ 122f28d2ffSAnthony Liguori 139bbc853bSPeter Maydell #include "qemu/osdep.h" 14da34e65cSMarkus Armbruster #include "qapi/error.h" 1514cccb61SPaolo Bonzini #include "qom/object.h" 16a31bdae5SDaniel P. Berrange #include "qom/object_interfaces.h" 17f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 187b1b5d19SPaolo Bonzini #include "qapi/visitor.h" 191f21772dSHu Tao #include "qapi-visit.h" 20b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h" 21b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h" 227b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 23fa131d94SPaolo Bonzini #include "trace.h" 242f28d2ffSAnthony Liguori 257b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency 267b7b7d18SPaolo Bonzini * of the QOM core on QObject? */ 2714cccb61SPaolo Bonzini #include "qom/qom-qobject.h" 287b1b5d19SPaolo Bonzini #include "qapi/qmp/qobject.h" 297b1b5d19SPaolo Bonzini #include "qapi/qmp/qbool.h" 307b1b5d19SPaolo Bonzini #include "qapi/qmp/qint.h" 317b1b5d19SPaolo Bonzini #include "qapi/qmp/qstring.h" 327b7b7d18SPaolo Bonzini 332f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 342f28d2ffSAnthony Liguori 352f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 362f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 372f28d2ffSAnthony Liguori 382f28d2ffSAnthony Liguori struct InterfaceImpl 392f28d2ffSAnthony Liguori { 4033e95c63SAnthony Liguori const char *typename; 412f28d2ffSAnthony Liguori }; 422f28d2ffSAnthony Liguori 432f28d2ffSAnthony Liguori struct TypeImpl 442f28d2ffSAnthony Liguori { 452f28d2ffSAnthony Liguori const char *name; 462f28d2ffSAnthony Liguori 472f28d2ffSAnthony Liguori size_t class_size; 482f28d2ffSAnthony Liguori 492f28d2ffSAnthony Liguori size_t instance_size; 502f28d2ffSAnthony Liguori 512f28d2ffSAnthony Liguori void (*class_init)(ObjectClass *klass, void *data); 523b50e311SPaolo Bonzini void (*class_base_init)(ObjectClass *klass, void *data); 532f28d2ffSAnthony Liguori void (*class_finalize)(ObjectClass *klass, void *data); 542f28d2ffSAnthony Liguori 552f28d2ffSAnthony Liguori void *class_data; 562f28d2ffSAnthony Liguori 572f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 588231c2ddSEduardo Habkost void (*instance_post_init)(Object *obj); 592f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 602f28d2ffSAnthony Liguori 612f28d2ffSAnthony Liguori bool abstract; 622f28d2ffSAnthony Liguori 632f28d2ffSAnthony Liguori const char *parent; 642f28d2ffSAnthony Liguori TypeImpl *parent_type; 652f28d2ffSAnthony Liguori 662f28d2ffSAnthony Liguori ObjectClass *class; 672f28d2ffSAnthony Liguori 682f28d2ffSAnthony Liguori int num_interfaces; 692f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 702f28d2ffSAnthony Liguori }; 712f28d2ffSAnthony Liguori 729970bd88SPaolo Bonzini static Type type_interface; 739970bd88SPaolo Bonzini 742f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 752f28d2ffSAnthony Liguori { 762f28d2ffSAnthony Liguori static GHashTable *type_table; 772f28d2ffSAnthony Liguori 782f28d2ffSAnthony Liguori if (type_table == NULL) { 792f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 802f28d2ffSAnthony Liguori } 812f28d2ffSAnthony Liguori 822f28d2ffSAnthony Liguori return type_table; 832f28d2ffSAnthony Liguori } 842f28d2ffSAnthony Liguori 85f54c19caSHervé Poussineau static bool enumerating_types; 86f54c19caSHervé Poussineau 872f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 882f28d2ffSAnthony Liguori { 89f54c19caSHervé Poussineau assert(!enumerating_types); 902f28d2ffSAnthony Liguori g_hash_table_insert(type_table_get(), (void *)ti->name, ti); 912f28d2ffSAnthony Liguori } 922f28d2ffSAnthony Liguori 932f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name) 942f28d2ffSAnthony Liguori { 952f28d2ffSAnthony Liguori return g_hash_table_lookup(type_table_get(), name); 962f28d2ffSAnthony Liguori } 972f28d2ffSAnthony Liguori 98b061dc41SPaolo Bonzini static TypeImpl *type_new(const TypeInfo *info) 992f28d2ffSAnthony Liguori { 1002f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 10133e95c63SAnthony Liguori int i; 1022f28d2ffSAnthony Liguori 1032f28d2ffSAnthony Liguori g_assert(info->name != NULL); 1042f28d2ffSAnthony Liguori 10573093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 10673093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 10773093354SAnthony Liguori abort(); 10873093354SAnthony Liguori } 10973093354SAnthony Liguori 1102f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 1112f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1122f28d2ffSAnthony Liguori 1132f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1142f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1152f28d2ffSAnthony Liguori 1162f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1173b50e311SPaolo Bonzini ti->class_base_init = info->class_base_init; 1182f28d2ffSAnthony Liguori ti->class_finalize = info->class_finalize; 1192f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1202f28d2ffSAnthony Liguori 1212f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1228231c2ddSEduardo Habkost ti->instance_post_init = info->instance_post_init; 1232f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1242f28d2ffSAnthony Liguori 1252f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1262f28d2ffSAnthony Liguori 12733e95c63SAnthony Liguori for (i = 0; info->interfaces && info->interfaces[i].type; i++) { 12833e95c63SAnthony Liguori ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); 1292f28d2ffSAnthony Liguori } 13033e95c63SAnthony Liguori ti->num_interfaces = i; 1312f28d2ffSAnthony Liguori 132b061dc41SPaolo Bonzini return ti; 133b061dc41SPaolo Bonzini } 1342f28d2ffSAnthony Liguori 135b061dc41SPaolo Bonzini static TypeImpl *type_register_internal(const TypeInfo *info) 136b061dc41SPaolo Bonzini { 137b061dc41SPaolo Bonzini TypeImpl *ti; 138b061dc41SPaolo Bonzini ti = type_new(info); 139b061dc41SPaolo Bonzini 140b061dc41SPaolo Bonzini type_table_add(ti); 1412f28d2ffSAnthony Liguori return ti; 1422f28d2ffSAnthony Liguori } 1432f28d2ffSAnthony Liguori 144049cb3cfSPaolo Bonzini TypeImpl *type_register(const TypeInfo *info) 145049cb3cfSPaolo Bonzini { 146049cb3cfSPaolo Bonzini assert(info->parent); 147049cb3cfSPaolo Bonzini return type_register_internal(info); 148049cb3cfSPaolo Bonzini } 149049cb3cfSPaolo Bonzini 1502f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1512f28d2ffSAnthony Liguori { 1522f28d2ffSAnthony Liguori return type_register(info); 1532f28d2ffSAnthony Liguori } 1542f28d2ffSAnthony Liguori 1552f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1562f28d2ffSAnthony Liguori { 1572f28d2ffSAnthony Liguori if (name == NULL) { 1582f28d2ffSAnthony Liguori return NULL; 1592f28d2ffSAnthony Liguori } 1602f28d2ffSAnthony Liguori 1612f28d2ffSAnthony Liguori return type_table_lookup(name); 1622f28d2ffSAnthony Liguori } 1632f28d2ffSAnthony Liguori 1642f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1652f28d2ffSAnthony Liguori { 1662f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1672f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 1682f28d2ffSAnthony Liguori g_assert(type->parent_type != NULL); 1692f28d2ffSAnthony Liguori } 1702f28d2ffSAnthony Liguori 1712f28d2ffSAnthony Liguori return type->parent_type; 1722f28d2ffSAnthony Liguori } 1732f28d2ffSAnthony Liguori 1742f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1752f28d2ffSAnthony Liguori { 1762f28d2ffSAnthony Liguori return (type->parent != NULL); 1772f28d2ffSAnthony Liguori } 1782f28d2ffSAnthony Liguori 1792f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1802f28d2ffSAnthony Liguori { 1812f28d2ffSAnthony Liguori if (ti->class_size) { 1822f28d2ffSAnthony Liguori return ti->class_size; 1832f28d2ffSAnthony Liguori } 1842f28d2ffSAnthony Liguori 1852f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 1862f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 1872f28d2ffSAnthony Liguori } 1882f28d2ffSAnthony Liguori 1892f28d2ffSAnthony Liguori return sizeof(ObjectClass); 1902f28d2ffSAnthony Liguori } 1912f28d2ffSAnthony Liguori 192aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti) 193aca59af6SIgor Mitsyanko { 194aca59af6SIgor Mitsyanko if (ti->instance_size) { 195aca59af6SIgor Mitsyanko return ti->instance_size; 196aca59af6SIgor Mitsyanko } 197aca59af6SIgor Mitsyanko 198aca59af6SIgor Mitsyanko if (type_has_parent(ti)) { 199aca59af6SIgor Mitsyanko return type_object_get_size(type_get_parent(ti)); 200aca59af6SIgor Mitsyanko } 201aca59af6SIgor Mitsyanko 202aca59af6SIgor Mitsyanko return 0; 203aca59af6SIgor Mitsyanko } 204aca59af6SIgor Mitsyanko 20533e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) 2062f28d2ffSAnthony Liguori { 20733e95c63SAnthony Liguori assert(target_type); 2082f28d2ffSAnthony Liguori 209b30d8054SCao jin /* Check if target_type is a direct ancestor of type */ 21033e95c63SAnthony Liguori while (type) { 21133e95c63SAnthony Liguori if (type == target_type) { 21233e95c63SAnthony Liguori return true; 21333e95c63SAnthony Liguori } 21433e95c63SAnthony Liguori 21533e95c63SAnthony Liguori type = type_get_parent(type); 21633e95c63SAnthony Liguori } 21733e95c63SAnthony Liguori 21833e95c63SAnthony Liguori return false; 21933e95c63SAnthony Liguori } 22033e95c63SAnthony Liguori 22133e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti); 22233e95c63SAnthony Liguori 223b061dc41SPaolo Bonzini static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, 224b061dc41SPaolo Bonzini TypeImpl *parent_type) 22533e95c63SAnthony Liguori { 22633e95c63SAnthony Liguori InterfaceClass *new_iface; 22733e95c63SAnthony Liguori TypeInfo info = { }; 22833e95c63SAnthony Liguori TypeImpl *iface_impl; 22933e95c63SAnthony Liguori 230b061dc41SPaolo Bonzini info.parent = parent_type->name; 231b061dc41SPaolo Bonzini info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name); 23233e95c63SAnthony Liguori info.abstract = true; 23333e95c63SAnthony Liguori 234b061dc41SPaolo Bonzini iface_impl = type_new(&info); 235b061dc41SPaolo Bonzini iface_impl->parent_type = parent_type; 23633e95c63SAnthony Liguori type_initialize(iface_impl); 23733e95c63SAnthony Liguori g_free((char *)info.name); 23833e95c63SAnthony Liguori 23933e95c63SAnthony Liguori new_iface = (InterfaceClass *)iface_impl->class; 24033e95c63SAnthony Liguori new_iface->concrete_class = ti->class; 241b061dc41SPaolo Bonzini new_iface->interface_type = interface_type; 24233e95c63SAnthony Liguori 24333e95c63SAnthony Liguori ti->class->interfaces = g_slist_append(ti->class->interfaces, 24433e95c63SAnthony Liguori iface_impl->class); 2452f28d2ffSAnthony Liguori } 2462f28d2ffSAnthony Liguori 24716bf7f52SDaniel P. Berrange static void object_property_free(gpointer data) 24816bf7f52SDaniel P. Berrange { 24916bf7f52SDaniel P. Berrange ObjectProperty *prop = data; 25016bf7f52SDaniel P. Berrange 25116bf7f52SDaniel P. Berrange g_free(prop->name); 25216bf7f52SDaniel P. Berrange g_free(prop->type); 25316bf7f52SDaniel P. Berrange g_free(prop->description); 25416bf7f52SDaniel P. Berrange g_free(prop); 25516bf7f52SDaniel P. Berrange } 25616bf7f52SDaniel P. Berrange 257ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti) 2582f28d2ffSAnthony Liguori { 259745549c8SPaolo Bonzini TypeImpl *parent; 2602f28d2ffSAnthony Liguori 2612f28d2ffSAnthony Liguori if (ti->class) { 2622f28d2ffSAnthony Liguori return; 2632f28d2ffSAnthony Liguori } 2642f28d2ffSAnthony Liguori 2652f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 266aca59af6SIgor Mitsyanko ti->instance_size = type_object_get_size(ti); 2672f28d2ffSAnthony Liguori 2682f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 2692f28d2ffSAnthony Liguori 270745549c8SPaolo Bonzini parent = type_get_parent(ti); 271745549c8SPaolo Bonzini if (parent) { 272ac451033SIgor Mitsyanko type_initialize(parent); 27333e95c63SAnthony Liguori GSList *e; 27433e95c63SAnthony Liguori int i; 2752f28d2ffSAnthony Liguori 2768438a135SAndreas Färber g_assert_cmpint(parent->class_size, <=, ti->class_size); 277745549c8SPaolo Bonzini memcpy(ti->class, parent->class, parent->class_size); 2783e407de4SPeter Crosthwaite ti->class->interfaces = NULL; 27916bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 28016bf7f52SDaniel P. Berrange g_str_hash, g_str_equal, g_free, object_property_free); 28133e95c63SAnthony Liguori 28233e95c63SAnthony Liguori for (e = parent->class->interfaces; e; e = e->next) { 283b061dc41SPaolo Bonzini InterfaceClass *iface = e->data; 284b061dc41SPaolo Bonzini ObjectClass *klass = OBJECT_CLASS(iface); 285b061dc41SPaolo Bonzini 286b061dc41SPaolo Bonzini type_initialize_interface(ti, iface->interface_type, klass->type); 28733e95c63SAnthony Liguori } 28833e95c63SAnthony Liguori 28933e95c63SAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 29033e95c63SAnthony Liguori TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); 29133e95c63SAnthony Liguori for (e = ti->class->interfaces; e; e = e->next) { 29233e95c63SAnthony Liguori TypeImpl *target_type = OBJECT_CLASS(e->data)->type; 29333e95c63SAnthony Liguori 29433e95c63SAnthony Liguori if (type_is_ancestor(target_type, t)) { 29533e95c63SAnthony Liguori break; 29633e95c63SAnthony Liguori } 29733e95c63SAnthony Liguori } 29833e95c63SAnthony Liguori 29933e95c63SAnthony Liguori if (e) { 30033e95c63SAnthony Liguori continue; 30133e95c63SAnthony Liguori } 30233e95c63SAnthony Liguori 303b061dc41SPaolo Bonzini type_initialize_interface(ti, t, t); 30433e95c63SAnthony Liguori } 30516bf7f52SDaniel P. Berrange } else { 30616bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 30716bf7f52SDaniel P. Berrange g_str_hash, g_str_equal, g_free, object_property_free); 308745549c8SPaolo Bonzini } 3092f28d2ffSAnthony Liguori 310745549c8SPaolo Bonzini ti->class->type = ti; 3113b50e311SPaolo Bonzini 3123b50e311SPaolo Bonzini while (parent) { 3133b50e311SPaolo Bonzini if (parent->class_base_init) { 3143b50e311SPaolo Bonzini parent->class_base_init(ti->class, ti->class_data); 3153b50e311SPaolo Bonzini } 3163b50e311SPaolo Bonzini parent = type_get_parent(parent); 3173b50e311SPaolo Bonzini } 3182f28d2ffSAnthony Liguori 3192f28d2ffSAnthony Liguori if (ti->class_init) { 3202f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 3212f28d2ffSAnthony Liguori } 3222f28d2ffSAnthony Liguori } 3232f28d2ffSAnthony Liguori 3242f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 3252f28d2ffSAnthony Liguori { 3262f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 3272f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 3282f28d2ffSAnthony Liguori } 3292f28d2ffSAnthony Liguori 3302f28d2ffSAnthony Liguori if (ti->instance_init) { 3312f28d2ffSAnthony Liguori ti->instance_init(obj); 3322f28d2ffSAnthony Liguori } 3332f28d2ffSAnthony Liguori } 3342f28d2ffSAnthony Liguori 3358231c2ddSEduardo Habkost static void object_post_init_with_type(Object *obj, TypeImpl *ti) 3368231c2ddSEduardo Habkost { 3378231c2ddSEduardo Habkost if (ti->instance_post_init) { 3388231c2ddSEduardo Habkost ti->instance_post_init(obj); 3398231c2ddSEduardo Habkost } 3408231c2ddSEduardo Habkost 3418231c2ddSEduardo Habkost if (type_has_parent(ti)) { 3428231c2ddSEduardo Habkost object_post_init_with_type(obj, type_get_parent(ti)); 3438231c2ddSEduardo Habkost } 3448231c2ddSEduardo Habkost } 3458231c2ddSEduardo Habkost 3465b9237f6SAndreas Färber void object_initialize_with_type(void *data, size_t size, TypeImpl *type) 3472f28d2ffSAnthony Liguori { 3482f28d2ffSAnthony Liguori Object *obj = data; 3492f28d2ffSAnthony Liguori 3502f28d2ffSAnthony Liguori g_assert(type != NULL); 351ac451033SIgor Mitsyanko type_initialize(type); 352aca59af6SIgor Mitsyanko 3538438a135SAndreas Färber g_assert_cmpint(type->instance_size, >=, sizeof(Object)); 3542f28d2ffSAnthony Liguori g_assert(type->abstract == false); 3558438a135SAndreas Färber g_assert_cmpint(size, >=, type->instance_size); 3562f28d2ffSAnthony Liguori 3572f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 3582f28d2ffSAnthony Liguori obj->class = type->class; 359764b6312SPaolo Bonzini object_ref(obj); 360b604a854SPavel Fedin obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal, 361b604a854SPavel Fedin NULL, object_property_free); 3622f28d2ffSAnthony Liguori object_init_with_type(obj, type); 3638231c2ddSEduardo Habkost object_post_init_with_type(obj, type); 3642f28d2ffSAnthony Liguori } 3652f28d2ffSAnthony Liguori 366213f0c4fSAndreas Färber void object_initialize(void *data, size_t size, const char *typename) 3672f28d2ffSAnthony Liguori { 3682f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 3692f28d2ffSAnthony Liguori 3705b9237f6SAndreas Färber object_initialize_with_type(data, size, type); 3712f28d2ffSAnthony Liguori } 3722f28d2ffSAnthony Liguori 3735d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop) 3745d9d3f47SAndreas Färber { 3755d9d3f47SAndreas Färber return strstart(prop->type, "child<", NULL); 3765d9d3f47SAndreas Färber } 3775d9d3f47SAndreas Färber 37857c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 37957c9fafeSAnthony Liguori { 380b604a854SPavel Fedin ObjectProperty *prop; 381b604a854SPavel Fedin GHashTableIter iter; 382b604a854SPavel Fedin gpointer key, value; 383b604a854SPavel Fedin bool released; 38457c9fafeSAnthony Liguori 385b604a854SPavel Fedin do { 386b604a854SPavel Fedin released = false; 387b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 388b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 389b604a854SPavel Fedin prop = value; 39057c9fafeSAnthony Liguori if (prop->release) { 39157c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 392b604a854SPavel Fedin prop->release = NULL; 393b604a854SPavel Fedin released = true; 394b604a854SPavel Fedin break; 39557c9fafeSAnthony Liguori } 396b604a854SPavel Fedin g_hash_table_iter_remove(&iter); 397b604a854SPavel Fedin } 398b604a854SPavel Fedin } while (released); 39957c9fafeSAnthony Liguori 400b604a854SPavel Fedin g_hash_table_unref(obj->properties); 40157c9fafeSAnthony Liguori } 40257c9fafeSAnthony Liguori 40357c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 40457c9fafeSAnthony Liguori { 40557c9fafeSAnthony Liguori ObjectProperty *prop; 406b604a854SPavel Fedin GHashTableIter iter; 407b604a854SPavel Fedin gpointer key, value; 40857c9fafeSAnthony Liguori 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; 4125d9d3f47SAndreas Färber if (object_property_is_child(prop) && prop->opaque == child) { 413b604a854SPavel Fedin if (prop->release) { 414b604a854SPavel Fedin prop->release(obj, prop->name, prop->opaque); 415b604a854SPavel Fedin prop->release = NULL; 416b604a854SPavel Fedin } 417b604a854SPavel Fedin break; 418b604a854SPavel Fedin } 419b604a854SPavel Fedin } 420b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 421b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 422b604a854SPavel Fedin prop = value; 423b604a854SPavel Fedin if (object_property_is_child(prop) && prop->opaque == child) { 424b604a854SPavel Fedin g_hash_table_iter_remove(&iter); 4256c1fdcf9SPaolo Bonzini break; 42657c9fafeSAnthony Liguori } 42757c9fafeSAnthony Liguori } 42857c9fafeSAnthony Liguori } 42957c9fafeSAnthony Liguori 43057c9fafeSAnthony Liguori void object_unparent(Object *obj) 43157c9fafeSAnthony Liguori { 432e998fa8dSMichael S. Tsirkin if (obj->parent) { 433e998fa8dSMichael S. Tsirkin object_property_del_child(obj->parent, obj, NULL); 434e998fa8dSMichael S. Tsirkin } 43557c9fafeSAnthony Liguori } 43657c9fafeSAnthony Liguori 4372f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 4382f28d2ffSAnthony Liguori { 4392f28d2ffSAnthony Liguori if (type->instance_finalize) { 4402f28d2ffSAnthony Liguori type->instance_finalize(obj); 4412f28d2ffSAnthony Liguori } 4422f28d2ffSAnthony Liguori 4432f28d2ffSAnthony Liguori if (type_has_parent(type)) { 4442f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 4452f28d2ffSAnthony Liguori } 4462f28d2ffSAnthony Liguori } 4472f28d2ffSAnthony Liguori 448339c2708SPaolo Bonzini static void object_finalize(void *data) 4492f28d2ffSAnthony Liguori { 4502f28d2ffSAnthony Liguori Object *obj = data; 4512f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 4522f28d2ffSAnthony Liguori 45357c9fafeSAnthony Liguori object_property_del_all(obj); 45476a6e1ccSPaolo Bonzini object_deinit(obj, ti); 455db85b575SAnthony Liguori 4568438a135SAndreas Färber g_assert_cmpint(obj->ref, ==, 0); 457fde9bf44SPaolo Bonzini if (obj->free) { 458fde9bf44SPaolo Bonzini obj->free(obj); 459fde9bf44SPaolo Bonzini } 4602f28d2ffSAnthony Liguori } 4612f28d2ffSAnthony Liguori 4622f28d2ffSAnthony Liguori Object *object_new_with_type(Type type) 4632f28d2ffSAnthony Liguori { 4642f28d2ffSAnthony Liguori Object *obj; 4652f28d2ffSAnthony Liguori 4662f28d2ffSAnthony Liguori g_assert(type != NULL); 467ac451033SIgor Mitsyanko type_initialize(type); 4682f28d2ffSAnthony Liguori 4692f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 4705b9237f6SAndreas Färber object_initialize_with_type(obj, type->instance_size, type); 471fde9bf44SPaolo Bonzini obj->free = g_free; 4722f28d2ffSAnthony Liguori 4732f28d2ffSAnthony Liguori return obj; 4742f28d2ffSAnthony Liguori } 4752f28d2ffSAnthony Liguori 4762f28d2ffSAnthony Liguori Object *object_new(const char *typename) 4772f28d2ffSAnthony Liguori { 4782f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 4792f28d2ffSAnthony Liguori 4802f28d2ffSAnthony Liguori return object_new_with_type(ti); 4812f28d2ffSAnthony Liguori } 4822f28d2ffSAnthony Liguori 483a31bdae5SDaniel P. Berrange 484a31bdae5SDaniel P. Berrange Object *object_new_with_props(const char *typename, 485a31bdae5SDaniel P. Berrange Object *parent, 486a31bdae5SDaniel P. Berrange const char *id, 487a31bdae5SDaniel P. Berrange Error **errp, 488a31bdae5SDaniel P. Berrange ...) 489a31bdae5SDaniel P. Berrange { 490a31bdae5SDaniel P. Berrange va_list vargs; 491a31bdae5SDaniel P. Berrange Object *obj; 492a31bdae5SDaniel P. Berrange 493a31bdae5SDaniel P. Berrange va_start(vargs, errp); 494a31bdae5SDaniel P. Berrange obj = object_new_with_propv(typename, parent, id, errp, vargs); 495a31bdae5SDaniel P. Berrange va_end(vargs); 496a31bdae5SDaniel P. Berrange 497a31bdae5SDaniel P. Berrange return obj; 498a31bdae5SDaniel P. Berrange } 499a31bdae5SDaniel P. Berrange 500a31bdae5SDaniel P. Berrange 501a31bdae5SDaniel P. Berrange Object *object_new_with_propv(const char *typename, 502a31bdae5SDaniel P. Berrange Object *parent, 503a31bdae5SDaniel P. Berrange const char *id, 504a31bdae5SDaniel P. Berrange Error **errp, 505a31bdae5SDaniel P. Berrange va_list vargs) 506a31bdae5SDaniel P. Berrange { 507a31bdae5SDaniel P. Berrange Object *obj; 508a31bdae5SDaniel P. Berrange ObjectClass *klass; 509a31bdae5SDaniel P. Berrange Error *local_err = NULL; 510a31bdae5SDaniel P. Berrange 511a31bdae5SDaniel P. Berrange klass = object_class_by_name(typename); 512a31bdae5SDaniel P. Berrange if (!klass) { 513a31bdae5SDaniel P. Berrange error_setg(errp, "invalid object type: %s", typename); 514a31bdae5SDaniel P. Berrange return NULL; 515a31bdae5SDaniel P. Berrange } 516a31bdae5SDaniel P. Berrange 517a31bdae5SDaniel P. Berrange if (object_class_is_abstract(klass)) { 518a31bdae5SDaniel P. Berrange error_setg(errp, "object type '%s' is abstract", typename); 519a31bdae5SDaniel P. Berrange return NULL; 520a31bdae5SDaniel P. Berrange } 521a31bdae5SDaniel P. Berrange obj = object_new(typename); 522a31bdae5SDaniel P. Berrange 523a31bdae5SDaniel P. Berrange if (object_set_propv(obj, &local_err, vargs) < 0) { 524a31bdae5SDaniel P. Berrange goto error; 525a31bdae5SDaniel P. Berrange } 526a31bdae5SDaniel P. Berrange 527a31bdae5SDaniel P. Berrange object_property_add_child(parent, id, obj, &local_err); 528a31bdae5SDaniel P. Berrange if (local_err) { 529a31bdae5SDaniel P. Berrange goto error; 530a31bdae5SDaniel P. Berrange } 531a31bdae5SDaniel P. Berrange 532a31bdae5SDaniel P. Berrange if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) { 533a31bdae5SDaniel P. Berrange user_creatable_complete(obj, &local_err); 534a31bdae5SDaniel P. Berrange if (local_err) { 535a31bdae5SDaniel P. Berrange object_unparent(obj); 536a31bdae5SDaniel P. Berrange goto error; 537a31bdae5SDaniel P. Berrange } 538a31bdae5SDaniel P. Berrange } 539a31bdae5SDaniel P. Berrange 540a31bdae5SDaniel P. Berrange object_unref(OBJECT(obj)); 541a31bdae5SDaniel P. Berrange return obj; 542a31bdae5SDaniel P. Berrange 543a31bdae5SDaniel P. Berrange error: 544a31bdae5SDaniel P. Berrange if (local_err) { 545a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 546a31bdae5SDaniel P. Berrange } 547a31bdae5SDaniel P. Berrange object_unref(obj); 548a31bdae5SDaniel P. Berrange return NULL; 549a31bdae5SDaniel P. Berrange } 550a31bdae5SDaniel P. Berrange 551a31bdae5SDaniel P. Berrange 552a31bdae5SDaniel P. Berrange int object_set_props(Object *obj, 553a31bdae5SDaniel P. Berrange Error **errp, 554a31bdae5SDaniel P. Berrange ...) 555a31bdae5SDaniel P. Berrange { 556a31bdae5SDaniel P. Berrange va_list vargs; 557a31bdae5SDaniel P. Berrange int ret; 558a31bdae5SDaniel P. Berrange 559a31bdae5SDaniel P. Berrange va_start(vargs, errp); 560a31bdae5SDaniel P. Berrange ret = object_set_propv(obj, errp, vargs); 561a31bdae5SDaniel P. Berrange va_end(vargs); 562a31bdae5SDaniel P. Berrange 563a31bdae5SDaniel P. Berrange return ret; 564a31bdae5SDaniel P. Berrange } 565a31bdae5SDaniel P. Berrange 566a31bdae5SDaniel P. Berrange 567a31bdae5SDaniel P. Berrange int object_set_propv(Object *obj, 568a31bdae5SDaniel P. Berrange Error **errp, 569a31bdae5SDaniel P. Berrange va_list vargs) 570a31bdae5SDaniel P. Berrange { 571a31bdae5SDaniel P. Berrange const char *propname; 572a31bdae5SDaniel P. Berrange Error *local_err = NULL; 573a31bdae5SDaniel P. Berrange 574a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 575a31bdae5SDaniel P. Berrange while (propname != NULL) { 576a31bdae5SDaniel P. Berrange const char *value = va_arg(vargs, char *); 577a31bdae5SDaniel P. Berrange 578a31bdae5SDaniel P. Berrange g_assert(value != NULL); 579a31bdae5SDaniel P. Berrange object_property_parse(obj, value, propname, &local_err); 580a31bdae5SDaniel P. Berrange if (local_err) { 581a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 582a31bdae5SDaniel P. Berrange return -1; 583a31bdae5SDaniel P. Berrange } 584a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 585a31bdae5SDaniel P. Berrange } 586a31bdae5SDaniel P. Berrange 587a31bdae5SDaniel P. Berrange return 0; 588a31bdae5SDaniel P. Berrange } 589a31bdae5SDaniel P. Berrange 590a31bdae5SDaniel P. Berrange 5912f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 5922f28d2ffSAnthony Liguori { 593b7f43fe4SPaolo Bonzini if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { 594acc4af3fSPaolo Bonzini return obj; 595acc4af3fSPaolo Bonzini } 596acc4af3fSPaolo Bonzini 5972f28d2ffSAnthony Liguori return NULL; 5982f28d2ffSAnthony Liguori } 5992f28d2ffSAnthony Liguori 600be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename, 601be17f18bSPaolo Bonzini const char *file, int line, const char *func) 6022f28d2ffSAnthony Liguori { 603fa131d94SPaolo Bonzini trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", 604fa131d94SPaolo Bonzini typename, file, line, func); 605fa131d94SPaolo Bonzini 6063556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG 60703587328SAnthony Liguori int i; 60803587328SAnthony Liguori Object *inst; 60903587328SAnthony Liguori 61095916abcSPeter Crosthwaite for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { 6110ab4c94cSPeter Crosthwaite if (obj->class->object_cast_cache[i] == typename) { 61203587328SAnthony Liguori goto out; 61303587328SAnthony Liguori } 61403587328SAnthony Liguori } 61503587328SAnthony Liguori 61603587328SAnthony Liguori inst = object_dynamic_cast(obj, typename); 6172f28d2ffSAnthony Liguori 618b7f43fe4SPaolo Bonzini if (!inst && obj) { 619be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 620be17f18bSPaolo Bonzini file, line, func, obj, typename); 6212f28d2ffSAnthony Liguori abort(); 6222f28d2ffSAnthony Liguori } 6232f28d2ffSAnthony Liguori 6243556c233SPaolo Bonzini assert(obj == inst); 62503587328SAnthony Liguori 62695916abcSPeter Crosthwaite if (obj && obj == inst) { 62703587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 6280ab4c94cSPeter Crosthwaite obj->class->object_cast_cache[i - 1] = 6290ab4c94cSPeter Crosthwaite obj->class->object_cast_cache[i]; 63003587328SAnthony Liguori } 6310ab4c94cSPeter Crosthwaite obj->class->object_cast_cache[i - 1] = typename; 63203587328SAnthony Liguori } 63303587328SAnthony Liguori 63403587328SAnthony Liguori out: 6353556c233SPaolo Bonzini #endif 6363556c233SPaolo Bonzini return obj; 6372f28d2ffSAnthony Liguori } 6382f28d2ffSAnthony Liguori 6392f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 6402f28d2ffSAnthony Liguori const char *typename) 6412f28d2ffSAnthony Liguori { 64233e95c63SAnthony Liguori ObjectClass *ret = NULL; 643bf0fda34SPaolo Bonzini TypeImpl *target_type; 644bf0fda34SPaolo Bonzini TypeImpl *type; 6452f28d2ffSAnthony Liguori 646bf0fda34SPaolo Bonzini if (!class) { 647bf0fda34SPaolo Bonzini return NULL; 648bf0fda34SPaolo Bonzini } 649bf0fda34SPaolo Bonzini 650793c96b5SPaolo Bonzini /* A simple fast path that can trigger a lot for leaf classes. */ 651bf0fda34SPaolo Bonzini type = class->type; 652793c96b5SPaolo Bonzini if (type->name == typename) { 653793c96b5SPaolo Bonzini return class; 654793c96b5SPaolo Bonzini } 655793c96b5SPaolo Bonzini 656bf0fda34SPaolo Bonzini target_type = type_get_by_name(typename); 6579ab880b3SAlexander Graf if (!target_type) { 6589ab880b3SAlexander Graf /* target class type unknown, so fail the cast */ 6599ab880b3SAlexander Graf return NULL; 6609ab880b3SAlexander Graf } 6619ab880b3SAlexander Graf 66200e2ceaeSPeter Crosthwaite if (type->class->interfaces && 66300e2ceaeSPeter Crosthwaite type_is_ancestor(target_type, type_interface)) { 66433e95c63SAnthony Liguori int found = 0; 66533e95c63SAnthony Liguori GSList *i; 66633e95c63SAnthony Liguori 66733e95c63SAnthony Liguori for (i = class->interfaces; i; i = i->next) { 66833e95c63SAnthony Liguori ObjectClass *target_class = i->data; 66933e95c63SAnthony Liguori 67033e95c63SAnthony Liguori if (type_is_ancestor(target_class->type, target_type)) { 67133e95c63SAnthony Liguori ret = target_class; 67233e95c63SAnthony Liguori found++; 67333e95c63SAnthony Liguori } 6742f28d2ffSAnthony Liguori } 6752f28d2ffSAnthony Liguori 67633e95c63SAnthony Liguori /* The match was ambiguous, don't allow a cast */ 67733e95c63SAnthony Liguori if (found > 1) { 67833e95c63SAnthony Liguori ret = NULL; 67933e95c63SAnthony Liguori } 68033e95c63SAnthony Liguori } else if (type_is_ancestor(type, target_type)) { 68133e95c63SAnthony Liguori ret = class; 6822f28d2ffSAnthony Liguori } 6832f28d2ffSAnthony Liguori 68433e95c63SAnthony Liguori return ret; 6852f28d2ffSAnthony Liguori } 6862f28d2ffSAnthony Liguori 6872f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 688be17f18bSPaolo Bonzini const char *typename, 689be17f18bSPaolo Bonzini const char *file, int line, 690be17f18bSPaolo Bonzini const char *func) 6912f28d2ffSAnthony Liguori { 692fa131d94SPaolo Bonzini ObjectClass *ret; 6932f28d2ffSAnthony Liguori 694fa131d94SPaolo Bonzini trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", 695fa131d94SPaolo Bonzini typename, file, line, func); 696fa131d94SPaolo Bonzini 69703587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 69803587328SAnthony Liguori int i; 69903587328SAnthony Liguori 7009d6a3d58SPeter Crosthwaite for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { 7010ab4c94cSPeter Crosthwaite if (class->class_cast_cache[i] == typename) { 70203587328SAnthony Liguori ret = class; 70303587328SAnthony Liguori goto out; 70403587328SAnthony Liguori } 70503587328SAnthony Liguori } 70603587328SAnthony Liguori #else 7079d6a3d58SPeter Crosthwaite if (!class || !class->interfaces) { 7083556c233SPaolo Bonzini return class; 7093556c233SPaolo Bonzini } 7103556c233SPaolo Bonzini #endif 7113556c233SPaolo Bonzini 712fa131d94SPaolo Bonzini ret = object_class_dynamic_cast(class, typename); 713bf0fda34SPaolo Bonzini if (!ret && class) { 714be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 715be17f18bSPaolo Bonzini file, line, func, class, typename); 7162f28d2ffSAnthony Liguori abort(); 7172f28d2ffSAnthony Liguori } 7182f28d2ffSAnthony Liguori 71903587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 7209d6a3d58SPeter Crosthwaite if (class && ret == class) { 72103587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 7220ab4c94cSPeter Crosthwaite class->class_cast_cache[i - 1] = class->class_cast_cache[i]; 72303587328SAnthony Liguori } 7240ab4c94cSPeter Crosthwaite class->class_cast_cache[i - 1] = typename; 72503587328SAnthony Liguori } 72603587328SAnthony Liguori out: 72703587328SAnthony Liguori #endif 7282f28d2ffSAnthony Liguori return ret; 7292f28d2ffSAnthony Liguori } 7302f28d2ffSAnthony Liguori 7312f28d2ffSAnthony Liguori const char *object_get_typename(Object *obj) 7322f28d2ffSAnthony Liguori { 7332f28d2ffSAnthony Liguori return obj->class->type->name; 7342f28d2ffSAnthony Liguori } 7352f28d2ffSAnthony Liguori 7362f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 7372f28d2ffSAnthony Liguori { 7382f28d2ffSAnthony Liguori return obj->class; 7392f28d2ffSAnthony Liguori } 7402f28d2ffSAnthony Liguori 74117862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass) 74217862378SAndreas Färber { 74317862378SAndreas Färber return klass->type->abstract; 74417862378SAndreas Färber } 74517862378SAndreas Färber 7462f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 7472f28d2ffSAnthony Liguori { 7482f28d2ffSAnthony Liguori return klass->type->name; 7492f28d2ffSAnthony Liguori } 7502f28d2ffSAnthony Liguori 7512f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 7522f28d2ffSAnthony Liguori { 7532f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 7542f28d2ffSAnthony Liguori 7552f28d2ffSAnthony Liguori if (!type) { 7562f28d2ffSAnthony Liguori return NULL; 7572f28d2ffSAnthony Liguori } 7582f28d2ffSAnthony Liguori 759ac451033SIgor Mitsyanko type_initialize(type); 7602f28d2ffSAnthony Liguori 7612f28d2ffSAnthony Liguori return type->class; 7622f28d2ffSAnthony Liguori } 7632f28d2ffSAnthony Liguori 764e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class) 765e7cce67fSPaolo Bonzini { 766e7cce67fSPaolo Bonzini TypeImpl *type = type_get_parent(class->type); 767e7cce67fSPaolo Bonzini 768e7cce67fSPaolo Bonzini if (!type) { 769e7cce67fSPaolo Bonzini return NULL; 770e7cce67fSPaolo Bonzini } 771e7cce67fSPaolo Bonzini 772e7cce67fSPaolo Bonzini type_initialize(type); 773e7cce67fSPaolo Bonzini 774e7cce67fSPaolo Bonzini return type->class; 775e7cce67fSPaolo Bonzini } 776e7cce67fSPaolo Bonzini 7772f28d2ffSAnthony Liguori typedef struct OCFData 7782f28d2ffSAnthony Liguori { 7792f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 78093c511a1SAnthony Liguori const char *implements_type; 78193c511a1SAnthony Liguori bool include_abstract; 7822f28d2ffSAnthony Liguori void *opaque; 7832f28d2ffSAnthony Liguori } OCFData; 7842f28d2ffSAnthony Liguori 7852f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 7862f28d2ffSAnthony Liguori gpointer opaque) 7872f28d2ffSAnthony Liguori { 7882f28d2ffSAnthony Liguori OCFData *data = opaque; 7892f28d2ffSAnthony Liguori TypeImpl *type = value; 79093c511a1SAnthony Liguori ObjectClass *k; 7912f28d2ffSAnthony Liguori 792ac451033SIgor Mitsyanko type_initialize(type); 79393c511a1SAnthony Liguori k = type->class; 7942f28d2ffSAnthony Liguori 79593c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 79693c511a1SAnthony Liguori return; 79793c511a1SAnthony Liguori } 79893c511a1SAnthony Liguori 79993c511a1SAnthony Liguori if (data->implements_type && 80093c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 80193c511a1SAnthony Liguori return; 80293c511a1SAnthony Liguori } 80393c511a1SAnthony Liguori 80493c511a1SAnthony Liguori data->fn(k, data->opaque); 8052f28d2ffSAnthony Liguori } 8062f28d2ffSAnthony Liguori 8072f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 80893c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 8092f28d2ffSAnthony Liguori void *opaque) 8102f28d2ffSAnthony Liguori { 81193c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 8122f28d2ffSAnthony Liguori 813f54c19caSHervé Poussineau enumerating_types = true; 8142f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 815f54c19caSHervé Poussineau enumerating_types = false; 8162f28d2ffSAnthony Liguori } 81757c9fafeSAnthony Liguori 818d714b8deSPeter Crosthwaite static int do_object_child_foreach(Object *obj, 819d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 820d714b8deSPeter Crosthwaite void *opaque, bool recurse) 82132efc535SPaolo Bonzini { 822b604a854SPavel Fedin GHashTableIter iter; 823b604a854SPavel Fedin ObjectProperty *prop; 82432efc535SPaolo Bonzini int ret = 0; 82532efc535SPaolo Bonzini 826b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 827b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 82832efc535SPaolo Bonzini if (object_property_is_child(prop)) { 829d714b8deSPeter Crosthwaite Object *child = prop->opaque; 830d714b8deSPeter Crosthwaite 831d714b8deSPeter Crosthwaite ret = fn(child, opaque); 83232efc535SPaolo Bonzini if (ret != 0) { 83332efc535SPaolo Bonzini break; 83432efc535SPaolo Bonzini } 835d714b8deSPeter Crosthwaite if (recurse) { 836d714b8deSPeter Crosthwaite do_object_child_foreach(child, fn, opaque, true); 837d714b8deSPeter Crosthwaite } 83832efc535SPaolo Bonzini } 83932efc535SPaolo Bonzini } 84032efc535SPaolo Bonzini return ret; 84132efc535SPaolo Bonzini } 84232efc535SPaolo Bonzini 843d714b8deSPeter Crosthwaite int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), 844d714b8deSPeter Crosthwaite void *opaque) 845d714b8deSPeter Crosthwaite { 846d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, false); 847d714b8deSPeter Crosthwaite } 848d714b8deSPeter Crosthwaite 849d714b8deSPeter Crosthwaite int object_child_foreach_recursive(Object *obj, 850d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 851d714b8deSPeter Crosthwaite void *opaque) 852d714b8deSPeter Crosthwaite { 853d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, true); 854d714b8deSPeter Crosthwaite } 855d714b8deSPeter Crosthwaite 856418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) 857418ba9e5SAndreas Färber { 858418ba9e5SAndreas Färber GSList **list = opaque; 859418ba9e5SAndreas Färber 860418ba9e5SAndreas Färber *list = g_slist_prepend(*list, klass); 861418ba9e5SAndreas Färber } 862418ba9e5SAndreas Färber 863418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type, 864418ba9e5SAndreas Färber bool include_abstract) 865418ba9e5SAndreas Färber { 866418ba9e5SAndreas Färber GSList *list = NULL; 867418ba9e5SAndreas Färber 868418ba9e5SAndreas Färber object_class_foreach(object_class_get_list_tramp, 869418ba9e5SAndreas Färber implements_type, include_abstract, &list); 870418ba9e5SAndreas Färber return list; 871418ba9e5SAndreas Färber } 872418ba9e5SAndreas Färber 87357c9fafeSAnthony Liguori void object_ref(Object *obj) 87457c9fafeSAnthony Liguori { 8758ffad850SPeter Crosthwaite if (!obj) { 8768ffad850SPeter Crosthwaite return; 8778ffad850SPeter Crosthwaite } 878f08c03f3SJan Kiszka atomic_inc(&obj->ref); 87957c9fafeSAnthony Liguori } 88057c9fafeSAnthony Liguori 88157c9fafeSAnthony Liguori void object_unref(Object *obj) 88257c9fafeSAnthony Liguori { 8838ffad850SPeter Crosthwaite if (!obj) { 8848ffad850SPeter Crosthwaite return; 8858ffad850SPeter Crosthwaite } 8868438a135SAndreas Färber g_assert_cmpint(obj->ref, >, 0); 88757c9fafeSAnthony Liguori 88857c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 889f08c03f3SJan Kiszka if (atomic_fetch_dec(&obj->ref) == 1) { 89057c9fafeSAnthony Liguori object_finalize(obj); 89157c9fafeSAnthony Liguori } 89257c9fafeSAnthony Liguori } 89357c9fafeSAnthony Liguori 89464607d08SPaolo Bonzini ObjectProperty * 89564607d08SPaolo Bonzini object_property_add(Object *obj, const char *name, const char *type, 89657c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 89757c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 89857c9fafeSAnthony Liguori ObjectPropertyRelease *release, 89957c9fafeSAnthony Liguori void *opaque, Error **errp) 90057c9fafeSAnthony Liguori { 90154852b03SPeter Maydell ObjectProperty *prop; 90233965904SPeter Crosthwaite size_t name_len = strlen(name); 90333965904SPeter Crosthwaite 90433965904SPeter Crosthwaite if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { 90533965904SPeter Crosthwaite int i; 90633965904SPeter Crosthwaite ObjectProperty *ret; 90733965904SPeter Crosthwaite char *name_no_array = g_strdup(name); 90833965904SPeter Crosthwaite 90933965904SPeter Crosthwaite name_no_array[name_len - 3] = '\0'; 91033965904SPeter Crosthwaite for (i = 0; ; ++i) { 91133965904SPeter Crosthwaite char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); 91233965904SPeter Crosthwaite 91333965904SPeter Crosthwaite ret = object_property_add(obj, full_name, type, get, set, 91433965904SPeter Crosthwaite release, opaque, NULL); 91533965904SPeter Crosthwaite g_free(full_name); 91633965904SPeter Crosthwaite if (ret) { 91733965904SPeter Crosthwaite break; 91833965904SPeter Crosthwaite } 91933965904SPeter Crosthwaite } 92033965904SPeter Crosthwaite g_free(name_no_array); 92133965904SPeter Crosthwaite return ret; 92233965904SPeter Crosthwaite } 92354852b03SPeter Maydell 92416bf7f52SDaniel P. Berrange if (object_property_find(obj, name, NULL) != NULL) { 92554852b03SPeter Maydell error_setg(errp, "attempt to add duplicate property '%s'" 92654852b03SPeter Maydell " to object (type '%s')", name, 92754852b03SPeter Maydell object_get_typename(obj)); 92864607d08SPaolo Bonzini return NULL; 92954852b03SPeter Maydell } 93054852b03SPeter Maydell 93154852b03SPeter Maydell prop = g_malloc0(sizeof(*prop)); 93257c9fafeSAnthony Liguori 93357c9fafeSAnthony Liguori prop->name = g_strdup(name); 93457c9fafeSAnthony Liguori prop->type = g_strdup(type); 93557c9fafeSAnthony Liguori 93657c9fafeSAnthony Liguori prop->get = get; 93757c9fafeSAnthony Liguori prop->set = set; 93857c9fafeSAnthony Liguori prop->release = release; 93957c9fafeSAnthony Liguori prop->opaque = opaque; 94057c9fafeSAnthony Liguori 941b604a854SPavel Fedin g_hash_table_insert(obj->properties, prop->name, prop); 94264607d08SPaolo Bonzini return prop; 94357c9fafeSAnthony Liguori } 94457c9fafeSAnthony Liguori 94516bf7f52SDaniel P. Berrange ObjectProperty * 94616bf7f52SDaniel P. Berrange object_class_property_add(ObjectClass *klass, 94716bf7f52SDaniel P. Berrange const char *name, 94816bf7f52SDaniel P. Berrange const char *type, 94916bf7f52SDaniel P. Berrange ObjectPropertyAccessor *get, 95016bf7f52SDaniel P. Berrange ObjectPropertyAccessor *set, 95116bf7f52SDaniel P. Berrange ObjectPropertyRelease *release, 95216bf7f52SDaniel P. Berrange void *opaque, 95316bf7f52SDaniel P. Berrange Error **errp) 95416bf7f52SDaniel P. Berrange { 95516bf7f52SDaniel P. Berrange ObjectProperty *prop; 95616bf7f52SDaniel P. Berrange 95716bf7f52SDaniel P. Berrange if (object_class_property_find(klass, name, NULL) != NULL) { 95816bf7f52SDaniel P. Berrange error_setg(errp, "attempt to add duplicate property '%s'" 95916bf7f52SDaniel P. Berrange " to object (type '%s')", name, 96016bf7f52SDaniel P. Berrange object_class_get_name(klass)); 96116bf7f52SDaniel P. Berrange return NULL; 96216bf7f52SDaniel P. Berrange } 96316bf7f52SDaniel P. Berrange 96416bf7f52SDaniel P. Berrange prop = g_malloc0(sizeof(*prop)); 96516bf7f52SDaniel P. Berrange 96616bf7f52SDaniel P. Berrange prop->name = g_strdup(name); 96716bf7f52SDaniel P. Berrange prop->type = g_strdup(type); 96816bf7f52SDaniel P. Berrange 96916bf7f52SDaniel P. Berrange prop->get = get; 97016bf7f52SDaniel P. Berrange prop->set = set; 97116bf7f52SDaniel P. Berrange prop->release = release; 97216bf7f52SDaniel P. Berrange prop->opaque = opaque; 97316bf7f52SDaniel P. Berrange 97416bf7f52SDaniel P. Berrange g_hash_table_insert(klass->properties, g_strdup(name), prop); 97516bf7f52SDaniel P. Berrange 97616bf7f52SDaniel P. Berrange return prop; 97716bf7f52SDaniel P. Berrange } 97816bf7f52SDaniel P. Berrange 97989bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name, 98089bfe000SPaolo Bonzini Error **errp) 98157c9fafeSAnthony Liguori { 98257c9fafeSAnthony Liguori ObjectProperty *prop; 98316bf7f52SDaniel P. Berrange ObjectClass *klass = object_get_class(obj); 98416bf7f52SDaniel P. Berrange 98516bf7f52SDaniel P. Berrange prop = object_class_property_find(klass, name, NULL); 98616bf7f52SDaniel P. Berrange if (prop) { 98716bf7f52SDaniel P. Berrange return prop; 98816bf7f52SDaniel P. Berrange } 98957c9fafeSAnthony Liguori 990b604a854SPavel Fedin prop = g_hash_table_lookup(obj->properties, name); 991b604a854SPavel Fedin if (prop) { 99257c9fafeSAnthony Liguori return prop; 99357c9fafeSAnthony Liguori } 99457c9fafeSAnthony Liguori 995f231b88dSCole Robinson error_setg(errp, "Property '.%s' not found", name); 99657c9fafeSAnthony Liguori return NULL; 99757c9fafeSAnthony Liguori } 99857c9fafeSAnthony Liguori 9997746abd8SDaniel P. Berrange void object_property_iter_init(ObjectPropertyIterator *iter, 10007746abd8SDaniel P. Berrange Object *obj) 1001a00c9482SDaniel P. Berrange { 10027746abd8SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, obj->properties); 10037746abd8SDaniel P. Berrange iter->nextclass = object_get_class(obj); 1004a00c9482SDaniel P. Berrange } 1005a00c9482SDaniel P. Berrange 1006a00c9482SDaniel P. Berrange ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) 1007a00c9482SDaniel P. Berrange { 1008b604a854SPavel Fedin gpointer key, val; 100916bf7f52SDaniel P. Berrange while (!g_hash_table_iter_next(&iter->iter, &key, &val)) { 101016bf7f52SDaniel P. Berrange if (!iter->nextclass) { 1011b604a854SPavel Fedin return NULL; 1012a00c9482SDaniel P. Berrange } 101316bf7f52SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, iter->nextclass->properties); 101416bf7f52SDaniel P. Berrange iter->nextclass = object_class_get_parent(iter->nextclass); 101516bf7f52SDaniel P. Berrange } 1016b604a854SPavel Fedin return val; 1017a00c9482SDaniel P. Berrange } 1018a00c9482SDaniel P. Berrange 101916bf7f52SDaniel P. Berrange ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, 102016bf7f52SDaniel P. Berrange Error **errp) 102116bf7f52SDaniel P. Berrange { 102216bf7f52SDaniel P. Berrange ObjectProperty *prop; 102316bf7f52SDaniel P. Berrange ObjectClass *parent_klass; 102416bf7f52SDaniel P. Berrange 102516bf7f52SDaniel P. Berrange parent_klass = object_class_get_parent(klass); 102616bf7f52SDaniel P. Berrange if (parent_klass) { 102716bf7f52SDaniel P. Berrange prop = object_class_property_find(parent_klass, name, NULL); 102816bf7f52SDaniel P. Berrange if (prop) { 102916bf7f52SDaniel P. Berrange return prop; 103016bf7f52SDaniel P. Berrange } 103116bf7f52SDaniel P. Berrange } 103216bf7f52SDaniel P. Berrange 103316bf7f52SDaniel P. Berrange prop = g_hash_table_lookup(klass->properties, name); 103416bf7f52SDaniel P. Berrange if (!prop) { 103516bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 103616bf7f52SDaniel P. Berrange } 103716bf7f52SDaniel P. Berrange return prop; 103816bf7f52SDaniel P. Berrange } 103916bf7f52SDaniel P. Berrange 104057c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 104157c9fafeSAnthony Liguori { 1042b604a854SPavel Fedin ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); 1043b604a854SPavel Fedin 1044b604a854SPavel Fedin if (!prop) { 1045b604a854SPavel Fedin error_setg(errp, "Property '.%s' not found", name); 10460866aca1SAnthony Liguori return; 10470866aca1SAnthony Liguori } 104857c9fafeSAnthony Liguori 10490866aca1SAnthony Liguori if (prop->release) { 10500866aca1SAnthony Liguori prop->release(obj, name, prop->opaque); 10510866aca1SAnthony Liguori } 1052b604a854SPavel Fedin g_hash_table_remove(obj->properties, name); 105357c9fafeSAnthony Liguori } 105457c9fafeSAnthony Liguori 105557c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 105657c9fafeSAnthony Liguori Error **errp) 105757c9fafeSAnthony Liguori { 105889bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 105957c9fafeSAnthony Liguori if (prop == NULL) { 106057c9fafeSAnthony Liguori return; 106157c9fafeSAnthony Liguori } 106257c9fafeSAnthony Liguori 106357c9fafeSAnthony Liguori if (!prop->get) { 1064c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 106557c9fafeSAnthony Liguori } else { 1066d7bce999SEric Blake prop->get(obj, v, name, prop->opaque, errp); 106757c9fafeSAnthony Liguori } 106857c9fafeSAnthony Liguori } 106957c9fafeSAnthony Liguori 107057c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 107157c9fafeSAnthony Liguori Error **errp) 107257c9fafeSAnthony Liguori { 107389bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 107457c9fafeSAnthony Liguori if (prop == NULL) { 107557c9fafeSAnthony Liguori return; 107657c9fafeSAnthony Liguori } 107757c9fafeSAnthony Liguori 107857c9fafeSAnthony Liguori if (!prop->set) { 1079c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 108057c9fafeSAnthony Liguori } else { 1081d7bce999SEric Blake prop->set(obj, v, name, prop->opaque, errp); 108257c9fafeSAnthony Liguori } 108357c9fafeSAnthony Liguori } 108457c9fafeSAnthony Liguori 10857b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value, 10867b7b7d18SPaolo Bonzini const char *name, Error **errp) 10877b7b7d18SPaolo Bonzini { 10887b7b7d18SPaolo Bonzini QString *qstr = qstring_from_str(value); 10897b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qstr), name, errp); 10907b7b7d18SPaolo Bonzini 10917b7b7d18SPaolo Bonzini QDECREF(qstr); 10927b7b7d18SPaolo Bonzini } 10937b7b7d18SPaolo Bonzini 10947b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name, 10957b7b7d18SPaolo Bonzini Error **errp) 10967b7b7d18SPaolo Bonzini { 10977b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 10987b7b7d18SPaolo Bonzini QString *qstring; 10997b7b7d18SPaolo Bonzini char *retval; 11007b7b7d18SPaolo Bonzini 11017b7b7d18SPaolo Bonzini if (!ret) { 11027b7b7d18SPaolo Bonzini return NULL; 11037b7b7d18SPaolo Bonzini } 11047b7b7d18SPaolo Bonzini qstring = qobject_to_qstring(ret); 11057b7b7d18SPaolo Bonzini if (!qstring) { 1106c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); 11077b7b7d18SPaolo Bonzini retval = NULL; 11087b7b7d18SPaolo Bonzini } else { 11097b7b7d18SPaolo Bonzini retval = g_strdup(qstring_get_str(qstring)); 11107b7b7d18SPaolo Bonzini } 11117b7b7d18SPaolo Bonzini 11127b7b7d18SPaolo Bonzini QDECREF(qstring); 11137b7b7d18SPaolo Bonzini return retval; 11147b7b7d18SPaolo Bonzini } 11157b7b7d18SPaolo Bonzini 11161d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value, 11171d9c5a12SPaolo Bonzini const char *name, Error **errp) 11181d9c5a12SPaolo Bonzini { 1119d3c49316SPeter Crosthwaite if (value) { 11202d3aa28cSVlad Yasevich gchar *path = object_get_canonical_path(value); 11212d3aa28cSVlad Yasevich object_property_set_str(obj, path, name, errp); 11222d3aa28cSVlad Yasevich g_free(path); 1123d3c49316SPeter Crosthwaite } else { 1124d3c49316SPeter Crosthwaite object_property_set_str(obj, "", name, errp); 1125d3c49316SPeter Crosthwaite } 11261d9c5a12SPaolo Bonzini } 11271d9c5a12SPaolo Bonzini 11281d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name, 11291d9c5a12SPaolo Bonzini Error **errp) 11301d9c5a12SPaolo Bonzini { 11311d9c5a12SPaolo Bonzini char *str = object_property_get_str(obj, name, errp); 11321d9c5a12SPaolo Bonzini Object *target = NULL; 11331d9c5a12SPaolo Bonzini 11341d9c5a12SPaolo Bonzini if (str && *str) { 11351d9c5a12SPaolo Bonzini target = object_resolve_path(str, NULL); 11361d9c5a12SPaolo Bonzini if (!target) { 113775158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 113875158ebbSMarkus Armbruster "Device '%s' not found", str); 11391d9c5a12SPaolo Bonzini } 11401d9c5a12SPaolo Bonzini } 11411d9c5a12SPaolo Bonzini 11421d9c5a12SPaolo Bonzini g_free(str); 11431d9c5a12SPaolo Bonzini return target; 11441d9c5a12SPaolo Bonzini } 11451d9c5a12SPaolo Bonzini 11467b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value, 11477b7b7d18SPaolo Bonzini const char *name, Error **errp) 11487b7b7d18SPaolo Bonzini { 1149fc48ffc3SEric Blake QBool *qbool = qbool_from_bool(value); 11507b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qbool), name, errp); 11517b7b7d18SPaolo Bonzini 11527b7b7d18SPaolo Bonzini QDECREF(qbool); 11537b7b7d18SPaolo Bonzini } 11547b7b7d18SPaolo Bonzini 11557b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name, 11567b7b7d18SPaolo Bonzini Error **errp) 11577b7b7d18SPaolo Bonzini { 11587b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 11597b7b7d18SPaolo Bonzini QBool *qbool; 11607b7b7d18SPaolo Bonzini bool retval; 11617b7b7d18SPaolo Bonzini 11627b7b7d18SPaolo Bonzini if (!ret) { 11637b7b7d18SPaolo Bonzini return false; 11647b7b7d18SPaolo Bonzini } 11657b7b7d18SPaolo Bonzini qbool = qobject_to_qbool(ret); 11667b7b7d18SPaolo Bonzini if (!qbool) { 1167c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); 11687b7b7d18SPaolo Bonzini retval = false; 11697b7b7d18SPaolo Bonzini } else { 1170fc48ffc3SEric Blake retval = qbool_get_bool(qbool); 11717b7b7d18SPaolo Bonzini } 11727b7b7d18SPaolo Bonzini 11737b7b7d18SPaolo Bonzini QDECREF(qbool); 11747b7b7d18SPaolo Bonzini return retval; 11757b7b7d18SPaolo Bonzini } 11767b7b7d18SPaolo Bonzini 11777b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value, 11787b7b7d18SPaolo Bonzini const char *name, Error **errp) 11797b7b7d18SPaolo Bonzini { 11807b7b7d18SPaolo Bonzini QInt *qint = qint_from_int(value); 11817b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qint), name, errp); 11827b7b7d18SPaolo Bonzini 11837b7b7d18SPaolo Bonzini QDECREF(qint); 11847b7b7d18SPaolo Bonzini } 11857b7b7d18SPaolo Bonzini 11867b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name, 11877b7b7d18SPaolo Bonzini Error **errp) 11887b7b7d18SPaolo Bonzini { 11897b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 11907b7b7d18SPaolo Bonzini QInt *qint; 11917b7b7d18SPaolo Bonzini int64_t retval; 11927b7b7d18SPaolo Bonzini 11937b7b7d18SPaolo Bonzini if (!ret) { 11947b7b7d18SPaolo Bonzini return -1; 11957b7b7d18SPaolo Bonzini } 11967b7b7d18SPaolo Bonzini qint = qobject_to_qint(ret); 11977b7b7d18SPaolo Bonzini if (!qint) { 1198c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); 11997b7b7d18SPaolo Bonzini retval = -1; 12007b7b7d18SPaolo Bonzini } else { 12017b7b7d18SPaolo Bonzini retval = qint_get_int(qint); 12027b7b7d18SPaolo Bonzini } 12037b7b7d18SPaolo Bonzini 12047b7b7d18SPaolo Bonzini QDECREF(qint); 12057b7b7d18SPaolo Bonzini return retval; 12067b7b7d18SPaolo Bonzini } 12077b7b7d18SPaolo Bonzini 1208a8e3fbedSDaniel P. Berrange typedef struct EnumProperty { 1209a8e3fbedSDaniel P. Berrange const char * const *strings; 1210a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **); 1211a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **); 1212a8e3fbedSDaniel P. Berrange } EnumProperty; 1213a8e3fbedSDaniel P. Berrange 12141f21772dSHu Tao int object_property_get_enum(Object *obj, const char *name, 1215a3590dacSDaniel P. Berrange const char *typename, Error **errp) 12161f21772dSHu Tao { 12174715d42eSMarkus Armbruster Error *err = NULL; 12181f21772dSHu Tao StringOutputVisitor *sov; 12191f21772dSHu Tao StringInputVisitor *siv; 1220976620acSChen Fan char *str; 12211f21772dSHu Tao int ret; 1222a3590dacSDaniel P. Berrange ObjectProperty *prop = object_property_find(obj, name, errp); 1223a3590dacSDaniel P. Berrange EnumProperty *enumprop; 1224a3590dacSDaniel P. Berrange 1225a3590dacSDaniel P. Berrange if (prop == NULL) { 1226a3590dacSDaniel P. Berrange return 0; 1227a3590dacSDaniel P. Berrange } 1228a3590dacSDaniel P. Berrange 1229a3590dacSDaniel P. Berrange if (!g_str_equal(prop->type, typename)) { 1230a3590dacSDaniel P. Berrange error_setg(errp, "Property %s on %s is not '%s' enum type", 1231a3590dacSDaniel P. Berrange name, object_class_get_name( 1232a3590dacSDaniel P. Berrange object_get_class(obj)), typename); 1233a3590dacSDaniel P. Berrange return 0; 1234a3590dacSDaniel P. Berrange } 1235a3590dacSDaniel P. Berrange 1236a3590dacSDaniel P. Berrange enumprop = prop->opaque; 12371f21772dSHu Tao 12381f21772dSHu Tao sov = string_output_visitor_new(false); 12394715d42eSMarkus Armbruster object_property_get(obj, string_output_get_visitor(sov), name, &err); 12404715d42eSMarkus Armbruster if (err) { 12414715d42eSMarkus Armbruster error_propagate(errp, err); 12424715d42eSMarkus Armbruster string_output_visitor_cleanup(sov); 12434715d42eSMarkus Armbruster return 0; 12444715d42eSMarkus Armbruster } 1245976620acSChen Fan str = string_output_get_string(sov); 1246976620acSChen Fan siv = string_input_visitor_new(str); 12471f21772dSHu Tao string_output_visitor_cleanup(sov); 124851e72bc1SEric Blake visit_type_enum(string_input_get_visitor(siv), name, &ret, 1249337283dfSEric Blake enumprop->strings, errp); 1250976620acSChen Fan 1251976620acSChen Fan g_free(str); 12521f21772dSHu Tao string_input_visitor_cleanup(siv); 12531f21772dSHu Tao 12541f21772dSHu Tao return ret; 12551f21772dSHu Tao } 12561f21772dSHu Tao 12571f21772dSHu Tao void object_property_get_uint16List(Object *obj, const char *name, 12581f21772dSHu Tao uint16List **list, Error **errp) 12591f21772dSHu Tao { 12604715d42eSMarkus Armbruster Error *err = NULL; 12611f21772dSHu Tao StringOutputVisitor *ov; 12621f21772dSHu Tao StringInputVisitor *iv; 1263976620acSChen Fan char *str; 12641f21772dSHu Tao 12651f21772dSHu Tao ov = string_output_visitor_new(false); 12661f21772dSHu Tao object_property_get(obj, string_output_get_visitor(ov), 12674715d42eSMarkus Armbruster name, &err); 12684715d42eSMarkus Armbruster if (err) { 12694715d42eSMarkus Armbruster error_propagate(errp, err); 12704715d42eSMarkus Armbruster goto out; 12714715d42eSMarkus Armbruster } 1272976620acSChen Fan str = string_output_get_string(ov); 1273976620acSChen Fan iv = string_input_visitor_new(str); 127451e72bc1SEric Blake visit_type_uint16List(string_input_get_visitor(iv), NULL, list, errp); 1275976620acSChen Fan 1276976620acSChen Fan g_free(str); 12771f21772dSHu Tao string_input_visitor_cleanup(iv); 12784715d42eSMarkus Armbruster out: 12794715d42eSMarkus Armbruster string_output_visitor_cleanup(ov); 12801f21772dSHu Tao } 12811f21772dSHu Tao 1282b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string, 1283b2cd7deeSPaolo Bonzini const char *name, Error **errp) 1284b2cd7deeSPaolo Bonzini { 1285f8b7f1a8SEric Blake StringInputVisitor *siv; 1286f8b7f1a8SEric Blake siv = string_input_visitor_new(string); 1287f8b7f1a8SEric Blake object_property_set(obj, string_input_get_visitor(siv), name, errp); 1288b2cd7deeSPaolo Bonzini 1289f8b7f1a8SEric Blake string_input_visitor_cleanup(siv); 1290b2cd7deeSPaolo Bonzini } 1291b2cd7deeSPaolo Bonzini 12920b7593e0SPaolo Bonzini char *object_property_print(Object *obj, const char *name, bool human, 1293b2cd7deeSPaolo Bonzini Error **errp) 1294b2cd7deeSPaolo Bonzini { 1295f8b7f1a8SEric Blake StringOutputVisitor *sov; 12963a53009fSGonglei char *string = NULL; 12973a53009fSGonglei Error *local_err = NULL; 1298b2cd7deeSPaolo Bonzini 1299f8b7f1a8SEric Blake sov = string_output_visitor_new(human); 1300f8b7f1a8SEric Blake object_property_get(obj, string_output_get_visitor(sov), name, &local_err); 13013a53009fSGonglei if (local_err) { 13023a53009fSGonglei error_propagate(errp, local_err); 13033a53009fSGonglei goto out; 13043a53009fSGonglei } 13053a53009fSGonglei 1306f8b7f1a8SEric Blake string = string_output_get_string(sov); 13073a53009fSGonglei 13083a53009fSGonglei out: 1309f8b7f1a8SEric Blake string_output_visitor_cleanup(sov); 1310b2cd7deeSPaolo Bonzini return string; 1311b2cd7deeSPaolo Bonzini } 1312b2cd7deeSPaolo Bonzini 131357c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 131457c9fafeSAnthony Liguori { 131589bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 131657c9fafeSAnthony Liguori if (prop == NULL) { 131757c9fafeSAnthony Liguori return NULL; 131857c9fafeSAnthony Liguori } 131957c9fafeSAnthony Liguori 132057c9fafeSAnthony Liguori return prop->type; 132157c9fafeSAnthony Liguori } 132257c9fafeSAnthony Liguori 132357c9fafeSAnthony Liguori Object *object_get_root(void) 132457c9fafeSAnthony Liguori { 13258b45d447SAnthony Liguori static Object *root; 132657c9fafeSAnthony Liguori 13278b45d447SAnthony Liguori if (!root) { 13288b45d447SAnthony Liguori root = object_new("container"); 132957c9fafeSAnthony Liguori } 133057c9fafeSAnthony Liguori 13318b45d447SAnthony Liguori return root; 133257c9fafeSAnthony Liguori } 133357c9fafeSAnthony Liguori 1334bc2256c4SDaniel P. Berrange Object *object_get_objects_root(void) 1335bc2256c4SDaniel P. Berrange { 1336bc2256c4SDaniel P. Berrange return container_get(object_get_root(), "/objects"); 1337bc2256c4SDaniel P. Berrange } 1338bc2256c4SDaniel P. Berrange 1339d7bce999SEric Blake static void object_get_child_property(Object *obj, Visitor *v, 1340d7bce999SEric Blake const char *name, void *opaque, 1341d7bce999SEric Blake Error **errp) 134257c9fafeSAnthony Liguori { 134357c9fafeSAnthony Liguori Object *child = opaque; 134457c9fafeSAnthony Liguori gchar *path; 134557c9fafeSAnthony Liguori 134657c9fafeSAnthony Liguori path = object_get_canonical_path(child); 134751e72bc1SEric Blake visit_type_str(v, name, &path, errp); 134857c9fafeSAnthony Liguori g_free(path); 134957c9fafeSAnthony Liguori } 135057c9fafeSAnthony Liguori 135164607d08SPaolo Bonzini static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) 135264607d08SPaolo Bonzini { 135364607d08SPaolo Bonzini return opaque; 135464607d08SPaolo Bonzini } 135564607d08SPaolo Bonzini 1356db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name, 1357db85b575SAnthony Liguori void *opaque) 1358db85b575SAnthony Liguori { 1359db85b575SAnthony Liguori Object *child = opaque; 1360db85b575SAnthony Liguori 1361bffc687dSPaolo Bonzini if (child->class->unparent) { 1362bffc687dSPaolo Bonzini (child->class->unparent)(child); 1363bffc687dSPaolo Bonzini } 1364bffc687dSPaolo Bonzini child->parent = NULL; 1365db85b575SAnthony Liguori object_unref(child); 1366db85b575SAnthony Liguori } 1367db85b575SAnthony Liguori 136857c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 136957c9fafeSAnthony Liguori Object *child, Error **errp) 137057c9fafeSAnthony Liguori { 1371b0ed5e9fSPaolo Bonzini Error *local_err = NULL; 137257c9fafeSAnthony Liguori gchar *type; 137364607d08SPaolo Bonzini ObjectProperty *op; 137457c9fafeSAnthony Liguori 13758faa2f85SPeter Crosthwaite if (child->parent != NULL) { 13768faa2f85SPeter Crosthwaite error_setg(errp, "child object is already parented"); 13778faa2f85SPeter Crosthwaite return; 13788faa2f85SPeter Crosthwaite } 13798faa2f85SPeter Crosthwaite 138057c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 138157c9fafeSAnthony Liguori 138264607d08SPaolo Bonzini op = object_property_add(obj, name, type, object_get_child_property, NULL, 1383b0ed5e9fSPaolo Bonzini object_finalize_child_property, child, &local_err); 1384b0ed5e9fSPaolo Bonzini if (local_err) { 1385b0ed5e9fSPaolo Bonzini error_propagate(errp, local_err); 1386b0ed5e9fSPaolo Bonzini goto out; 1387b0ed5e9fSPaolo Bonzini } 138864607d08SPaolo Bonzini 138964607d08SPaolo Bonzini op->resolve = object_resolve_child_property; 139057c9fafeSAnthony Liguori object_ref(child); 139157c9fafeSAnthony Liguori child->parent = obj; 139257c9fafeSAnthony Liguori 1393b0ed5e9fSPaolo Bonzini out: 139457c9fafeSAnthony Liguori g_free(type); 139557c9fafeSAnthony Liguori } 139657c9fafeSAnthony Liguori 139739f72ef9SStefan Hajnoczi void object_property_allow_set_link(Object *obj, const char *name, 139839f72ef9SStefan Hajnoczi Object *val, Error **errp) 139939f72ef9SStefan Hajnoczi { 140039f72ef9SStefan Hajnoczi /* Allow the link to be set, always */ 140139f72ef9SStefan Hajnoczi } 140239f72ef9SStefan Hajnoczi 14039561fda8SStefan Hajnoczi typedef struct { 14049561fda8SStefan Hajnoczi Object **child; 140539f72ef9SStefan Hajnoczi void (*check)(Object *, const char *, Object *, Error **); 14069561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags; 14079561fda8SStefan Hajnoczi } LinkProperty; 14089561fda8SStefan Hajnoczi 1409d7bce999SEric Blake static void object_get_link_property(Object *obj, Visitor *v, 1410d7bce999SEric Blake const char *name, void *opaque, 1411d7bce999SEric Blake Error **errp) 141257c9fafeSAnthony Liguori { 14139561fda8SStefan Hajnoczi LinkProperty *lprop = opaque; 14149561fda8SStefan Hajnoczi Object **child = lprop->child; 141557c9fafeSAnthony Liguori gchar *path; 141657c9fafeSAnthony Liguori 141757c9fafeSAnthony Liguori if (*child) { 141857c9fafeSAnthony Liguori path = object_get_canonical_path(*child); 141951e72bc1SEric Blake visit_type_str(v, name, &path, errp); 142057c9fafeSAnthony Liguori g_free(path); 142157c9fafeSAnthony Liguori } else { 142257c9fafeSAnthony Liguori path = (gchar *)""; 142351e72bc1SEric Blake visit_type_str(v, name, &path, errp); 142457c9fafeSAnthony Liguori } 142557c9fafeSAnthony Liguori } 142657c9fafeSAnthony Liguori 1427f5ec6704SStefan Hajnoczi /* 1428f5ec6704SStefan Hajnoczi * object_resolve_link: 1429f5ec6704SStefan Hajnoczi * 1430f5ec6704SStefan Hajnoczi * Lookup an object and ensure its type matches the link property type. This 1431f5ec6704SStefan Hajnoczi * is similar to object_resolve_path() except type verification against the 1432f5ec6704SStefan Hajnoczi * link property is performed. 1433f5ec6704SStefan Hajnoczi * 1434f5ec6704SStefan Hajnoczi * Returns: The matched object or NULL on path lookup failures. 1435f5ec6704SStefan Hajnoczi */ 1436f5ec6704SStefan Hajnoczi static Object *object_resolve_link(Object *obj, const char *name, 1437f5ec6704SStefan Hajnoczi const char *path, Error **errp) 1438f5ec6704SStefan Hajnoczi { 1439f5ec6704SStefan Hajnoczi const char *type; 1440f5ec6704SStefan Hajnoczi gchar *target_type; 1441f5ec6704SStefan Hajnoczi bool ambiguous = false; 1442f5ec6704SStefan Hajnoczi Object *target; 1443f5ec6704SStefan Hajnoczi 1444f5ec6704SStefan Hajnoczi /* Go from link<FOO> to FOO. */ 1445f5ec6704SStefan Hajnoczi type = object_property_get_type(obj, name, NULL); 1446f5ec6704SStefan Hajnoczi target_type = g_strndup(&type[5], strlen(type) - 6); 1447f5ec6704SStefan Hajnoczi target = object_resolve_path_type(path, target_type, &ambiguous); 1448f5ec6704SStefan Hajnoczi 1449f5ec6704SStefan Hajnoczi if (ambiguous) { 1450455b0fdeSEric Blake error_setg(errp, "Path '%s' does not uniquely identify an object", 1451455b0fdeSEric Blake path); 1452f5ec6704SStefan Hajnoczi } else if (!target) { 1453f5ec6704SStefan Hajnoczi target = object_resolve_path(path, &ambiguous); 1454f5ec6704SStefan Hajnoczi if (target || ambiguous) { 1455c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); 1456f5ec6704SStefan Hajnoczi } else { 145775158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 145875158ebbSMarkus Armbruster "Device '%s' not found", path); 1459f5ec6704SStefan Hajnoczi } 1460f5ec6704SStefan Hajnoczi target = NULL; 1461f5ec6704SStefan Hajnoczi } 1462f5ec6704SStefan Hajnoczi g_free(target_type); 1463f5ec6704SStefan Hajnoczi 1464f5ec6704SStefan Hajnoczi return target; 1465f5ec6704SStefan Hajnoczi } 1466f5ec6704SStefan Hajnoczi 1467d7bce999SEric Blake static void object_set_link_property(Object *obj, Visitor *v, 1468d7bce999SEric Blake const char *name, void *opaque, 1469d7bce999SEric Blake Error **errp) 147057c9fafeSAnthony Liguori { 1471c6aed983SStefan Hajnoczi Error *local_err = NULL; 14729561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 14739561fda8SStefan Hajnoczi Object **child = prop->child; 1474c6aed983SStefan Hajnoczi Object *old_target = *child; 1475c6aed983SStefan Hajnoczi Object *new_target = NULL; 1476c6aed983SStefan Hajnoczi char *path = NULL; 147757c9fafeSAnthony Liguori 147851e72bc1SEric Blake visit_type_str(v, name, &path, &local_err); 147957c9fafeSAnthony Liguori 1480c6aed983SStefan Hajnoczi if (!local_err && strcmp(path, "") != 0) { 1481c6aed983SStefan Hajnoczi new_target = object_resolve_link(obj, name, path, &local_err); 148211e35bfdSPaolo Bonzini } 148357c9fafeSAnthony Liguori 148457c9fafeSAnthony Liguori g_free(path); 1485c6aed983SStefan Hajnoczi if (local_err) { 1486c6aed983SStefan Hajnoczi error_propagate(errp, local_err); 1487c6aed983SStefan Hajnoczi return; 1488c6aed983SStefan Hajnoczi } 1489f0cdc966SAlexander Barabash 149039f72ef9SStefan Hajnoczi prop->check(obj, name, new_target, &local_err); 149139f72ef9SStefan Hajnoczi if (local_err) { 149239f72ef9SStefan Hajnoczi error_propagate(errp, local_err); 149339f72ef9SStefan Hajnoczi return; 149439f72ef9SStefan Hajnoczi } 149539f72ef9SStefan Hajnoczi 1496c6aed983SStefan Hajnoczi object_ref(new_target); 1497c6aed983SStefan Hajnoczi *child = new_target; 1498f0cdc966SAlexander Barabash object_unref(old_target); 1499f0cdc966SAlexander Barabash } 150057c9fafeSAnthony Liguori 150164607d08SPaolo Bonzini static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) 150264607d08SPaolo Bonzini { 150364607d08SPaolo Bonzini LinkProperty *lprop = opaque; 150464607d08SPaolo Bonzini 150564607d08SPaolo Bonzini return *lprop->child; 150664607d08SPaolo Bonzini } 150764607d08SPaolo Bonzini 15089561fda8SStefan Hajnoczi static void object_release_link_property(Object *obj, const char *name, 15099561fda8SStefan Hajnoczi void *opaque) 15109561fda8SStefan Hajnoczi { 15119561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 15129561fda8SStefan Hajnoczi 15139561fda8SStefan Hajnoczi if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { 15149561fda8SStefan Hajnoczi object_unref(*prop->child); 15159561fda8SStefan Hajnoczi } 15169561fda8SStefan Hajnoczi g_free(prop); 15179561fda8SStefan Hajnoczi } 15189561fda8SStefan Hajnoczi 151957c9fafeSAnthony Liguori void object_property_add_link(Object *obj, const char *name, 152057c9fafeSAnthony Liguori const char *type, Object **child, 152139f72ef9SStefan Hajnoczi void (*check)(Object *, const char *, 152239f72ef9SStefan Hajnoczi Object *, Error **), 15239561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags, 152457c9fafeSAnthony Liguori Error **errp) 152557c9fafeSAnthony Liguori { 15269561fda8SStefan Hajnoczi Error *local_err = NULL; 15279561fda8SStefan Hajnoczi LinkProperty *prop = g_malloc(sizeof(*prop)); 152857c9fafeSAnthony Liguori gchar *full_type; 152964607d08SPaolo Bonzini ObjectProperty *op; 153057c9fafeSAnthony Liguori 15319561fda8SStefan Hajnoczi prop->child = child; 153239f72ef9SStefan Hajnoczi prop->check = check; 15339561fda8SStefan Hajnoczi prop->flags = flags; 15349561fda8SStefan Hajnoczi 153557c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 153657c9fafeSAnthony Liguori 153764607d08SPaolo Bonzini op = object_property_add(obj, name, full_type, 153857c9fafeSAnthony Liguori object_get_link_property, 153939f72ef9SStefan Hajnoczi check ? object_set_link_property : NULL, 15409561fda8SStefan Hajnoczi object_release_link_property, 15419561fda8SStefan Hajnoczi prop, 15429561fda8SStefan Hajnoczi &local_err); 15439561fda8SStefan Hajnoczi if (local_err) { 15449561fda8SStefan Hajnoczi error_propagate(errp, local_err); 15459561fda8SStefan Hajnoczi g_free(prop); 154664607d08SPaolo Bonzini goto out; 15479561fda8SStefan Hajnoczi } 154857c9fafeSAnthony Liguori 154964607d08SPaolo Bonzini op->resolve = object_resolve_link_property; 155064607d08SPaolo Bonzini 155164607d08SPaolo Bonzini out: 155257c9fafeSAnthony Liguori g_free(full_type); 155357c9fafeSAnthony Liguori } 155457c9fafeSAnthony Liguori 1555fb9e7e33SPaolo Bonzini void object_property_add_const_link(Object *obj, const char *name, 1556fb9e7e33SPaolo Bonzini Object *target, Error **errp) 1557fb9e7e33SPaolo Bonzini { 1558fb9e7e33SPaolo Bonzini char *link_type; 1559fb9e7e33SPaolo Bonzini ObjectProperty *op; 1560fb9e7e33SPaolo Bonzini 1561fb9e7e33SPaolo Bonzini link_type = g_strdup_printf("link<%s>", object_get_typename(target)); 1562fb9e7e33SPaolo Bonzini op = object_property_add(obj, name, link_type, 1563fb9e7e33SPaolo Bonzini object_get_child_property, NULL, 1564fb9e7e33SPaolo Bonzini NULL, target, errp); 1565fb9e7e33SPaolo Bonzini if (op != NULL) { 1566fb9e7e33SPaolo Bonzini op->resolve = object_resolve_child_property; 1567fb9e7e33SPaolo Bonzini } 1568fb9e7e33SPaolo Bonzini g_free(link_type); 1569fb9e7e33SPaolo Bonzini } 1570fb9e7e33SPaolo Bonzini 157111f590b1SStefan Hajnoczi gchar *object_get_canonical_path_component(Object *obj) 157257c9fafeSAnthony Liguori { 157357c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 1574b604a854SPavel Fedin GHashTableIter iter; 157557c9fafeSAnthony Liguori 157611f590b1SStefan Hajnoczi g_assert(obj); 157757c9fafeSAnthony Liguori g_assert(obj->parent != NULL); 157857c9fafeSAnthony Liguori 1579b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->parent->properties); 1580b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 15815d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 158257c9fafeSAnthony Liguori continue; 158357c9fafeSAnthony Liguori } 158457c9fafeSAnthony Liguori 158557c9fafeSAnthony Liguori if (prop->opaque == obj) { 158611f590b1SStefan Hajnoczi return g_strdup(prop->name); 158757c9fafeSAnthony Liguori } 158857c9fafeSAnthony Liguori } 158957c9fafeSAnthony Liguori 159011f590b1SStefan Hajnoczi /* obj had a parent but was not a child, should never happen */ 159111f590b1SStefan Hajnoczi g_assert_not_reached(); 159211f590b1SStefan Hajnoczi return NULL; 159311f590b1SStefan Hajnoczi } 159411f590b1SStefan Hajnoczi 159511f590b1SStefan Hajnoczi gchar *object_get_canonical_path(Object *obj) 159611f590b1SStefan Hajnoczi { 159711f590b1SStefan Hajnoczi Object *root = object_get_root(); 159811f590b1SStefan Hajnoczi char *newpath, *path = NULL; 159911f590b1SStefan Hajnoczi 160011f590b1SStefan Hajnoczi while (obj != root) { 160111f590b1SStefan Hajnoczi char *component = object_get_canonical_path_component(obj); 160211f590b1SStefan Hajnoczi 160311f590b1SStefan Hajnoczi if (path) { 160411f590b1SStefan Hajnoczi newpath = g_strdup_printf("%s/%s", component, path); 160511f590b1SStefan Hajnoczi g_free(component); 160611f590b1SStefan Hajnoczi g_free(path); 160711f590b1SStefan Hajnoczi path = newpath; 160811f590b1SStefan Hajnoczi } else { 160911f590b1SStefan Hajnoczi path = component; 161011f590b1SStefan Hajnoczi } 161157c9fafeSAnthony Liguori 161257c9fafeSAnthony Liguori obj = obj->parent; 161357c9fafeSAnthony Liguori } 161457c9fafeSAnthony Liguori 161511f590b1SStefan Hajnoczi newpath = g_strdup_printf("/%s", path ? path : ""); 161657c9fafeSAnthony Liguori g_free(path); 161757c9fafeSAnthony Liguori 161857c9fafeSAnthony Liguori return newpath; 161957c9fafeSAnthony Liguori } 162057c9fafeSAnthony Liguori 16213e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part) 1622a612b2a6SPaolo Bonzini { 162389bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(parent, part, NULL); 1624a612b2a6SPaolo Bonzini if (prop == NULL) { 1625a612b2a6SPaolo Bonzini return NULL; 1626a612b2a6SPaolo Bonzini } 1627a612b2a6SPaolo Bonzini 162864607d08SPaolo Bonzini if (prop->resolve) { 162964607d08SPaolo Bonzini return prop->resolve(parent, prop->opaque, part); 1630a612b2a6SPaolo Bonzini } else { 1631a612b2a6SPaolo Bonzini return NULL; 1632a612b2a6SPaolo Bonzini } 1633a612b2a6SPaolo Bonzini } 1634a612b2a6SPaolo Bonzini 163557c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 163657c9fafeSAnthony Liguori gchar **parts, 163702fe2db6SPaolo Bonzini const char *typename, 163857c9fafeSAnthony Liguori int index) 163957c9fafeSAnthony Liguori { 164057c9fafeSAnthony Liguori Object *child; 164157c9fafeSAnthony Liguori 164257c9fafeSAnthony Liguori if (parts[index] == NULL) { 164302fe2db6SPaolo Bonzini return object_dynamic_cast(parent, typename); 164457c9fafeSAnthony Liguori } 164557c9fafeSAnthony Liguori 164657c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 164702fe2db6SPaolo Bonzini return object_resolve_abs_path(parent, parts, typename, index + 1); 164857c9fafeSAnthony Liguori } 164957c9fafeSAnthony Liguori 1650a612b2a6SPaolo Bonzini child = object_resolve_path_component(parent, parts[index]); 165157c9fafeSAnthony Liguori if (!child) { 165257c9fafeSAnthony Liguori return NULL; 165357c9fafeSAnthony Liguori } 165457c9fafeSAnthony Liguori 165502fe2db6SPaolo Bonzini return object_resolve_abs_path(child, parts, typename, index + 1); 165657c9fafeSAnthony Liguori } 165757c9fafeSAnthony Liguori 165857c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 165957c9fafeSAnthony Liguori gchar **parts, 166002fe2db6SPaolo Bonzini const char *typename, 166157c9fafeSAnthony Liguori bool *ambiguous) 166257c9fafeSAnthony Liguori { 166357c9fafeSAnthony Liguori Object *obj; 1664b604a854SPavel Fedin GHashTableIter iter; 166557c9fafeSAnthony Liguori ObjectProperty *prop; 166657c9fafeSAnthony Liguori 166702fe2db6SPaolo Bonzini obj = object_resolve_abs_path(parent, parts, typename, 0); 166857c9fafeSAnthony Liguori 1669b604a854SPavel Fedin g_hash_table_iter_init(&iter, parent->properties); 1670b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 167157c9fafeSAnthony Liguori Object *found; 167257c9fafeSAnthony Liguori 16735d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 167457c9fafeSAnthony Liguori continue; 167557c9fafeSAnthony Liguori } 167657c9fafeSAnthony Liguori 167702fe2db6SPaolo Bonzini found = object_resolve_partial_path(prop->opaque, parts, 167802fe2db6SPaolo Bonzini typename, ambiguous); 167957c9fafeSAnthony Liguori if (found) { 168057c9fafeSAnthony Liguori if (obj) { 168157c9fafeSAnthony Liguori if (ambiguous) { 168257c9fafeSAnthony Liguori *ambiguous = true; 168357c9fafeSAnthony Liguori } 168457c9fafeSAnthony Liguori return NULL; 168557c9fafeSAnthony Liguori } 168657c9fafeSAnthony Liguori obj = found; 168757c9fafeSAnthony Liguori } 168857c9fafeSAnthony Liguori 168957c9fafeSAnthony Liguori if (ambiguous && *ambiguous) { 169057c9fafeSAnthony Liguori return NULL; 169157c9fafeSAnthony Liguori } 169257c9fafeSAnthony Liguori } 169357c9fafeSAnthony Liguori 169457c9fafeSAnthony Liguori return obj; 169557c9fafeSAnthony Liguori } 169657c9fafeSAnthony Liguori 169702fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename, 169802fe2db6SPaolo Bonzini bool *ambiguous) 169957c9fafeSAnthony Liguori { 170057c9fafeSAnthony Liguori Object *obj; 170157c9fafeSAnthony Liguori gchar **parts; 170257c9fafeSAnthony Liguori 170357c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 17042e1103f6SPaolo Bonzini assert(parts); 170557c9fafeSAnthony Liguori 17062e1103f6SPaolo Bonzini if (parts[0] == NULL || strcmp(parts[0], "") != 0) { 170757c9fafeSAnthony Liguori if (ambiguous) { 170857c9fafeSAnthony Liguori *ambiguous = false; 170957c9fafeSAnthony Liguori } 171002fe2db6SPaolo Bonzini obj = object_resolve_partial_path(object_get_root(), parts, 171102fe2db6SPaolo Bonzini typename, ambiguous); 171257c9fafeSAnthony Liguori } else { 171302fe2db6SPaolo Bonzini obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); 171457c9fafeSAnthony Liguori } 171557c9fafeSAnthony Liguori 171657c9fafeSAnthony Liguori g_strfreev(parts); 171757c9fafeSAnthony Liguori 171857c9fafeSAnthony Liguori return obj; 171957c9fafeSAnthony Liguori } 172057c9fafeSAnthony Liguori 172102fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous) 172202fe2db6SPaolo Bonzini { 172302fe2db6SPaolo Bonzini return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); 172402fe2db6SPaolo Bonzini } 172502fe2db6SPaolo Bonzini 172657c9fafeSAnthony Liguori typedef struct StringProperty 172757c9fafeSAnthony Liguori { 172857c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 172957c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 173057c9fafeSAnthony Liguori } StringProperty; 173157c9fafeSAnthony Liguori 1732d7bce999SEric Blake static void property_get_str(Object *obj, Visitor *v, const char *name, 1733d7bce999SEric Blake void *opaque, Error **errp) 173457c9fafeSAnthony Liguori { 173557c9fafeSAnthony Liguori StringProperty *prop = opaque; 173657c9fafeSAnthony Liguori char *value; 1737e1c8237dSMarkus Armbruster Error *err = NULL; 173857c9fafeSAnthony Liguori 1739e1c8237dSMarkus Armbruster value = prop->get(obj, &err); 1740e1c8237dSMarkus Armbruster if (err) { 1741e1c8237dSMarkus Armbruster error_propagate(errp, err); 1742e1c8237dSMarkus Armbruster return; 1743e1c8237dSMarkus Armbruster } 1744e1c8237dSMarkus Armbruster 174551e72bc1SEric Blake visit_type_str(v, name, &value, errp); 174657c9fafeSAnthony Liguori g_free(value); 174757c9fafeSAnthony Liguori } 174857c9fafeSAnthony Liguori 1749d7bce999SEric Blake static void property_set_str(Object *obj, Visitor *v, const char *name, 1750d7bce999SEric Blake void *opaque, Error **errp) 175157c9fafeSAnthony Liguori { 175257c9fafeSAnthony Liguori StringProperty *prop = opaque; 175357c9fafeSAnthony Liguori char *value; 175457c9fafeSAnthony Liguori Error *local_err = NULL; 175557c9fafeSAnthony Liguori 175651e72bc1SEric Blake visit_type_str(v, name, &value, &local_err); 175757c9fafeSAnthony Liguori if (local_err) { 175857c9fafeSAnthony Liguori error_propagate(errp, local_err); 175957c9fafeSAnthony Liguori return; 176057c9fafeSAnthony Liguori } 176157c9fafeSAnthony Liguori 176257c9fafeSAnthony Liguori prop->set(obj, value, errp); 176357c9fafeSAnthony Liguori g_free(value); 176457c9fafeSAnthony Liguori } 176557c9fafeSAnthony Liguori 17667b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name, 176757c9fafeSAnthony Liguori void *opaque) 176857c9fafeSAnthony Liguori { 176957c9fafeSAnthony Liguori StringProperty *prop = opaque; 177057c9fafeSAnthony Liguori g_free(prop); 177157c9fafeSAnthony Liguori } 177257c9fafeSAnthony Liguori 177357c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 177457c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 177557c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 177657c9fafeSAnthony Liguori Error **errp) 177757c9fafeSAnthony Liguori { 1778a01aedc8SStefan Hajnoczi Error *local_err = NULL; 177957c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 178057c9fafeSAnthony Liguori 178157c9fafeSAnthony Liguori prop->get = get; 178257c9fafeSAnthony Liguori prop->set = set; 178357c9fafeSAnthony Liguori 178457c9fafeSAnthony Liguori object_property_add(obj, name, "string", 17857b7b7d18SPaolo Bonzini get ? property_get_str : NULL, 17867b7b7d18SPaolo Bonzini set ? property_set_str : NULL, 17877b7b7d18SPaolo Bonzini property_release_str, 1788a01aedc8SStefan Hajnoczi prop, &local_err); 1789a01aedc8SStefan Hajnoczi if (local_err) { 1790a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1791a01aedc8SStefan Hajnoczi g_free(prop); 1792a01aedc8SStefan Hajnoczi } 179357c9fafeSAnthony Liguori } 1794745549c8SPaolo Bonzini 179516bf7f52SDaniel P. Berrange void object_class_property_add_str(ObjectClass *klass, const char *name, 179616bf7f52SDaniel P. Berrange char *(*get)(Object *, Error **), 179716bf7f52SDaniel P. Berrange void (*set)(Object *, const char *, 179816bf7f52SDaniel P. Berrange Error **), 179916bf7f52SDaniel P. Berrange Error **errp) 180016bf7f52SDaniel P. Berrange { 180116bf7f52SDaniel P. Berrange Error *local_err = NULL; 180216bf7f52SDaniel P. Berrange StringProperty *prop = g_malloc0(sizeof(*prop)); 180316bf7f52SDaniel P. Berrange 180416bf7f52SDaniel P. Berrange prop->get = get; 180516bf7f52SDaniel P. Berrange prop->set = set; 180616bf7f52SDaniel P. Berrange 180716bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "string", 180816bf7f52SDaniel P. Berrange get ? property_get_str : NULL, 180916bf7f52SDaniel P. Berrange set ? property_set_str : NULL, 181016bf7f52SDaniel P. Berrange property_release_str, 181116bf7f52SDaniel P. Berrange prop, &local_err); 181216bf7f52SDaniel P. Berrange if (local_err) { 181316bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 181416bf7f52SDaniel P. Berrange g_free(prop); 181516bf7f52SDaniel P. Berrange } 181616bf7f52SDaniel P. Berrange } 181716bf7f52SDaniel P. Berrange 18180e558843SAnthony Liguori typedef struct BoolProperty 18190e558843SAnthony Liguori { 18200e558843SAnthony Liguori bool (*get)(Object *, Error **); 18210e558843SAnthony Liguori void (*set)(Object *, bool, Error **); 18220e558843SAnthony Liguori } BoolProperty; 18230e558843SAnthony Liguori 1824d7bce999SEric Blake static void property_get_bool(Object *obj, Visitor *v, const char *name, 1825d7bce999SEric Blake void *opaque, Error **errp) 18260e558843SAnthony Liguori { 18270e558843SAnthony Liguori BoolProperty *prop = opaque; 18280e558843SAnthony Liguori bool value; 18294715d42eSMarkus Armbruster Error *err = NULL; 18300e558843SAnthony Liguori 18314715d42eSMarkus Armbruster value = prop->get(obj, &err); 18324715d42eSMarkus Armbruster if (err) { 18334715d42eSMarkus Armbruster error_propagate(errp, err); 18344715d42eSMarkus Armbruster return; 18354715d42eSMarkus Armbruster } 18364715d42eSMarkus Armbruster 183751e72bc1SEric Blake visit_type_bool(v, name, &value, errp); 18380e558843SAnthony Liguori } 18390e558843SAnthony Liguori 1840d7bce999SEric Blake static void property_set_bool(Object *obj, Visitor *v, const char *name, 1841d7bce999SEric Blake void *opaque, Error **errp) 18420e558843SAnthony Liguori { 18430e558843SAnthony Liguori BoolProperty *prop = opaque; 18440e558843SAnthony Liguori bool value; 18450e558843SAnthony Liguori Error *local_err = NULL; 18460e558843SAnthony Liguori 184751e72bc1SEric Blake visit_type_bool(v, name, &value, &local_err); 18480e558843SAnthony Liguori if (local_err) { 18490e558843SAnthony Liguori error_propagate(errp, local_err); 18500e558843SAnthony Liguori return; 18510e558843SAnthony Liguori } 18520e558843SAnthony Liguori 18530e558843SAnthony Liguori prop->set(obj, value, errp); 18540e558843SAnthony Liguori } 18550e558843SAnthony Liguori 18560e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name, 18570e558843SAnthony Liguori void *opaque) 18580e558843SAnthony Liguori { 18590e558843SAnthony Liguori BoolProperty *prop = opaque; 18600e558843SAnthony Liguori g_free(prop); 18610e558843SAnthony Liguori } 18620e558843SAnthony Liguori 18630e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name, 18640e558843SAnthony Liguori bool (*get)(Object *, Error **), 18650e558843SAnthony Liguori void (*set)(Object *, bool, Error **), 18660e558843SAnthony Liguori Error **errp) 18670e558843SAnthony Liguori { 1868a01aedc8SStefan Hajnoczi Error *local_err = NULL; 18690e558843SAnthony Liguori BoolProperty *prop = g_malloc0(sizeof(*prop)); 18700e558843SAnthony Liguori 18710e558843SAnthony Liguori prop->get = get; 18720e558843SAnthony Liguori prop->set = set; 18730e558843SAnthony Liguori 18740e558843SAnthony Liguori object_property_add(obj, name, "bool", 18750e558843SAnthony Liguori get ? property_get_bool : NULL, 18760e558843SAnthony Liguori set ? property_set_bool : NULL, 18770e558843SAnthony Liguori property_release_bool, 1878a01aedc8SStefan Hajnoczi prop, &local_err); 1879a01aedc8SStefan Hajnoczi if (local_err) { 1880a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 1881a01aedc8SStefan Hajnoczi g_free(prop); 1882a01aedc8SStefan Hajnoczi } 18830e558843SAnthony Liguori } 18840e558843SAnthony Liguori 188516bf7f52SDaniel P. Berrange void object_class_property_add_bool(ObjectClass *klass, const char *name, 188616bf7f52SDaniel P. Berrange bool (*get)(Object *, Error **), 188716bf7f52SDaniel P. Berrange void (*set)(Object *, bool, Error **), 188816bf7f52SDaniel P. Berrange Error **errp) 188916bf7f52SDaniel P. Berrange { 189016bf7f52SDaniel P. Berrange Error *local_err = NULL; 189116bf7f52SDaniel P. Berrange BoolProperty *prop = g_malloc0(sizeof(*prop)); 189216bf7f52SDaniel P. Berrange 189316bf7f52SDaniel P. Berrange prop->get = get; 189416bf7f52SDaniel P. Berrange prop->set = set; 189516bf7f52SDaniel P. Berrange 189616bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "bool", 189716bf7f52SDaniel P. Berrange get ? property_get_bool : NULL, 189816bf7f52SDaniel P. Berrange set ? property_set_bool : NULL, 189916bf7f52SDaniel P. Berrange property_release_bool, 190016bf7f52SDaniel P. Berrange prop, &local_err); 190116bf7f52SDaniel P. Berrange if (local_err) { 190216bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 190316bf7f52SDaniel P. Berrange g_free(prop); 190416bf7f52SDaniel P. Berrange } 190516bf7f52SDaniel P. Berrange } 190616bf7f52SDaniel P. Berrange 1907d7bce999SEric Blake static void property_get_enum(Object *obj, Visitor *v, const char *name, 1908d7bce999SEric Blake void *opaque, Error **errp) 1909a8e3fbedSDaniel P. Berrange { 1910a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1911a8e3fbedSDaniel P. Berrange int value; 19124715d42eSMarkus Armbruster Error *err = NULL; 1913a8e3fbedSDaniel P. Berrange 19144715d42eSMarkus Armbruster value = prop->get(obj, &err); 19154715d42eSMarkus Armbruster if (err) { 19164715d42eSMarkus Armbruster error_propagate(errp, err); 19174715d42eSMarkus Armbruster return; 19184715d42eSMarkus Armbruster } 19194715d42eSMarkus Armbruster 1920337283dfSEric Blake visit_type_enum(v, name, &value, prop->strings, errp); 1921a8e3fbedSDaniel P. Berrange } 1922a8e3fbedSDaniel P. Berrange 1923d7bce999SEric Blake static void property_set_enum(Object *obj, Visitor *v, const char *name, 1924d7bce999SEric Blake void *opaque, Error **errp) 1925a8e3fbedSDaniel P. Berrange { 1926a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1927a8e3fbedSDaniel P. Berrange int value; 19284715d42eSMarkus Armbruster Error *err = NULL; 1929a8e3fbedSDaniel P. Berrange 1930337283dfSEric Blake visit_type_enum(v, name, &value, prop->strings, &err); 19314715d42eSMarkus Armbruster if (err) { 19324715d42eSMarkus Armbruster error_propagate(errp, err); 19334715d42eSMarkus Armbruster return; 19344715d42eSMarkus Armbruster } 1935a8e3fbedSDaniel P. Berrange prop->set(obj, value, errp); 1936a8e3fbedSDaniel P. Berrange } 1937a8e3fbedSDaniel P. Berrange 1938a8e3fbedSDaniel P. Berrange static void property_release_enum(Object *obj, const char *name, 1939a8e3fbedSDaniel P. Berrange void *opaque) 1940a8e3fbedSDaniel P. Berrange { 1941a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 1942a8e3fbedSDaniel P. Berrange g_free(prop); 1943a8e3fbedSDaniel P. Berrange } 1944a8e3fbedSDaniel P. Berrange 1945a8e3fbedSDaniel P. Berrange void object_property_add_enum(Object *obj, const char *name, 1946a8e3fbedSDaniel P. Berrange const char *typename, 1947a8e3fbedSDaniel P. Berrange const char * const *strings, 1948a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **), 1949a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **), 1950a8e3fbedSDaniel P. Berrange Error **errp) 1951a8e3fbedSDaniel P. Berrange { 1952a8e3fbedSDaniel P. Berrange Error *local_err = NULL; 1953a8e3fbedSDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 1954a8e3fbedSDaniel P. Berrange 1955a8e3fbedSDaniel P. Berrange prop->strings = strings; 1956a8e3fbedSDaniel P. Berrange prop->get = get; 1957a8e3fbedSDaniel P. Berrange prop->set = set; 1958a8e3fbedSDaniel P. Berrange 1959a8e3fbedSDaniel P. Berrange object_property_add(obj, name, typename, 1960a8e3fbedSDaniel P. Berrange get ? property_get_enum : NULL, 1961a8e3fbedSDaniel P. Berrange set ? property_set_enum : NULL, 1962a8e3fbedSDaniel P. Berrange property_release_enum, 1963a8e3fbedSDaniel P. Berrange prop, &local_err); 1964a8e3fbedSDaniel P. Berrange if (local_err) { 1965a8e3fbedSDaniel P. Berrange error_propagate(errp, local_err); 1966a8e3fbedSDaniel P. Berrange g_free(prop); 1967a8e3fbedSDaniel P. Berrange } 1968a8e3fbedSDaniel P. Berrange } 1969a8e3fbedSDaniel P. Berrange 197016bf7f52SDaniel P. Berrange void object_class_property_add_enum(ObjectClass *klass, const char *name, 197116bf7f52SDaniel P. Berrange const char *typename, 197216bf7f52SDaniel P. Berrange const char * const *strings, 197316bf7f52SDaniel P. Berrange int (*get)(Object *, Error **), 197416bf7f52SDaniel P. Berrange void (*set)(Object *, int, Error **), 197516bf7f52SDaniel P. Berrange Error **errp) 197616bf7f52SDaniel P. Berrange { 197716bf7f52SDaniel P. Berrange Error *local_err = NULL; 197816bf7f52SDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 197916bf7f52SDaniel P. Berrange 198016bf7f52SDaniel P. Berrange prop->strings = strings; 198116bf7f52SDaniel P. Berrange prop->get = get; 198216bf7f52SDaniel P. Berrange prop->set = set; 198316bf7f52SDaniel P. Berrange 198416bf7f52SDaniel P. Berrange object_class_property_add(klass, name, typename, 198516bf7f52SDaniel P. Berrange get ? property_get_enum : NULL, 198616bf7f52SDaniel P. Berrange set ? property_set_enum : NULL, 198716bf7f52SDaniel P. Berrange property_release_enum, 198816bf7f52SDaniel P. Berrange prop, &local_err); 198916bf7f52SDaniel P. Berrange if (local_err) { 199016bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 199116bf7f52SDaniel P. Berrange g_free(prop); 199216bf7f52SDaniel P. Berrange } 199316bf7f52SDaniel P. Berrange } 199416bf7f52SDaniel P. Berrange 19958e099d14SDavid Gibson typedef struct TMProperty { 19968e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **); 19978e099d14SDavid Gibson } TMProperty; 19988e099d14SDavid Gibson 1999d7bce999SEric Blake static void property_get_tm(Object *obj, Visitor *v, const char *name, 2000d7bce999SEric Blake void *opaque, Error **errp) 20018e099d14SDavid Gibson { 20028e099d14SDavid Gibson TMProperty *prop = opaque; 20038e099d14SDavid Gibson Error *err = NULL; 20048e099d14SDavid Gibson struct tm value; 20058e099d14SDavid Gibson 20068e099d14SDavid Gibson prop->get(obj, &value, &err); 20078e099d14SDavid Gibson if (err) { 20088e099d14SDavid Gibson goto out; 20098e099d14SDavid Gibson } 20108e099d14SDavid Gibson 2011337283dfSEric Blake visit_start_struct(v, name, NULL, 0, &err); 20128e099d14SDavid Gibson if (err) { 20138e099d14SDavid Gibson goto out; 20148e099d14SDavid Gibson } 201551e72bc1SEric Blake visit_type_int32(v, "tm_year", &value.tm_year, &err); 20168e099d14SDavid Gibson if (err) { 20178e099d14SDavid Gibson goto out_end; 20188e099d14SDavid Gibson } 201951e72bc1SEric Blake visit_type_int32(v, "tm_mon", &value.tm_mon, &err); 20208e099d14SDavid Gibson if (err) { 20218e099d14SDavid Gibson goto out_end; 20228e099d14SDavid Gibson } 202351e72bc1SEric Blake visit_type_int32(v, "tm_mday", &value.tm_mday, &err); 20248e099d14SDavid Gibson if (err) { 20258e099d14SDavid Gibson goto out_end; 20268e099d14SDavid Gibson } 202751e72bc1SEric Blake visit_type_int32(v, "tm_hour", &value.tm_hour, &err); 20288e099d14SDavid Gibson if (err) { 20298e099d14SDavid Gibson goto out_end; 20308e099d14SDavid Gibson } 203151e72bc1SEric Blake visit_type_int32(v, "tm_min", &value.tm_min, &err); 20328e099d14SDavid Gibson if (err) { 20338e099d14SDavid Gibson goto out_end; 20348e099d14SDavid Gibson } 203551e72bc1SEric Blake visit_type_int32(v, "tm_sec", &value.tm_sec, &err); 20368e099d14SDavid Gibson if (err) { 20378e099d14SDavid Gibson goto out_end; 20388e099d14SDavid Gibson } 2039*15c2f669SEric Blake visit_check_struct(v, &err); 20408e099d14SDavid Gibson out_end: 2041*15c2f669SEric Blake visit_end_struct(v); 20428e099d14SDavid Gibson out: 20438e099d14SDavid Gibson error_propagate(errp, err); 20448e099d14SDavid Gibson 20458e099d14SDavid Gibson } 20468e099d14SDavid Gibson 20478e099d14SDavid Gibson static void property_release_tm(Object *obj, const char *name, 20488e099d14SDavid Gibson void *opaque) 20498e099d14SDavid Gibson { 20508e099d14SDavid Gibson TMProperty *prop = opaque; 20518e099d14SDavid Gibson g_free(prop); 20528e099d14SDavid Gibson } 20538e099d14SDavid Gibson 20548e099d14SDavid Gibson void object_property_add_tm(Object *obj, const char *name, 20558e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **), 20568e099d14SDavid Gibson Error **errp) 20578e099d14SDavid Gibson { 20588e099d14SDavid Gibson Error *local_err = NULL; 20598e099d14SDavid Gibson TMProperty *prop = g_malloc0(sizeof(*prop)); 20608e099d14SDavid Gibson 20618e099d14SDavid Gibson prop->get = get; 20628e099d14SDavid Gibson 20638e099d14SDavid Gibson object_property_add(obj, name, "struct tm", 20648e099d14SDavid Gibson get ? property_get_tm : NULL, NULL, 20658e099d14SDavid Gibson property_release_tm, 20668e099d14SDavid Gibson prop, &local_err); 20678e099d14SDavid Gibson if (local_err) { 20688e099d14SDavid Gibson error_propagate(errp, local_err); 20698e099d14SDavid Gibson g_free(prop); 20708e099d14SDavid Gibson } 20718e099d14SDavid Gibson } 20728e099d14SDavid Gibson 207316bf7f52SDaniel P. Berrange void object_class_property_add_tm(ObjectClass *klass, const char *name, 207416bf7f52SDaniel P. Berrange void (*get)(Object *, struct tm *, Error **), 207516bf7f52SDaniel P. Berrange Error **errp) 207616bf7f52SDaniel P. Berrange { 207716bf7f52SDaniel P. Berrange Error *local_err = NULL; 207816bf7f52SDaniel P. Berrange TMProperty *prop = g_malloc0(sizeof(*prop)); 207916bf7f52SDaniel P. Berrange 208016bf7f52SDaniel P. Berrange prop->get = get; 208116bf7f52SDaniel P. Berrange 208216bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "struct tm", 208316bf7f52SDaniel P. Berrange get ? property_get_tm : NULL, NULL, 208416bf7f52SDaniel P. Berrange property_release_tm, 208516bf7f52SDaniel P. Berrange prop, &local_err); 208616bf7f52SDaniel P. Berrange if (local_err) { 208716bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 208816bf7f52SDaniel P. Berrange g_free(prop); 208916bf7f52SDaniel P. Berrange } 209016bf7f52SDaniel P. Berrange } 209116bf7f52SDaniel P. Berrange 20922f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp) 20932f262e06SPaolo Bonzini { 20942f262e06SPaolo Bonzini return g_strdup(object_get_typename(obj)); 20952f262e06SPaolo Bonzini } 20962f262e06SPaolo Bonzini 2097d7bce999SEric Blake static void property_get_uint8_ptr(Object *obj, Visitor *v, const char *name, 2098d7bce999SEric Blake void *opaque, Error **errp) 2099e732ea63SMichael S. Tsirkin { 2100e732ea63SMichael S. Tsirkin uint8_t value = *(uint8_t *)opaque; 210151e72bc1SEric Blake visit_type_uint8(v, name, &value, errp); 2102e732ea63SMichael S. Tsirkin } 2103e732ea63SMichael S. Tsirkin 2104d7bce999SEric Blake static void property_get_uint16_ptr(Object *obj, Visitor *v, const char *name, 2105d7bce999SEric Blake void *opaque, Error **errp) 2106e732ea63SMichael S. Tsirkin { 2107e732ea63SMichael S. Tsirkin uint16_t value = *(uint16_t *)opaque; 210851e72bc1SEric Blake visit_type_uint16(v, name, &value, errp); 2109e732ea63SMichael S. Tsirkin } 2110e732ea63SMichael S. Tsirkin 2111d7bce999SEric Blake static void property_get_uint32_ptr(Object *obj, Visitor *v, const char *name, 2112d7bce999SEric Blake void *opaque, Error **errp) 2113e732ea63SMichael S. Tsirkin { 2114e732ea63SMichael S. Tsirkin uint32_t value = *(uint32_t *)opaque; 211551e72bc1SEric Blake visit_type_uint32(v, name, &value, errp); 2116e732ea63SMichael S. Tsirkin } 2117e732ea63SMichael S. Tsirkin 2118d7bce999SEric Blake static void property_get_uint64_ptr(Object *obj, Visitor *v, const char *name, 2119d7bce999SEric Blake void *opaque, Error **errp) 2120e732ea63SMichael S. Tsirkin { 2121e732ea63SMichael S. Tsirkin uint64_t value = *(uint64_t *)opaque; 212251e72bc1SEric Blake visit_type_uint64(v, name, &value, errp); 2123e732ea63SMichael S. Tsirkin } 2124e732ea63SMichael S. Tsirkin 2125e732ea63SMichael S. Tsirkin void object_property_add_uint8_ptr(Object *obj, const char *name, 2126e732ea63SMichael S. Tsirkin const uint8_t *v, Error **errp) 2127e732ea63SMichael S. Tsirkin { 2128e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint8", property_get_uint8_ptr, 2129e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2130e732ea63SMichael S. Tsirkin } 2131e732ea63SMichael S. Tsirkin 213216bf7f52SDaniel P. Berrange void object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, 213316bf7f52SDaniel P. Berrange const uint8_t *v, Error **errp) 213416bf7f52SDaniel P. Berrange { 213516bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint8", property_get_uint8_ptr, 213616bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 213716bf7f52SDaniel P. Berrange } 213816bf7f52SDaniel P. Berrange 2139e732ea63SMichael S. Tsirkin void object_property_add_uint16_ptr(Object *obj, const char *name, 2140e732ea63SMichael S. Tsirkin const uint16_t *v, Error **errp) 2141e732ea63SMichael S. Tsirkin { 2142e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint16", property_get_uint16_ptr, 2143e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2144e732ea63SMichael S. Tsirkin } 2145e732ea63SMichael S. Tsirkin 214616bf7f52SDaniel P. Berrange void object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, 214716bf7f52SDaniel P. Berrange const uint16_t *v, Error **errp) 214816bf7f52SDaniel P. Berrange { 214916bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint16", property_get_uint16_ptr, 215016bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 215116bf7f52SDaniel P. Berrange } 215216bf7f52SDaniel P. Berrange 2153e732ea63SMichael S. Tsirkin void object_property_add_uint32_ptr(Object *obj, const char *name, 2154e732ea63SMichael S. Tsirkin const uint32_t *v, Error **errp) 2155e732ea63SMichael S. Tsirkin { 2156e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint32", property_get_uint32_ptr, 2157e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2158e732ea63SMichael S. Tsirkin } 2159e732ea63SMichael S. Tsirkin 216016bf7f52SDaniel P. Berrange void object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, 216116bf7f52SDaniel P. Berrange const uint32_t *v, Error **errp) 216216bf7f52SDaniel P. Berrange { 216316bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint32", property_get_uint32_ptr, 216416bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 216516bf7f52SDaniel P. Berrange } 216616bf7f52SDaniel P. Berrange 2167e732ea63SMichael S. Tsirkin void object_property_add_uint64_ptr(Object *obj, const char *name, 2168e732ea63SMichael S. Tsirkin const uint64_t *v, Error **errp) 2169e732ea63SMichael S. Tsirkin { 2170e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint64", property_get_uint64_ptr, 2171e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2172e732ea63SMichael S. Tsirkin } 2173e732ea63SMichael S. Tsirkin 217416bf7f52SDaniel P. Berrange void object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, 217516bf7f52SDaniel P. Berrange const uint64_t *v, Error **errp) 217616bf7f52SDaniel P. Berrange { 217716bf7f52SDaniel P. Berrange object_class_property_add(klass, name, "uint64", property_get_uint64_ptr, 217816bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 217916bf7f52SDaniel P. Berrange } 218016bf7f52SDaniel P. Berrange 2181ef7c7ff6SStefan Hajnoczi typedef struct { 2182ef7c7ff6SStefan Hajnoczi Object *target_obj; 21831590d266SEduardo Habkost char *target_name; 2184ef7c7ff6SStefan Hajnoczi } AliasProperty; 2185ef7c7ff6SStefan Hajnoczi 2186d7bce999SEric Blake static void property_get_alias(Object *obj, Visitor *v, const char *name, 2187d7bce999SEric Blake void *opaque, Error **errp) 2188ef7c7ff6SStefan Hajnoczi { 2189ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2190ef7c7ff6SStefan Hajnoczi 2191ef7c7ff6SStefan Hajnoczi object_property_get(prop->target_obj, v, prop->target_name, errp); 2192ef7c7ff6SStefan Hajnoczi } 2193ef7c7ff6SStefan Hajnoczi 2194d7bce999SEric Blake static void property_set_alias(Object *obj, Visitor *v, const char *name, 2195d7bce999SEric Blake void *opaque, Error **errp) 2196ef7c7ff6SStefan Hajnoczi { 2197ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2198ef7c7ff6SStefan Hajnoczi 2199ef7c7ff6SStefan Hajnoczi object_property_set(prop->target_obj, v, prop->target_name, errp); 2200ef7c7ff6SStefan Hajnoczi } 2201ef7c7ff6SStefan Hajnoczi 220264607d08SPaolo Bonzini static Object *property_resolve_alias(Object *obj, void *opaque, 220364607d08SPaolo Bonzini const gchar *part) 220464607d08SPaolo Bonzini { 220564607d08SPaolo Bonzini AliasProperty *prop = opaque; 220664607d08SPaolo Bonzini 220764607d08SPaolo Bonzini return object_resolve_path_component(prop->target_obj, prop->target_name); 220864607d08SPaolo Bonzini } 220964607d08SPaolo Bonzini 2210ef7c7ff6SStefan Hajnoczi static void property_release_alias(Object *obj, const char *name, void *opaque) 2211ef7c7ff6SStefan Hajnoczi { 2212ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2213ef7c7ff6SStefan Hajnoczi 22141590d266SEduardo Habkost g_free(prop->target_name); 2215ef7c7ff6SStefan Hajnoczi g_free(prop); 2216ef7c7ff6SStefan Hajnoczi } 2217ef7c7ff6SStefan Hajnoczi 2218ef7c7ff6SStefan Hajnoczi void object_property_add_alias(Object *obj, const char *name, 2219ef7c7ff6SStefan Hajnoczi Object *target_obj, const char *target_name, 2220ef7c7ff6SStefan Hajnoczi Error **errp) 2221ef7c7ff6SStefan Hajnoczi { 2222ef7c7ff6SStefan Hajnoczi AliasProperty *prop; 222364607d08SPaolo Bonzini ObjectProperty *op; 2224ef7c7ff6SStefan Hajnoczi ObjectProperty *target_prop; 2225d190698eSPaolo Bonzini gchar *prop_type; 22268ae9a9efSGonglei Error *local_err = NULL; 2227ef7c7ff6SStefan Hajnoczi 2228ef7c7ff6SStefan Hajnoczi target_prop = object_property_find(target_obj, target_name, errp); 2229ef7c7ff6SStefan Hajnoczi if (!target_prop) { 2230ef7c7ff6SStefan Hajnoczi return; 2231ef7c7ff6SStefan Hajnoczi } 2232ef7c7ff6SStefan Hajnoczi 2233d190698eSPaolo Bonzini if (object_property_is_child(target_prop)) { 2234d190698eSPaolo Bonzini prop_type = g_strdup_printf("link%s", 2235d190698eSPaolo Bonzini target_prop->type + strlen("child")); 2236d190698eSPaolo Bonzini } else { 2237d190698eSPaolo Bonzini prop_type = g_strdup(target_prop->type); 2238d190698eSPaolo Bonzini } 2239d190698eSPaolo Bonzini 2240ef7c7ff6SStefan Hajnoczi prop = g_malloc(sizeof(*prop)); 2241ef7c7ff6SStefan Hajnoczi prop->target_obj = target_obj; 22421590d266SEduardo Habkost prop->target_name = g_strdup(target_name); 2243ef7c7ff6SStefan Hajnoczi 2244d190698eSPaolo Bonzini op = object_property_add(obj, name, prop_type, 2245ef7c7ff6SStefan Hajnoczi property_get_alias, 2246ef7c7ff6SStefan Hajnoczi property_set_alias, 2247ef7c7ff6SStefan Hajnoczi property_release_alias, 22488ae9a9efSGonglei prop, &local_err); 22498ae9a9efSGonglei if (local_err) { 22508ae9a9efSGonglei error_propagate(errp, local_err); 22518ae9a9efSGonglei g_free(prop); 22528ae9a9efSGonglei goto out; 22538ae9a9efSGonglei } 225464607d08SPaolo Bonzini op->resolve = property_resolve_alias; 2255d190698eSPaolo Bonzini 2256a18bb417SAndreas Färber object_property_set_description(obj, op->name, 225780742642SGonglei target_prop->description, 225880742642SGonglei &error_abort); 225980742642SGonglei 22608ae9a9efSGonglei out: 2261d190698eSPaolo Bonzini g_free(prop_type); 2262ef7c7ff6SStefan Hajnoczi } 2263ef7c7ff6SStefan Hajnoczi 226480742642SGonglei void object_property_set_description(Object *obj, const char *name, 226580742642SGonglei const char *description, Error **errp) 226680742642SGonglei { 226780742642SGonglei ObjectProperty *op; 226880742642SGonglei 226980742642SGonglei op = object_property_find(obj, name, errp); 227080742642SGonglei if (!op) { 227180742642SGonglei return; 227280742642SGonglei } 227380742642SGonglei 227480742642SGonglei g_free(op->description); 227580742642SGonglei op->description = g_strdup(description); 227680742642SGonglei } 227780742642SGonglei 227816bf7f52SDaniel P. Berrange void object_class_property_set_description(ObjectClass *klass, 227916bf7f52SDaniel P. Berrange const char *name, 228016bf7f52SDaniel P. Berrange const char *description, 228116bf7f52SDaniel P. Berrange Error **errp) 228216bf7f52SDaniel P. Berrange { 228316bf7f52SDaniel P. Berrange ObjectProperty *op; 228416bf7f52SDaniel P. Berrange 228516bf7f52SDaniel P. Berrange op = g_hash_table_lookup(klass->properties, name); 228616bf7f52SDaniel P. Berrange if (!op) { 228716bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 228816bf7f52SDaniel P. Berrange return; 228916bf7f52SDaniel P. Berrange } 229016bf7f52SDaniel P. Berrange 229116bf7f52SDaniel P. Berrange g_free(op->description); 229216bf7f52SDaniel P. Berrange op->description = g_strdup(description); 229316bf7f52SDaniel P. Berrange } 229416bf7f52SDaniel P. Berrange 22952f262e06SPaolo Bonzini static void object_instance_init(Object *obj) 22962f262e06SPaolo Bonzini { 22972f262e06SPaolo Bonzini object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); 22982f262e06SPaolo Bonzini } 22992f262e06SPaolo Bonzini 2300745549c8SPaolo Bonzini static void register_types(void) 2301745549c8SPaolo Bonzini { 2302745549c8SPaolo Bonzini static TypeInfo interface_info = { 2303745549c8SPaolo Bonzini .name = TYPE_INTERFACE, 230433e95c63SAnthony Liguori .class_size = sizeof(InterfaceClass), 2305745549c8SPaolo Bonzini .abstract = true, 2306745549c8SPaolo Bonzini }; 2307745549c8SPaolo Bonzini 2308745549c8SPaolo Bonzini static TypeInfo object_info = { 2309745549c8SPaolo Bonzini .name = TYPE_OBJECT, 2310745549c8SPaolo Bonzini .instance_size = sizeof(Object), 23112f262e06SPaolo Bonzini .instance_init = object_instance_init, 2312745549c8SPaolo Bonzini .abstract = true, 2313745549c8SPaolo Bonzini }; 2314745549c8SPaolo Bonzini 2315049cb3cfSPaolo Bonzini type_interface = type_register_internal(&interface_info); 2316049cb3cfSPaolo Bonzini type_register_internal(&object_info); 2317745549c8SPaolo Bonzini } 2318745549c8SPaolo Bonzini 2319745549c8SPaolo Bonzini type_init(register_types) 2320