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" 1413d4ff07SMarkus Armbruster #include "hw/qdev-core.h" 15da34e65cSMarkus Armbruster #include "qapi/error.h" 1614cccb61SPaolo Bonzini #include "qom/object.h" 17a31bdae5SDaniel P. Berrange #include "qom/object_interfaces.h" 18f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 197b1b5d19SPaolo Bonzini #include "qapi/visitor.h" 20b2cd7deeSPaolo Bonzini #include "qapi/string-input-visitor.h" 21b2cd7deeSPaolo Bonzini #include "qapi/string-output-visitor.h" 220e76ed0aSMarc-André Lureau #include "qapi/qobject-input-visitor.h" 23eb815e24SMarkus Armbruster #include "qapi/qapi-builtin-visit.h" 247b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h" 250e76ed0aSMarc-André Lureau #include "qapi/qmp/qjson.h" 26fa131d94SPaolo Bonzini #include "trace.h" 272f28d2ffSAnthony Liguori 287b7b7d18SPaolo Bonzini /* TODO: replace QObject with a simpler visitor to avoid a dependency 297b7b7d18SPaolo Bonzini * of the QOM core on QObject? */ 3014cccb61SPaolo Bonzini #include "qom/qom-qobject.h" 317b1b5d19SPaolo Bonzini #include "qapi/qmp/qbool.h" 3215280c36SMarkus Armbruster #include "qapi/qmp/qnum.h" 337b1b5d19SPaolo Bonzini #include "qapi/qmp/qstring.h" 34e02bdf1cSPhilippe Mathieu-Daudé #include "qemu/error-report.h" 357b7b7d18SPaolo Bonzini 362f28d2ffSAnthony Liguori #define MAX_INTERFACES 32 372f28d2ffSAnthony Liguori 382f28d2ffSAnthony Liguori typedef struct InterfaceImpl InterfaceImpl; 392f28d2ffSAnthony Liguori typedef struct TypeImpl TypeImpl; 402f28d2ffSAnthony Liguori 412f28d2ffSAnthony Liguori struct InterfaceImpl 422f28d2ffSAnthony Liguori { 4333e95c63SAnthony Liguori const char *typename; 442f28d2ffSAnthony Liguori }; 452f28d2ffSAnthony Liguori 462f28d2ffSAnthony Liguori struct TypeImpl 472f28d2ffSAnthony Liguori { 482f28d2ffSAnthony Liguori const char *name; 492f28d2ffSAnthony Liguori 502f28d2ffSAnthony Liguori size_t class_size; 512f28d2ffSAnthony Liguori 522f28d2ffSAnthony Liguori size_t instance_size; 532f28d2ffSAnthony Liguori 542f28d2ffSAnthony Liguori void (*class_init)(ObjectClass *klass, void *data); 553b50e311SPaolo Bonzini void (*class_base_init)(ObjectClass *klass, void *data); 562f28d2ffSAnthony Liguori 572f28d2ffSAnthony Liguori void *class_data; 582f28d2ffSAnthony Liguori 592f28d2ffSAnthony Liguori void (*instance_init)(Object *obj); 608231c2ddSEduardo Habkost void (*instance_post_init)(Object *obj); 612f28d2ffSAnthony Liguori void (*instance_finalize)(Object *obj); 622f28d2ffSAnthony Liguori 632f28d2ffSAnthony Liguori bool abstract; 642f28d2ffSAnthony Liguori 652f28d2ffSAnthony Liguori const char *parent; 662f28d2ffSAnthony Liguori TypeImpl *parent_type; 672f28d2ffSAnthony Liguori 682f28d2ffSAnthony Liguori ObjectClass *class; 692f28d2ffSAnthony Liguori 702f28d2ffSAnthony Liguori int num_interfaces; 712f28d2ffSAnthony Liguori InterfaceImpl interfaces[MAX_INTERFACES]; 722f28d2ffSAnthony Liguori }; 732f28d2ffSAnthony Liguori 749970bd88SPaolo Bonzini static Type type_interface; 759970bd88SPaolo Bonzini 762f28d2ffSAnthony Liguori static GHashTable *type_table_get(void) 772f28d2ffSAnthony Liguori { 782f28d2ffSAnthony Liguori static GHashTable *type_table; 792f28d2ffSAnthony Liguori 802f28d2ffSAnthony Liguori if (type_table == NULL) { 812f28d2ffSAnthony Liguori type_table = g_hash_table_new(g_str_hash, g_str_equal); 822f28d2ffSAnthony Liguori } 832f28d2ffSAnthony Liguori 842f28d2ffSAnthony Liguori return type_table; 852f28d2ffSAnthony Liguori } 862f28d2ffSAnthony Liguori 87f54c19caSHervé Poussineau static bool enumerating_types; 88f54c19caSHervé Poussineau 892f28d2ffSAnthony Liguori static void type_table_add(TypeImpl *ti) 902f28d2ffSAnthony Liguori { 91f54c19caSHervé Poussineau assert(!enumerating_types); 922f28d2ffSAnthony Liguori g_hash_table_insert(type_table_get(), (void *)ti->name, ti); 932f28d2ffSAnthony Liguori } 942f28d2ffSAnthony Liguori 952f28d2ffSAnthony Liguori static TypeImpl *type_table_lookup(const char *name) 962f28d2ffSAnthony Liguori { 972f28d2ffSAnthony Liguori return g_hash_table_lookup(type_table_get(), name); 982f28d2ffSAnthony Liguori } 992f28d2ffSAnthony Liguori 100b061dc41SPaolo Bonzini static TypeImpl *type_new(const TypeInfo *info) 1012f28d2ffSAnthony Liguori { 1022f28d2ffSAnthony Liguori TypeImpl *ti = g_malloc0(sizeof(*ti)); 10333e95c63SAnthony Liguori int i; 1042f28d2ffSAnthony Liguori 1052f28d2ffSAnthony Liguori g_assert(info->name != NULL); 1062f28d2ffSAnthony Liguori 10773093354SAnthony Liguori if (type_table_lookup(info->name) != NULL) { 10873093354SAnthony Liguori fprintf(stderr, "Registering `%s' which already exists\n", info->name); 10973093354SAnthony Liguori abort(); 11073093354SAnthony Liguori } 11173093354SAnthony Liguori 1122f28d2ffSAnthony Liguori ti->name = g_strdup(info->name); 1132f28d2ffSAnthony Liguori ti->parent = g_strdup(info->parent); 1142f28d2ffSAnthony Liguori 1152f28d2ffSAnthony Liguori ti->class_size = info->class_size; 1162f28d2ffSAnthony Liguori ti->instance_size = info->instance_size; 1172f28d2ffSAnthony Liguori 1182f28d2ffSAnthony Liguori ti->class_init = info->class_init; 1193b50e311SPaolo Bonzini ti->class_base_init = info->class_base_init; 1202f28d2ffSAnthony Liguori ti->class_data = info->class_data; 1212f28d2ffSAnthony Liguori 1222f28d2ffSAnthony Liguori ti->instance_init = info->instance_init; 1238231c2ddSEduardo Habkost ti->instance_post_init = info->instance_post_init; 1242f28d2ffSAnthony Liguori ti->instance_finalize = info->instance_finalize; 1252f28d2ffSAnthony Liguori 1262f28d2ffSAnthony Liguori ti->abstract = info->abstract; 1272f28d2ffSAnthony Liguori 12833e95c63SAnthony Liguori for (i = 0; info->interfaces && info->interfaces[i].type; i++) { 12933e95c63SAnthony Liguori ti->interfaces[i].typename = g_strdup(info->interfaces[i].type); 1302f28d2ffSAnthony Liguori } 13133e95c63SAnthony Liguori ti->num_interfaces = i; 1322f28d2ffSAnthony Liguori 133b061dc41SPaolo Bonzini return ti; 134b061dc41SPaolo Bonzini } 1352f28d2ffSAnthony Liguori 136b061dc41SPaolo Bonzini static TypeImpl *type_register_internal(const TypeInfo *info) 137b061dc41SPaolo Bonzini { 138b061dc41SPaolo Bonzini TypeImpl *ti; 139b061dc41SPaolo Bonzini ti = type_new(info); 140b061dc41SPaolo Bonzini 141b061dc41SPaolo Bonzini type_table_add(ti); 1422f28d2ffSAnthony Liguori return ti; 1432f28d2ffSAnthony Liguori } 1442f28d2ffSAnthony Liguori 145049cb3cfSPaolo Bonzini TypeImpl *type_register(const TypeInfo *info) 146049cb3cfSPaolo Bonzini { 147049cb3cfSPaolo Bonzini assert(info->parent); 148049cb3cfSPaolo Bonzini return type_register_internal(info); 149049cb3cfSPaolo Bonzini } 150049cb3cfSPaolo Bonzini 1512f28d2ffSAnthony Liguori TypeImpl *type_register_static(const TypeInfo *info) 1522f28d2ffSAnthony Liguori { 1532f28d2ffSAnthony Liguori return type_register(info); 1542f28d2ffSAnthony Liguori } 1552f28d2ffSAnthony Liguori 156aa04c9d2SIgor Mammedov void type_register_static_array(const TypeInfo *infos, int nr_infos) 157aa04c9d2SIgor Mammedov { 158aa04c9d2SIgor Mammedov int i; 159aa04c9d2SIgor Mammedov 160aa04c9d2SIgor Mammedov for (i = 0; i < nr_infos; i++) { 161aa04c9d2SIgor Mammedov type_register_static(&infos[i]); 162aa04c9d2SIgor Mammedov } 163aa04c9d2SIgor Mammedov } 164aa04c9d2SIgor Mammedov 1652f28d2ffSAnthony Liguori static TypeImpl *type_get_by_name(const char *name) 1662f28d2ffSAnthony Liguori { 1672f28d2ffSAnthony Liguori if (name == NULL) { 1682f28d2ffSAnthony Liguori return NULL; 1692f28d2ffSAnthony Liguori } 1702f28d2ffSAnthony Liguori 1712f28d2ffSAnthony Liguori return type_table_lookup(name); 1722f28d2ffSAnthony Liguori } 1732f28d2ffSAnthony Liguori 1742f28d2ffSAnthony Liguori static TypeImpl *type_get_parent(TypeImpl *type) 1752f28d2ffSAnthony Liguori { 1762f28d2ffSAnthony Liguori if (!type->parent_type && type->parent) { 1772f28d2ffSAnthony Liguori type->parent_type = type_get_by_name(type->parent); 17889d337fdSPhilippe Mathieu-Daudé if (!type->parent_type) { 17989d337fdSPhilippe Mathieu-Daudé fprintf(stderr, "Type '%s' is missing its parent '%s'\n", 18089d337fdSPhilippe Mathieu-Daudé type->name, type->parent); 18189d337fdSPhilippe Mathieu-Daudé abort(); 18289d337fdSPhilippe Mathieu-Daudé } 1832f28d2ffSAnthony Liguori } 1842f28d2ffSAnthony Liguori 1852f28d2ffSAnthony Liguori return type->parent_type; 1862f28d2ffSAnthony Liguori } 1872f28d2ffSAnthony Liguori 1882f28d2ffSAnthony Liguori static bool type_has_parent(TypeImpl *type) 1892f28d2ffSAnthony Liguori { 1902f28d2ffSAnthony Liguori return (type->parent != NULL); 1912f28d2ffSAnthony Liguori } 1922f28d2ffSAnthony Liguori 1932f28d2ffSAnthony Liguori static size_t type_class_get_size(TypeImpl *ti) 1942f28d2ffSAnthony Liguori { 1952f28d2ffSAnthony Liguori if (ti->class_size) { 1962f28d2ffSAnthony Liguori return ti->class_size; 1972f28d2ffSAnthony Liguori } 1982f28d2ffSAnthony Liguori 1992f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 2002f28d2ffSAnthony Liguori return type_class_get_size(type_get_parent(ti)); 2012f28d2ffSAnthony Liguori } 2022f28d2ffSAnthony Liguori 2032f28d2ffSAnthony Liguori return sizeof(ObjectClass); 2042f28d2ffSAnthony Liguori } 2052f28d2ffSAnthony Liguori 206aca59af6SIgor Mitsyanko static size_t type_object_get_size(TypeImpl *ti) 207aca59af6SIgor Mitsyanko { 208aca59af6SIgor Mitsyanko if (ti->instance_size) { 209aca59af6SIgor Mitsyanko return ti->instance_size; 210aca59af6SIgor Mitsyanko } 211aca59af6SIgor Mitsyanko 212aca59af6SIgor Mitsyanko if (type_has_parent(ti)) { 213aca59af6SIgor Mitsyanko return type_object_get_size(type_get_parent(ti)); 214aca59af6SIgor Mitsyanko } 215aca59af6SIgor Mitsyanko 216aca59af6SIgor Mitsyanko return 0; 217aca59af6SIgor Mitsyanko } 218aca59af6SIgor Mitsyanko 2193f97b53aSBharata B Rao size_t object_type_get_instance_size(const char *typename) 2203f97b53aSBharata B Rao { 2213f97b53aSBharata B Rao TypeImpl *type = type_get_by_name(typename); 2223f97b53aSBharata B Rao 2233f97b53aSBharata B Rao g_assert(type != NULL); 2243f97b53aSBharata B Rao return type_object_get_size(type); 2253f97b53aSBharata B Rao } 2263f97b53aSBharata B Rao 22733e95c63SAnthony Liguori static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) 2282f28d2ffSAnthony Liguori { 22933e95c63SAnthony Liguori assert(target_type); 2302f28d2ffSAnthony Liguori 231b30d8054SCao jin /* Check if target_type is a direct ancestor of type */ 23233e95c63SAnthony Liguori while (type) { 23333e95c63SAnthony Liguori if (type == target_type) { 23433e95c63SAnthony Liguori return true; 23533e95c63SAnthony Liguori } 23633e95c63SAnthony Liguori 23733e95c63SAnthony Liguori type = type_get_parent(type); 23833e95c63SAnthony Liguori } 23933e95c63SAnthony Liguori 24033e95c63SAnthony Liguori return false; 24133e95c63SAnthony Liguori } 24233e95c63SAnthony Liguori 24333e95c63SAnthony Liguori static void type_initialize(TypeImpl *ti); 24433e95c63SAnthony Liguori 245b061dc41SPaolo Bonzini static void type_initialize_interface(TypeImpl *ti, TypeImpl *interface_type, 246b061dc41SPaolo Bonzini TypeImpl *parent_type) 24733e95c63SAnthony Liguori { 24833e95c63SAnthony Liguori InterfaceClass *new_iface; 24933e95c63SAnthony Liguori TypeInfo info = { }; 25033e95c63SAnthony Liguori TypeImpl *iface_impl; 25133e95c63SAnthony Liguori 252b061dc41SPaolo Bonzini info.parent = parent_type->name; 253b061dc41SPaolo Bonzini info.name = g_strdup_printf("%s::%s", ti->name, interface_type->name); 25433e95c63SAnthony Liguori info.abstract = true; 25533e95c63SAnthony Liguori 256b061dc41SPaolo Bonzini iface_impl = type_new(&info); 257b061dc41SPaolo Bonzini iface_impl->parent_type = parent_type; 25833e95c63SAnthony Liguori type_initialize(iface_impl); 25933e95c63SAnthony Liguori g_free((char *)info.name); 26033e95c63SAnthony Liguori 26133e95c63SAnthony Liguori new_iface = (InterfaceClass *)iface_impl->class; 26233e95c63SAnthony Liguori new_iface->concrete_class = ti->class; 263b061dc41SPaolo Bonzini new_iface->interface_type = interface_type; 26433e95c63SAnthony Liguori 26533e95c63SAnthony Liguori ti->class->interfaces = g_slist_append(ti->class->interfaces, 26633e95c63SAnthony Liguori iface_impl->class); 2672f28d2ffSAnthony Liguori } 2682f28d2ffSAnthony Liguori 26916bf7f52SDaniel P. Berrange static void object_property_free(gpointer data) 27016bf7f52SDaniel P. Berrange { 27116bf7f52SDaniel P. Berrange ObjectProperty *prop = data; 27216bf7f52SDaniel P. Berrange 2730e76ed0aSMarc-André Lureau if (prop->defval) { 2740e76ed0aSMarc-André Lureau qobject_unref(prop->defval); 2750e76ed0aSMarc-André Lureau prop->defval = NULL; 2760e76ed0aSMarc-André Lureau } 27716bf7f52SDaniel P. Berrange g_free(prop->name); 27816bf7f52SDaniel P. Berrange g_free(prop->type); 27916bf7f52SDaniel P. Berrange g_free(prop->description); 28016bf7f52SDaniel P. Berrange g_free(prop); 28116bf7f52SDaniel P. Berrange } 28216bf7f52SDaniel P. Berrange 283ac451033SIgor Mitsyanko static void type_initialize(TypeImpl *ti) 2842f28d2ffSAnthony Liguori { 285745549c8SPaolo Bonzini TypeImpl *parent; 2862f28d2ffSAnthony Liguori 2872f28d2ffSAnthony Liguori if (ti->class) { 2882f28d2ffSAnthony Liguori return; 2892f28d2ffSAnthony Liguori } 2902f28d2ffSAnthony Liguori 2912f28d2ffSAnthony Liguori ti->class_size = type_class_get_size(ti); 292aca59af6SIgor Mitsyanko ti->instance_size = type_object_get_size(ti); 2931c6d75d5SEduardo Habkost /* Any type with zero instance_size is implicitly abstract. 2941c6d75d5SEduardo Habkost * This means interface types are all abstract. 2951c6d75d5SEduardo Habkost */ 2961c6d75d5SEduardo Habkost if (ti->instance_size == 0) { 2971c6d75d5SEduardo Habkost ti->abstract = true; 2981c6d75d5SEduardo Habkost } 299422ca143SMarc-André Lureau if (type_is_ancestor(ti, type_interface)) { 300422ca143SMarc-André Lureau assert(ti->instance_size == 0); 301422ca143SMarc-André Lureau assert(ti->abstract); 302422ca143SMarc-André Lureau assert(!ti->instance_init); 303422ca143SMarc-André Lureau assert(!ti->instance_post_init); 304422ca143SMarc-André Lureau assert(!ti->instance_finalize); 305422ca143SMarc-André Lureau assert(!ti->num_interfaces); 306422ca143SMarc-André Lureau } 3072f28d2ffSAnthony Liguori ti->class = g_malloc0(ti->class_size); 3082f28d2ffSAnthony Liguori 309745549c8SPaolo Bonzini parent = type_get_parent(ti); 310745549c8SPaolo Bonzini if (parent) { 311ac451033SIgor Mitsyanko type_initialize(parent); 31233e95c63SAnthony Liguori GSList *e; 31333e95c63SAnthony Liguori int i; 3142f28d2ffSAnthony Liguori 315719a3077SMarkus Armbruster g_assert(parent->class_size <= ti->class_size); 316d5e633fcSMarc-André Lureau g_assert(parent->instance_size <= ti->instance_size); 317745549c8SPaolo Bonzini memcpy(ti->class, parent->class, parent->class_size); 3183e407de4SPeter Crosthwaite ti->class->interfaces = NULL; 31916bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 320ba806ffbSMarc-André Lureau g_str_hash, g_str_equal, NULL, object_property_free); 32133e95c63SAnthony Liguori 32233e95c63SAnthony Liguori for (e = parent->class->interfaces; e; e = e->next) { 323b061dc41SPaolo Bonzini InterfaceClass *iface = e->data; 324b061dc41SPaolo Bonzini ObjectClass *klass = OBJECT_CLASS(iface); 325b061dc41SPaolo Bonzini 326b061dc41SPaolo Bonzini type_initialize_interface(ti, iface->interface_type, klass->type); 32733e95c63SAnthony Liguori } 32833e95c63SAnthony Liguori 32933e95c63SAnthony Liguori for (i = 0; i < ti->num_interfaces; i++) { 33033e95c63SAnthony Liguori TypeImpl *t = type_get_by_name(ti->interfaces[i].typename); 331a9ee3a9eSPhilippe Mathieu-Daudé if (!t) { 332a9ee3a9eSPhilippe Mathieu-Daudé error_report("missing interface '%s' for object '%s'", 333a9ee3a9eSPhilippe Mathieu-Daudé ti->interfaces[i].typename, parent->name); 334a9ee3a9eSPhilippe Mathieu-Daudé abort(); 335a9ee3a9eSPhilippe Mathieu-Daudé } 33633e95c63SAnthony Liguori for (e = ti->class->interfaces; e; e = e->next) { 33733e95c63SAnthony Liguori TypeImpl *target_type = OBJECT_CLASS(e->data)->type; 33833e95c63SAnthony Liguori 33933e95c63SAnthony Liguori if (type_is_ancestor(target_type, t)) { 34033e95c63SAnthony Liguori break; 34133e95c63SAnthony Liguori } 34233e95c63SAnthony Liguori } 34333e95c63SAnthony Liguori 34433e95c63SAnthony Liguori if (e) { 34533e95c63SAnthony Liguori continue; 34633e95c63SAnthony Liguori } 34733e95c63SAnthony Liguori 348b061dc41SPaolo Bonzini type_initialize_interface(ti, t, t); 34933e95c63SAnthony Liguori } 35016bf7f52SDaniel P. Berrange } else { 35116bf7f52SDaniel P. Berrange ti->class->properties = g_hash_table_new_full( 352ba806ffbSMarc-André Lureau g_str_hash, g_str_equal, NULL, object_property_free); 353745549c8SPaolo Bonzini } 3542f28d2ffSAnthony Liguori 355745549c8SPaolo Bonzini ti->class->type = ti; 3563b50e311SPaolo Bonzini 3573b50e311SPaolo Bonzini while (parent) { 3583b50e311SPaolo Bonzini if (parent->class_base_init) { 3593b50e311SPaolo Bonzini parent->class_base_init(ti->class, ti->class_data); 3603b50e311SPaolo Bonzini } 3613b50e311SPaolo Bonzini parent = type_get_parent(parent); 3623b50e311SPaolo Bonzini } 3632f28d2ffSAnthony Liguori 3642f28d2ffSAnthony Liguori if (ti->class_init) { 3652f28d2ffSAnthony Liguori ti->class_init(ti->class, ti->class_data); 3662f28d2ffSAnthony Liguori } 3672f28d2ffSAnthony Liguori } 3682f28d2ffSAnthony Liguori 3692f28d2ffSAnthony Liguori static void object_init_with_type(Object *obj, TypeImpl *ti) 3702f28d2ffSAnthony Liguori { 3712f28d2ffSAnthony Liguori if (type_has_parent(ti)) { 3722f28d2ffSAnthony Liguori object_init_with_type(obj, type_get_parent(ti)); 3732f28d2ffSAnthony Liguori } 3742f28d2ffSAnthony Liguori 3752f28d2ffSAnthony Liguori if (ti->instance_init) { 3762f28d2ffSAnthony Liguori ti->instance_init(obj); 3772f28d2ffSAnthony Liguori } 3782f28d2ffSAnthony Liguori } 3792f28d2ffSAnthony Liguori 3808231c2ddSEduardo Habkost static void object_post_init_with_type(Object *obj, TypeImpl *ti) 3818231c2ddSEduardo Habkost { 3828231c2ddSEduardo Habkost if (ti->instance_post_init) { 3838231c2ddSEduardo Habkost ti->instance_post_init(obj); 3848231c2ddSEduardo Habkost } 3858231c2ddSEduardo Habkost 3868231c2ddSEduardo Habkost if (type_has_parent(ti)) { 3878231c2ddSEduardo Habkost object_post_init_with_type(obj, type_get_parent(ti)); 3888231c2ddSEduardo Habkost } 3898231c2ddSEduardo Habkost } 3908231c2ddSEduardo Habkost 391ea9ce893SMarc-André Lureau void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp) 392ea9ce893SMarc-André Lureau { 393ea9ce893SMarc-André Lureau int i; 394ea9ce893SMarc-André Lureau 395ea9ce893SMarc-André Lureau if (!props) { 396ea9ce893SMarc-André Lureau return; 397ea9ce893SMarc-André Lureau } 398ea9ce893SMarc-André Lureau 399ea9ce893SMarc-André Lureau for (i = 0; i < props->len; i++) { 400ea9ce893SMarc-André Lureau GlobalProperty *p = g_ptr_array_index(props, i); 401d769f0dfSEduardo Habkost Error *err = NULL; 402ea9ce893SMarc-André Lureau 403ea9ce893SMarc-André Lureau if (object_dynamic_cast(obj, p->driver) == NULL) { 404ea9ce893SMarc-André Lureau continue; 405ea9ce893SMarc-André Lureau } 40692fd453cSDr. David Alan Gilbert if (p->optional && !object_property_find(obj, p->property, NULL)) { 40792fd453cSDr. David Alan Gilbert continue; 40892fd453cSDr. David Alan Gilbert } 409ea9ce893SMarc-André Lureau p->used = true; 410ea9ce893SMarc-André Lureau object_property_parse(obj, p->value, p->property, &err); 411ea9ce893SMarc-André Lureau if (err != NULL) { 412ea9ce893SMarc-André Lureau error_prepend(&err, "can't apply global %s.%s=%s: ", 413ea9ce893SMarc-André Lureau p->driver, p->property, p->value); 41450545b2cSMarc-André Lureau /* 41550545b2cSMarc-André Lureau * If errp != NULL, propagate error and return. 41650545b2cSMarc-André Lureau * If errp == NULL, report a warning, but keep going 41750545b2cSMarc-André Lureau * with the remaining globals. 41850545b2cSMarc-André Lureau */ 41950545b2cSMarc-André Lureau if (errp) { 420ea9ce893SMarc-André Lureau error_propagate(errp, err); 42150545b2cSMarc-André Lureau return; 42250545b2cSMarc-André Lureau } else { 42350545b2cSMarc-André Lureau warn_report_err(err); 42450545b2cSMarc-André Lureau } 425ea9ce893SMarc-André Lureau } 426ea9ce893SMarc-André Lureau } 427ea9ce893SMarc-André Lureau } 428ea9ce893SMarc-André Lureau 429617902afSMarkus Armbruster /* 430617902afSMarkus Armbruster * Global property defaults 431617902afSMarkus Armbruster * Slot 0: accelerator's global property defaults 432617902afSMarkus Armbruster * Slot 1: machine's global property defaults 4331fff3c20SPaolo Bonzini * Slot 2: global properties from legacy command line option 434617902afSMarkus Armbruster * Each is a GPtrArray of of GlobalProperty. 435617902afSMarkus Armbruster * Applied in order, later entries override earlier ones. 436617902afSMarkus Armbruster */ 4371fff3c20SPaolo Bonzini static GPtrArray *object_compat_props[3]; 4381fff3c20SPaolo Bonzini 4391fff3c20SPaolo Bonzini /* 4401fff3c20SPaolo Bonzini * Retrieve @GPtrArray for global property defined with options 4411fff3c20SPaolo Bonzini * other than "-global". These are generally used for syntactic 4421fff3c20SPaolo Bonzini * sugar and legacy command line options. 4431fff3c20SPaolo Bonzini */ 4441fff3c20SPaolo Bonzini void object_register_sugar_prop(const char *driver, const char *prop, const char *value) 4451fff3c20SPaolo Bonzini { 4461fff3c20SPaolo Bonzini GlobalProperty *g; 4471fff3c20SPaolo Bonzini if (!object_compat_props[2]) { 4481fff3c20SPaolo Bonzini object_compat_props[2] = g_ptr_array_new(); 4491fff3c20SPaolo Bonzini } 4501fff3c20SPaolo Bonzini g = g_new0(GlobalProperty, 1); 4511fff3c20SPaolo Bonzini g->driver = g_strdup(driver); 4521fff3c20SPaolo Bonzini g->property = g_strdup(prop); 4531fff3c20SPaolo Bonzini g->value = g_strdup(value); 4541fff3c20SPaolo Bonzini g_ptr_array_add(object_compat_props[2], g); 4551fff3c20SPaolo Bonzini } 456617902afSMarkus Armbruster 457617902afSMarkus Armbruster /* 458617902afSMarkus Armbruster * Set machine's global property defaults to @compat_props. 459617902afSMarkus Armbruster * May be called at most once. 460617902afSMarkus Armbruster */ 461617902afSMarkus Armbruster void object_set_machine_compat_props(GPtrArray *compat_props) 462617902afSMarkus Armbruster { 463617902afSMarkus Armbruster assert(!object_compat_props[1]); 464617902afSMarkus Armbruster object_compat_props[1] = compat_props; 465617902afSMarkus Armbruster } 466617902afSMarkus Armbruster 467617902afSMarkus Armbruster /* 468617902afSMarkus Armbruster * Set accelerator's global property defaults to @compat_props. 469617902afSMarkus Armbruster * May be called at most once. 470617902afSMarkus Armbruster */ 471617902afSMarkus Armbruster void object_set_accelerator_compat_props(GPtrArray *compat_props) 472617902afSMarkus Armbruster { 473617902afSMarkus Armbruster assert(!object_compat_props[0]); 474617902afSMarkus Armbruster object_compat_props[0] = compat_props; 475617902afSMarkus Armbruster } 476617902afSMarkus Armbruster 477617902afSMarkus Armbruster void object_apply_compat_props(Object *obj) 478617902afSMarkus Armbruster { 479617902afSMarkus Armbruster int i; 480617902afSMarkus Armbruster 481617902afSMarkus Armbruster for (i = 0; i < ARRAY_SIZE(object_compat_props); i++) { 482617902afSMarkus Armbruster object_apply_global_props(obj, object_compat_props[i], 4831fff3c20SPaolo Bonzini i == 2 ? &error_fatal : &error_abort); 484617902afSMarkus Armbruster } 485617902afSMarkus Armbruster } 486617902afSMarkus Armbruster 4872a1be4b3SMarc-André Lureau static void object_class_property_init_all(Object *obj) 4882a1be4b3SMarc-André Lureau { 4892a1be4b3SMarc-André Lureau ObjectPropertyIterator iter; 4902a1be4b3SMarc-André Lureau ObjectProperty *prop; 4912a1be4b3SMarc-André Lureau 4922a1be4b3SMarc-André Lureau object_class_property_iter_init(&iter, object_get_class(obj)); 4932a1be4b3SMarc-André Lureau while ((prop = object_property_iter_next(&iter))) { 4942a1be4b3SMarc-André Lureau if (prop->init) { 4952a1be4b3SMarc-André Lureau prop->init(obj, prop); 4962a1be4b3SMarc-André Lureau } 4972a1be4b3SMarc-André Lureau } 4982a1be4b3SMarc-André Lureau } 4992a1be4b3SMarc-André Lureau 50063f7b10bSMarc-André Lureau static void object_initialize_with_type(void *data, size_t size, TypeImpl *type) 5012f28d2ffSAnthony Liguori { 5022f28d2ffSAnthony Liguori Object *obj = data; 5032f28d2ffSAnthony Liguori 504ac451033SIgor Mitsyanko type_initialize(type); 505aca59af6SIgor Mitsyanko 506719a3077SMarkus Armbruster g_assert(type->instance_size >= sizeof(Object)); 5072f28d2ffSAnthony Liguori g_assert(type->abstract == false); 508719a3077SMarkus Armbruster g_assert(size >= type->instance_size); 5092f28d2ffSAnthony Liguori 5102f28d2ffSAnthony Liguori memset(obj, 0, type->instance_size); 5112f28d2ffSAnthony Liguori obj->class = type->class; 512764b6312SPaolo Bonzini object_ref(obj); 5132a1be4b3SMarc-André Lureau object_class_property_init_all(obj); 514b604a854SPavel Fedin obj->properties = g_hash_table_new_full(g_str_hash, g_str_equal, 515b604a854SPavel Fedin NULL, object_property_free); 5162f28d2ffSAnthony Liguori object_init_with_type(obj, type); 5178231c2ddSEduardo Habkost object_post_init_with_type(obj, type); 5182f28d2ffSAnthony Liguori } 5192f28d2ffSAnthony Liguori 520213f0c4fSAndreas Färber void object_initialize(void *data, size_t size, const char *typename) 5212f28d2ffSAnthony Liguori { 5222f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 5232f28d2ffSAnthony Liguori 524e02bdf1cSPhilippe Mathieu-Daudé if (!type) { 525e02bdf1cSPhilippe Mathieu-Daudé error_report("missing object type '%s'", typename); 526e02bdf1cSPhilippe Mathieu-Daudé abort(); 527e02bdf1cSPhilippe Mathieu-Daudé } 528e02bdf1cSPhilippe Mathieu-Daudé 5295b9237f6SAndreas Färber object_initialize_with_type(data, size, type); 5302f28d2ffSAnthony Liguori } 5312f28d2ffSAnthony Liguori 5320210b39dSThomas Huth void object_initialize_child(Object *parentobj, const char *propname, 5330210b39dSThomas Huth void *childobj, size_t size, const char *type, 5340210b39dSThomas Huth Error **errp, ...) 5350210b39dSThomas Huth { 5360210b39dSThomas Huth va_list vargs; 5370210b39dSThomas Huth 5380210b39dSThomas Huth va_start(vargs, errp); 5390210b39dSThomas Huth object_initialize_childv(parentobj, propname, childobj, size, type, errp, 5400210b39dSThomas Huth vargs); 5410210b39dSThomas Huth va_end(vargs); 5420210b39dSThomas Huth } 5430210b39dSThomas Huth 5440210b39dSThomas Huth void object_initialize_childv(Object *parentobj, const char *propname, 5450210b39dSThomas Huth void *childobj, size_t size, const char *type, 5460210b39dSThomas Huth Error **errp, va_list vargs) 5470210b39dSThomas Huth { 5480210b39dSThomas Huth Error *local_err = NULL; 5490210b39dSThomas Huth Object *obj; 5503650b2deSMarc-André Lureau UserCreatable *uc; 5510210b39dSThomas Huth 5520210b39dSThomas Huth object_initialize(childobj, size, type); 5530210b39dSThomas Huth obj = OBJECT(childobj); 5540210b39dSThomas Huth 5550210b39dSThomas Huth object_set_propv(obj, &local_err, vargs); 5560210b39dSThomas Huth if (local_err) { 5570210b39dSThomas Huth goto out; 5580210b39dSThomas Huth } 5590210b39dSThomas Huth 5600210b39dSThomas Huth object_property_add_child(parentobj, propname, obj, &local_err); 5610210b39dSThomas Huth if (local_err) { 5620210b39dSThomas Huth goto out; 5630210b39dSThomas Huth } 5640210b39dSThomas Huth 5653650b2deSMarc-André Lureau uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); 5663650b2deSMarc-André Lureau if (uc) { 5673650b2deSMarc-André Lureau user_creatable_complete(uc, &local_err); 5680210b39dSThomas Huth if (local_err) { 5690210b39dSThomas Huth object_unparent(obj); 5700210b39dSThomas Huth goto out; 5710210b39dSThomas Huth } 5720210b39dSThomas Huth } 5730210b39dSThomas Huth 5740210b39dSThomas Huth /* 5750210b39dSThomas Huth * Since object_property_add_child added a reference to the child object, 5760210b39dSThomas Huth * we can drop the reference added by object_initialize(), so the child 5770210b39dSThomas Huth * property will own the only reference to the object. 5780210b39dSThomas Huth */ 5790210b39dSThomas Huth object_unref(obj); 5800210b39dSThomas Huth 5810210b39dSThomas Huth out: 5820210b39dSThomas Huth if (local_err) { 5830210b39dSThomas Huth error_propagate(errp, local_err); 5840210b39dSThomas Huth object_unref(obj); 5850210b39dSThomas Huth } 5860210b39dSThomas Huth } 5870210b39dSThomas Huth 5885d9d3f47SAndreas Färber static inline bool object_property_is_child(ObjectProperty *prop) 5895d9d3f47SAndreas Färber { 5905d9d3f47SAndreas Färber return strstart(prop->type, "child<", NULL); 5915d9d3f47SAndreas Färber } 5925d9d3f47SAndreas Färber 59357c9fafeSAnthony Liguori static void object_property_del_all(Object *obj) 59457c9fafeSAnthony Liguori { 595*9859faccSMarc-André Lureau g_autoptr(GHashTable) done = g_hash_table_new(NULL, NULL); 596b604a854SPavel Fedin ObjectProperty *prop; 597*9859faccSMarc-André Lureau ObjectPropertyIterator iter; 598b604a854SPavel Fedin bool released; 59957c9fafeSAnthony Liguori 600b604a854SPavel Fedin do { 601b604a854SPavel Fedin released = false; 602*9859faccSMarc-André Lureau object_property_iter_init(&iter, obj); 603*9859faccSMarc-André Lureau while ((prop = object_property_iter_next(&iter)) != NULL) { 604*9859faccSMarc-André Lureau if (g_hash_table_add(done, prop)) { 60557c9fafeSAnthony Liguori if (prop->release) { 60657c9fafeSAnthony Liguori prop->release(obj, prop->name, prop->opaque); 607b604a854SPavel Fedin released = true; 608b604a854SPavel Fedin break; 60957c9fafeSAnthony Liguori } 610*9859faccSMarc-André Lureau } 611b604a854SPavel Fedin } 612b604a854SPavel Fedin } while (released); 61357c9fafeSAnthony Liguori 614b604a854SPavel Fedin g_hash_table_unref(obj->properties); 61557c9fafeSAnthony Liguori } 61657c9fafeSAnthony Liguori 61757c9fafeSAnthony Liguori static void object_property_del_child(Object *obj, Object *child, Error **errp) 61857c9fafeSAnthony Liguori { 61957c9fafeSAnthony Liguori ObjectProperty *prop; 620b604a854SPavel Fedin GHashTableIter iter; 621b604a854SPavel Fedin gpointer key, value; 62257c9fafeSAnthony Liguori 623b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 624b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 625b604a854SPavel Fedin prop = value; 6265d9d3f47SAndreas Färber if (object_property_is_child(prop) && prop->opaque == child) { 627b604a854SPavel Fedin if (prop->release) { 628b604a854SPavel Fedin prop->release(obj, prop->name, prop->opaque); 629b604a854SPavel Fedin prop->release = NULL; 630b604a854SPavel Fedin } 631b604a854SPavel Fedin break; 632b604a854SPavel Fedin } 633b604a854SPavel Fedin } 634b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 635b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, &key, &value)) { 636b604a854SPavel Fedin prop = value; 637b604a854SPavel Fedin if (object_property_is_child(prop) && prop->opaque == child) { 638b604a854SPavel Fedin g_hash_table_iter_remove(&iter); 6396c1fdcf9SPaolo Bonzini break; 64057c9fafeSAnthony Liguori } 64157c9fafeSAnthony Liguori } 64257c9fafeSAnthony Liguori } 64357c9fafeSAnthony Liguori 64457c9fafeSAnthony Liguori void object_unparent(Object *obj) 64557c9fafeSAnthony Liguori { 646e998fa8dSMichael S. Tsirkin if (obj->parent) { 647e998fa8dSMichael S. Tsirkin object_property_del_child(obj->parent, obj, NULL); 648e998fa8dSMichael S. Tsirkin } 64957c9fafeSAnthony Liguori } 65057c9fafeSAnthony Liguori 6512f28d2ffSAnthony Liguori static void object_deinit(Object *obj, TypeImpl *type) 6522f28d2ffSAnthony Liguori { 6532f28d2ffSAnthony Liguori if (type->instance_finalize) { 6542f28d2ffSAnthony Liguori type->instance_finalize(obj); 6552f28d2ffSAnthony Liguori } 6562f28d2ffSAnthony Liguori 6572f28d2ffSAnthony Liguori if (type_has_parent(type)) { 6582f28d2ffSAnthony Liguori object_deinit(obj, type_get_parent(type)); 6592f28d2ffSAnthony Liguori } 6602f28d2ffSAnthony Liguori } 6612f28d2ffSAnthony Liguori 662339c2708SPaolo Bonzini static void object_finalize(void *data) 6632f28d2ffSAnthony Liguori { 6642f28d2ffSAnthony Liguori Object *obj = data; 6652f28d2ffSAnthony Liguori TypeImpl *ti = obj->class->type; 6662f28d2ffSAnthony Liguori 66757c9fafeSAnthony Liguori object_property_del_all(obj); 66876a6e1ccSPaolo Bonzini object_deinit(obj, ti); 669db85b575SAnthony Liguori 670719a3077SMarkus Armbruster g_assert(obj->ref == 0); 671fde9bf44SPaolo Bonzini if (obj->free) { 672fde9bf44SPaolo Bonzini obj->free(obj); 673fde9bf44SPaolo Bonzini } 6742f28d2ffSAnthony Liguori } 6752f28d2ffSAnthony Liguori 67663f7b10bSMarc-André Lureau static Object *object_new_with_type(Type type) 6772f28d2ffSAnthony Liguori { 6782f28d2ffSAnthony Liguori Object *obj; 6792f28d2ffSAnthony Liguori 6802f28d2ffSAnthony Liguori g_assert(type != NULL); 681ac451033SIgor Mitsyanko type_initialize(type); 6822f28d2ffSAnthony Liguori 6832f28d2ffSAnthony Liguori obj = g_malloc(type->instance_size); 6845b9237f6SAndreas Färber object_initialize_with_type(obj, type->instance_size, type); 685fde9bf44SPaolo Bonzini obj->free = g_free; 6862f28d2ffSAnthony Liguori 6872f28d2ffSAnthony Liguori return obj; 6882f28d2ffSAnthony Liguori } 6892f28d2ffSAnthony Liguori 6903c75e12eSPaolo Bonzini Object *object_new_with_class(ObjectClass *klass) 6913c75e12eSPaolo Bonzini { 6923c75e12eSPaolo Bonzini return object_new_with_type(klass->type); 6933c75e12eSPaolo Bonzini } 6943c75e12eSPaolo Bonzini 6952f28d2ffSAnthony Liguori Object *object_new(const char *typename) 6962f28d2ffSAnthony Liguori { 6972f28d2ffSAnthony Liguori TypeImpl *ti = type_get_by_name(typename); 6982f28d2ffSAnthony Liguori 6992f28d2ffSAnthony Liguori return object_new_with_type(ti); 7002f28d2ffSAnthony Liguori } 7012f28d2ffSAnthony Liguori 702a31bdae5SDaniel P. Berrange 703a31bdae5SDaniel P. Berrange Object *object_new_with_props(const char *typename, 704a31bdae5SDaniel P. Berrange Object *parent, 705a31bdae5SDaniel P. Berrange const char *id, 706a31bdae5SDaniel P. Berrange Error **errp, 707a31bdae5SDaniel P. Berrange ...) 708a31bdae5SDaniel P. Berrange { 709a31bdae5SDaniel P. Berrange va_list vargs; 710a31bdae5SDaniel P. Berrange Object *obj; 711a31bdae5SDaniel P. Berrange 712a31bdae5SDaniel P. Berrange va_start(vargs, errp); 713a31bdae5SDaniel P. Berrange obj = object_new_with_propv(typename, parent, id, errp, vargs); 714a31bdae5SDaniel P. Berrange va_end(vargs); 715a31bdae5SDaniel P. Berrange 716a31bdae5SDaniel P. Berrange return obj; 717a31bdae5SDaniel P. Berrange } 718a31bdae5SDaniel P. Berrange 719a31bdae5SDaniel P. Berrange 720a31bdae5SDaniel P. Berrange Object *object_new_with_propv(const char *typename, 721a31bdae5SDaniel P. Berrange Object *parent, 722a31bdae5SDaniel P. Berrange const char *id, 723a31bdae5SDaniel P. Berrange Error **errp, 724a31bdae5SDaniel P. Berrange va_list vargs) 725a31bdae5SDaniel P. Berrange { 726a31bdae5SDaniel P. Berrange Object *obj; 727a31bdae5SDaniel P. Berrange ObjectClass *klass; 728a31bdae5SDaniel P. Berrange Error *local_err = NULL; 7293650b2deSMarc-André Lureau UserCreatable *uc; 730a31bdae5SDaniel P. Berrange 731a31bdae5SDaniel P. Berrange klass = object_class_by_name(typename); 732a31bdae5SDaniel P. Berrange if (!klass) { 733a31bdae5SDaniel P. Berrange error_setg(errp, "invalid object type: %s", typename); 734a31bdae5SDaniel P. Berrange return NULL; 735a31bdae5SDaniel P. Berrange } 736a31bdae5SDaniel P. Berrange 737a31bdae5SDaniel P. Berrange if (object_class_is_abstract(klass)) { 738a31bdae5SDaniel P. Berrange error_setg(errp, "object type '%s' is abstract", typename); 739a31bdae5SDaniel P. Berrange return NULL; 740a31bdae5SDaniel P. Berrange } 74166e1155aSWei Yang obj = object_new_with_type(klass->type); 742a31bdae5SDaniel P. Berrange 743a31bdae5SDaniel P. Berrange if (object_set_propv(obj, &local_err, vargs) < 0) { 744a31bdae5SDaniel P. Berrange goto error; 745a31bdae5SDaniel P. Berrange } 746a31bdae5SDaniel P. Berrange 7476134d752SDaniel P. Berrangé if (id != NULL) { 748a31bdae5SDaniel P. Berrange object_property_add_child(parent, id, obj, &local_err); 749a31bdae5SDaniel P. Berrange if (local_err) { 750a31bdae5SDaniel P. Berrange goto error; 751a31bdae5SDaniel P. Berrange } 7526134d752SDaniel P. Berrangé } 753a31bdae5SDaniel P. Berrange 7543650b2deSMarc-André Lureau uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); 7553650b2deSMarc-André Lureau if (uc) { 7563650b2deSMarc-André Lureau user_creatable_complete(uc, &local_err); 757a31bdae5SDaniel P. Berrange if (local_err) { 7586134d752SDaniel P. Berrangé if (id != NULL) { 759a31bdae5SDaniel P. Berrange object_unparent(obj); 7606134d752SDaniel P. Berrangé } 761a31bdae5SDaniel P. Berrange goto error; 762a31bdae5SDaniel P. Berrange } 763a31bdae5SDaniel P. Berrange } 764a31bdae5SDaniel P. Berrange 765a31bdae5SDaniel P. Berrange object_unref(OBJECT(obj)); 766a31bdae5SDaniel P. Berrange return obj; 767a31bdae5SDaniel P. Berrange 768a31bdae5SDaniel P. Berrange error: 769a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 770a31bdae5SDaniel P. Berrange object_unref(obj); 771a31bdae5SDaniel P. Berrange return NULL; 772a31bdae5SDaniel P. Berrange } 773a31bdae5SDaniel P. Berrange 774a31bdae5SDaniel P. Berrange 775a31bdae5SDaniel P. Berrange int object_set_props(Object *obj, 776a31bdae5SDaniel P. Berrange Error **errp, 777a31bdae5SDaniel P. Berrange ...) 778a31bdae5SDaniel P. Berrange { 779a31bdae5SDaniel P. Berrange va_list vargs; 780a31bdae5SDaniel P. Berrange int ret; 781a31bdae5SDaniel P. Berrange 782a31bdae5SDaniel P. Berrange va_start(vargs, errp); 783a31bdae5SDaniel P. Berrange ret = object_set_propv(obj, errp, vargs); 784a31bdae5SDaniel P. Berrange va_end(vargs); 785a31bdae5SDaniel P. Berrange 786a31bdae5SDaniel P. Berrange return ret; 787a31bdae5SDaniel P. Berrange } 788a31bdae5SDaniel P. Berrange 789a31bdae5SDaniel P. Berrange 790a31bdae5SDaniel P. Berrange int object_set_propv(Object *obj, 791a31bdae5SDaniel P. Berrange Error **errp, 792a31bdae5SDaniel P. Berrange va_list vargs) 793a31bdae5SDaniel P. Berrange { 794a31bdae5SDaniel P. Berrange const char *propname; 795a31bdae5SDaniel P. Berrange Error *local_err = NULL; 796a31bdae5SDaniel P. Berrange 797a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 798a31bdae5SDaniel P. Berrange while (propname != NULL) { 799a31bdae5SDaniel P. Berrange const char *value = va_arg(vargs, char *); 800a31bdae5SDaniel P. Berrange 801a31bdae5SDaniel P. Berrange g_assert(value != NULL); 802a31bdae5SDaniel P. Berrange object_property_parse(obj, value, propname, &local_err); 803a31bdae5SDaniel P. Berrange if (local_err) { 804a31bdae5SDaniel P. Berrange error_propagate(errp, local_err); 805a31bdae5SDaniel P. Berrange return -1; 806a31bdae5SDaniel P. Berrange } 807a31bdae5SDaniel P. Berrange propname = va_arg(vargs, char *); 808a31bdae5SDaniel P. Berrange } 809a31bdae5SDaniel P. Berrange 810a31bdae5SDaniel P. Berrange return 0; 811a31bdae5SDaniel P. Berrange } 812a31bdae5SDaniel P. Berrange 813a31bdae5SDaniel P. Berrange 8142f28d2ffSAnthony Liguori Object *object_dynamic_cast(Object *obj, const char *typename) 8152f28d2ffSAnthony Liguori { 816b7f43fe4SPaolo Bonzini if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { 817acc4af3fSPaolo Bonzini return obj; 818acc4af3fSPaolo Bonzini } 819acc4af3fSPaolo Bonzini 8202f28d2ffSAnthony Liguori return NULL; 8212f28d2ffSAnthony Liguori } 8222f28d2ffSAnthony Liguori 823be17f18bSPaolo Bonzini Object *object_dynamic_cast_assert(Object *obj, const char *typename, 824be17f18bSPaolo Bonzini const char *file, int line, const char *func) 8252f28d2ffSAnthony Liguori { 826fa131d94SPaolo Bonzini trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", 827fa131d94SPaolo Bonzini typename, file, line, func); 828fa131d94SPaolo Bonzini 8293556c233SPaolo Bonzini #ifdef CONFIG_QOM_CAST_DEBUG 83003587328SAnthony Liguori int i; 83103587328SAnthony Liguori Object *inst; 83203587328SAnthony Liguori 83395916abcSPeter Crosthwaite for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { 834b6b3ccfdSAlex Bennée if (atomic_read(&obj->class->object_cast_cache[i]) == typename) { 83503587328SAnthony Liguori goto out; 83603587328SAnthony Liguori } 83703587328SAnthony Liguori } 83803587328SAnthony Liguori 83903587328SAnthony Liguori inst = object_dynamic_cast(obj, typename); 8402f28d2ffSAnthony Liguori 841b7f43fe4SPaolo Bonzini if (!inst && obj) { 842be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 843be17f18bSPaolo Bonzini file, line, func, obj, typename); 8442f28d2ffSAnthony Liguori abort(); 8452f28d2ffSAnthony Liguori } 8462f28d2ffSAnthony Liguori 8473556c233SPaolo Bonzini assert(obj == inst); 84803587328SAnthony Liguori 84995916abcSPeter Crosthwaite if (obj && obj == inst) { 85003587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 851b6b3ccfdSAlex Bennée atomic_set(&obj->class->object_cast_cache[i - 1], 852b6b3ccfdSAlex Bennée atomic_read(&obj->class->object_cast_cache[i])); 85303587328SAnthony Liguori } 854b6b3ccfdSAlex Bennée atomic_set(&obj->class->object_cast_cache[i - 1], typename); 85503587328SAnthony Liguori } 85603587328SAnthony Liguori 85703587328SAnthony Liguori out: 8583556c233SPaolo Bonzini #endif 8593556c233SPaolo Bonzini return obj; 8602f28d2ffSAnthony Liguori } 8612f28d2ffSAnthony Liguori 8622f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast(ObjectClass *class, 8632f28d2ffSAnthony Liguori const char *typename) 8642f28d2ffSAnthony Liguori { 86533e95c63SAnthony Liguori ObjectClass *ret = NULL; 866bf0fda34SPaolo Bonzini TypeImpl *target_type; 867bf0fda34SPaolo Bonzini TypeImpl *type; 8682f28d2ffSAnthony Liguori 869bf0fda34SPaolo Bonzini if (!class) { 870bf0fda34SPaolo Bonzini return NULL; 871bf0fda34SPaolo Bonzini } 872bf0fda34SPaolo Bonzini 873793c96b5SPaolo Bonzini /* A simple fast path that can trigger a lot for leaf classes. */ 874bf0fda34SPaolo Bonzini type = class->type; 875793c96b5SPaolo Bonzini if (type->name == typename) { 876793c96b5SPaolo Bonzini return class; 877793c96b5SPaolo Bonzini } 878793c96b5SPaolo Bonzini 879bf0fda34SPaolo Bonzini target_type = type_get_by_name(typename); 8809ab880b3SAlexander Graf if (!target_type) { 8819ab880b3SAlexander Graf /* target class type unknown, so fail the cast */ 8829ab880b3SAlexander Graf return NULL; 8839ab880b3SAlexander Graf } 8849ab880b3SAlexander Graf 88500e2ceaeSPeter Crosthwaite if (type->class->interfaces && 88600e2ceaeSPeter Crosthwaite type_is_ancestor(target_type, type_interface)) { 88733e95c63SAnthony Liguori int found = 0; 88833e95c63SAnthony Liguori GSList *i; 88933e95c63SAnthony Liguori 89033e95c63SAnthony Liguori for (i = class->interfaces; i; i = i->next) { 89133e95c63SAnthony Liguori ObjectClass *target_class = i->data; 89233e95c63SAnthony Liguori 89333e95c63SAnthony Liguori if (type_is_ancestor(target_class->type, target_type)) { 89433e95c63SAnthony Liguori ret = target_class; 89533e95c63SAnthony Liguori found++; 89633e95c63SAnthony Liguori } 8972f28d2ffSAnthony Liguori } 8982f28d2ffSAnthony Liguori 89933e95c63SAnthony Liguori /* The match was ambiguous, don't allow a cast */ 90033e95c63SAnthony Liguori if (found > 1) { 90133e95c63SAnthony Liguori ret = NULL; 90233e95c63SAnthony Liguori } 90333e95c63SAnthony Liguori } else if (type_is_ancestor(type, target_type)) { 90433e95c63SAnthony Liguori ret = class; 9052f28d2ffSAnthony Liguori } 9062f28d2ffSAnthony Liguori 90733e95c63SAnthony Liguori return ret; 9082f28d2ffSAnthony Liguori } 9092f28d2ffSAnthony Liguori 9102f28d2ffSAnthony Liguori ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, 911be17f18bSPaolo Bonzini const char *typename, 912be17f18bSPaolo Bonzini const char *file, int line, 913be17f18bSPaolo Bonzini const char *func) 9142f28d2ffSAnthony Liguori { 915fa131d94SPaolo Bonzini ObjectClass *ret; 9162f28d2ffSAnthony Liguori 917fa131d94SPaolo Bonzini trace_object_class_dynamic_cast_assert(class ? class->type->name : "(null)", 918fa131d94SPaolo Bonzini typename, file, line, func); 919fa131d94SPaolo Bonzini 92003587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 92103587328SAnthony Liguori int i; 92203587328SAnthony Liguori 9239d6a3d58SPeter Crosthwaite for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { 924b6b3ccfdSAlex Bennée if (atomic_read(&class->class_cast_cache[i]) == typename) { 92503587328SAnthony Liguori ret = class; 92603587328SAnthony Liguori goto out; 92703587328SAnthony Liguori } 92803587328SAnthony Liguori } 92903587328SAnthony Liguori #else 9309d6a3d58SPeter Crosthwaite if (!class || !class->interfaces) { 9313556c233SPaolo Bonzini return class; 9323556c233SPaolo Bonzini } 9333556c233SPaolo Bonzini #endif 9343556c233SPaolo Bonzini 935fa131d94SPaolo Bonzini ret = object_class_dynamic_cast(class, typename); 936bf0fda34SPaolo Bonzini if (!ret && class) { 937be17f18bSPaolo Bonzini fprintf(stderr, "%s:%d:%s: Object %p is not an instance of type %s\n", 938be17f18bSPaolo Bonzini file, line, func, class, typename); 9392f28d2ffSAnthony Liguori abort(); 9402f28d2ffSAnthony Liguori } 9412f28d2ffSAnthony Liguori 94203587328SAnthony Liguori #ifdef CONFIG_QOM_CAST_DEBUG 9439d6a3d58SPeter Crosthwaite if (class && ret == class) { 94403587328SAnthony Liguori for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { 945b6b3ccfdSAlex Bennée atomic_set(&class->class_cast_cache[i - 1], 946b6b3ccfdSAlex Bennée atomic_read(&class->class_cast_cache[i])); 94703587328SAnthony Liguori } 948b6b3ccfdSAlex Bennée atomic_set(&class->class_cast_cache[i - 1], typename); 94903587328SAnthony Liguori } 95003587328SAnthony Liguori out: 95103587328SAnthony Liguori #endif 9522f28d2ffSAnthony Liguori return ret; 9532f28d2ffSAnthony Liguori } 9542f28d2ffSAnthony Liguori 9558f5d58efSIgor Mammedov const char *object_get_typename(const Object *obj) 9562f28d2ffSAnthony Liguori { 9572f28d2ffSAnthony Liguori return obj->class->type->name; 9582f28d2ffSAnthony Liguori } 9592f28d2ffSAnthony Liguori 9602f28d2ffSAnthony Liguori ObjectClass *object_get_class(Object *obj) 9612f28d2ffSAnthony Liguori { 9622f28d2ffSAnthony Liguori return obj->class; 9632f28d2ffSAnthony Liguori } 9642f28d2ffSAnthony Liguori 96517862378SAndreas Färber bool object_class_is_abstract(ObjectClass *klass) 96617862378SAndreas Färber { 96717862378SAndreas Färber return klass->type->abstract; 96817862378SAndreas Färber } 96917862378SAndreas Färber 9702f28d2ffSAnthony Liguori const char *object_class_get_name(ObjectClass *klass) 9712f28d2ffSAnthony Liguori { 9722f28d2ffSAnthony Liguori return klass->type->name; 9732f28d2ffSAnthony Liguori } 9742f28d2ffSAnthony Liguori 9752f28d2ffSAnthony Liguori ObjectClass *object_class_by_name(const char *typename) 9762f28d2ffSAnthony Liguori { 9772f28d2ffSAnthony Liguori TypeImpl *type = type_get_by_name(typename); 9782f28d2ffSAnthony Liguori 9792f28d2ffSAnthony Liguori if (!type) { 9802f28d2ffSAnthony Liguori return NULL; 9812f28d2ffSAnthony Liguori } 9822f28d2ffSAnthony Liguori 983ac451033SIgor Mitsyanko type_initialize(type); 9842f28d2ffSAnthony Liguori 9852f28d2ffSAnthony Liguori return type->class; 9862f28d2ffSAnthony Liguori } 9872f28d2ffSAnthony Liguori 988e7cce67fSPaolo Bonzini ObjectClass *object_class_get_parent(ObjectClass *class) 989e7cce67fSPaolo Bonzini { 990e7cce67fSPaolo Bonzini TypeImpl *type = type_get_parent(class->type); 991e7cce67fSPaolo Bonzini 992e7cce67fSPaolo Bonzini if (!type) { 993e7cce67fSPaolo Bonzini return NULL; 994e7cce67fSPaolo Bonzini } 995e7cce67fSPaolo Bonzini 996e7cce67fSPaolo Bonzini type_initialize(type); 997e7cce67fSPaolo Bonzini 998e7cce67fSPaolo Bonzini return type->class; 999e7cce67fSPaolo Bonzini } 1000e7cce67fSPaolo Bonzini 10012f28d2ffSAnthony Liguori typedef struct OCFData 10022f28d2ffSAnthony Liguori { 10032f28d2ffSAnthony Liguori void (*fn)(ObjectClass *klass, void *opaque); 100493c511a1SAnthony Liguori const char *implements_type; 100593c511a1SAnthony Liguori bool include_abstract; 10062f28d2ffSAnthony Liguori void *opaque; 10072f28d2ffSAnthony Liguori } OCFData; 10082f28d2ffSAnthony Liguori 10092f28d2ffSAnthony Liguori static void object_class_foreach_tramp(gpointer key, gpointer value, 10102f28d2ffSAnthony Liguori gpointer opaque) 10112f28d2ffSAnthony Liguori { 10122f28d2ffSAnthony Liguori OCFData *data = opaque; 10132f28d2ffSAnthony Liguori TypeImpl *type = value; 101493c511a1SAnthony Liguori ObjectClass *k; 10152f28d2ffSAnthony Liguori 1016ac451033SIgor Mitsyanko type_initialize(type); 101793c511a1SAnthony Liguori k = type->class; 10182f28d2ffSAnthony Liguori 101993c511a1SAnthony Liguori if (!data->include_abstract && type->abstract) { 102093c511a1SAnthony Liguori return; 102193c511a1SAnthony Liguori } 102293c511a1SAnthony Liguori 102393c511a1SAnthony Liguori if (data->implements_type && 102493c511a1SAnthony Liguori !object_class_dynamic_cast(k, data->implements_type)) { 102593c511a1SAnthony Liguori return; 102693c511a1SAnthony Liguori } 102793c511a1SAnthony Liguori 102893c511a1SAnthony Liguori data->fn(k, data->opaque); 10292f28d2ffSAnthony Liguori } 10302f28d2ffSAnthony Liguori 10312f28d2ffSAnthony Liguori void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), 103293c511a1SAnthony Liguori const char *implements_type, bool include_abstract, 10332f28d2ffSAnthony Liguori void *opaque) 10342f28d2ffSAnthony Liguori { 103593c511a1SAnthony Liguori OCFData data = { fn, implements_type, include_abstract, opaque }; 10362f28d2ffSAnthony Liguori 1037f54c19caSHervé Poussineau enumerating_types = true; 10382f28d2ffSAnthony Liguori g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data); 1039f54c19caSHervé Poussineau enumerating_types = false; 10402f28d2ffSAnthony Liguori } 104157c9fafeSAnthony Liguori 1042d714b8deSPeter Crosthwaite static int do_object_child_foreach(Object *obj, 1043d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 1044d714b8deSPeter Crosthwaite void *opaque, bool recurse) 104532efc535SPaolo Bonzini { 1046b604a854SPavel Fedin GHashTableIter iter; 1047b604a854SPavel Fedin ObjectProperty *prop; 104832efc535SPaolo Bonzini int ret = 0; 104932efc535SPaolo Bonzini 1050b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->properties); 1051b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 105232efc535SPaolo Bonzini if (object_property_is_child(prop)) { 1053d714b8deSPeter Crosthwaite Object *child = prop->opaque; 1054d714b8deSPeter Crosthwaite 1055d714b8deSPeter Crosthwaite ret = fn(child, opaque); 105632efc535SPaolo Bonzini if (ret != 0) { 105732efc535SPaolo Bonzini break; 105832efc535SPaolo Bonzini } 1059d714b8deSPeter Crosthwaite if (recurse) { 1060d714b8deSPeter Crosthwaite do_object_child_foreach(child, fn, opaque, true); 1061d714b8deSPeter Crosthwaite } 106232efc535SPaolo Bonzini } 106332efc535SPaolo Bonzini } 106432efc535SPaolo Bonzini return ret; 106532efc535SPaolo Bonzini } 106632efc535SPaolo Bonzini 1067d714b8deSPeter Crosthwaite int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), 1068d714b8deSPeter Crosthwaite void *opaque) 1069d714b8deSPeter Crosthwaite { 1070d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, false); 1071d714b8deSPeter Crosthwaite } 1072d714b8deSPeter Crosthwaite 1073d714b8deSPeter Crosthwaite int object_child_foreach_recursive(Object *obj, 1074d714b8deSPeter Crosthwaite int (*fn)(Object *child, void *opaque), 1075d714b8deSPeter Crosthwaite void *opaque) 1076d714b8deSPeter Crosthwaite { 1077d714b8deSPeter Crosthwaite return do_object_child_foreach(obj, fn, opaque, true); 1078d714b8deSPeter Crosthwaite } 1079d714b8deSPeter Crosthwaite 1080418ba9e5SAndreas Färber static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) 1081418ba9e5SAndreas Färber { 1082418ba9e5SAndreas Färber GSList **list = opaque; 1083418ba9e5SAndreas Färber 1084418ba9e5SAndreas Färber *list = g_slist_prepend(*list, klass); 1085418ba9e5SAndreas Färber } 1086418ba9e5SAndreas Färber 1087418ba9e5SAndreas Färber GSList *object_class_get_list(const char *implements_type, 1088418ba9e5SAndreas Färber bool include_abstract) 1089418ba9e5SAndreas Färber { 1090418ba9e5SAndreas Färber GSList *list = NULL; 1091418ba9e5SAndreas Färber 1092418ba9e5SAndreas Färber object_class_foreach(object_class_get_list_tramp, 1093418ba9e5SAndreas Färber implements_type, include_abstract, &list); 1094418ba9e5SAndreas Färber return list; 1095418ba9e5SAndreas Färber } 1096418ba9e5SAndreas Färber 109747c66009SPaolo Bonzini static gint object_class_cmp(gconstpointer a, gconstpointer b) 109847c66009SPaolo Bonzini { 109947c66009SPaolo Bonzini return strcasecmp(object_class_get_name((ObjectClass *)a), 110047c66009SPaolo Bonzini object_class_get_name((ObjectClass *)b)); 110147c66009SPaolo Bonzini } 110247c66009SPaolo Bonzini 110347c66009SPaolo Bonzini GSList *object_class_get_list_sorted(const char *implements_type, 110447c66009SPaolo Bonzini bool include_abstract) 110547c66009SPaolo Bonzini { 110647c66009SPaolo Bonzini return g_slist_sort(object_class_get_list(implements_type, include_abstract), 110747c66009SPaolo Bonzini object_class_cmp); 110847c66009SPaolo Bonzini } 110947c66009SPaolo Bonzini 111057c9fafeSAnthony Liguori void object_ref(Object *obj) 111157c9fafeSAnthony Liguori { 11128ffad850SPeter Crosthwaite if (!obj) { 11138ffad850SPeter Crosthwaite return; 11148ffad850SPeter Crosthwaite } 1115f08c03f3SJan Kiszka atomic_inc(&obj->ref); 111657c9fafeSAnthony Liguori } 111757c9fafeSAnthony Liguori 111857c9fafeSAnthony Liguori void object_unref(Object *obj) 111957c9fafeSAnthony Liguori { 11208ffad850SPeter Crosthwaite if (!obj) { 11218ffad850SPeter Crosthwaite return; 11228ffad850SPeter Crosthwaite } 1123719a3077SMarkus Armbruster g_assert(obj->ref > 0); 112457c9fafeSAnthony Liguori 112557c9fafeSAnthony Liguori /* parent always holds a reference to its children */ 1126f08c03f3SJan Kiszka if (atomic_fetch_dec(&obj->ref) == 1) { 112757c9fafeSAnthony Liguori object_finalize(obj); 112857c9fafeSAnthony Liguori } 112957c9fafeSAnthony Liguori } 113057c9fafeSAnthony Liguori 113164607d08SPaolo Bonzini ObjectProperty * 113264607d08SPaolo Bonzini object_property_add(Object *obj, const char *name, const char *type, 113357c9fafeSAnthony Liguori ObjectPropertyAccessor *get, 113457c9fafeSAnthony Liguori ObjectPropertyAccessor *set, 113557c9fafeSAnthony Liguori ObjectPropertyRelease *release, 113657c9fafeSAnthony Liguori void *opaque, Error **errp) 113757c9fafeSAnthony Liguori { 113854852b03SPeter Maydell ObjectProperty *prop; 113933965904SPeter Crosthwaite size_t name_len = strlen(name); 114033965904SPeter Crosthwaite 114133965904SPeter Crosthwaite if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) { 114233965904SPeter Crosthwaite int i; 114333965904SPeter Crosthwaite ObjectProperty *ret; 114433965904SPeter Crosthwaite char *name_no_array = g_strdup(name); 114533965904SPeter Crosthwaite 114633965904SPeter Crosthwaite name_no_array[name_len - 3] = '\0'; 114733965904SPeter Crosthwaite for (i = 0; ; ++i) { 114833965904SPeter Crosthwaite char *full_name = g_strdup_printf("%s[%d]", name_no_array, i); 114933965904SPeter Crosthwaite 115033965904SPeter Crosthwaite ret = object_property_add(obj, full_name, type, get, set, 115133965904SPeter Crosthwaite release, opaque, NULL); 115233965904SPeter Crosthwaite g_free(full_name); 115333965904SPeter Crosthwaite if (ret) { 115433965904SPeter Crosthwaite break; 115533965904SPeter Crosthwaite } 115633965904SPeter Crosthwaite } 115733965904SPeter Crosthwaite g_free(name_no_array); 115833965904SPeter Crosthwaite return ret; 115933965904SPeter Crosthwaite } 116054852b03SPeter Maydell 116116bf7f52SDaniel P. Berrange if (object_property_find(obj, name, NULL) != NULL) { 1162d55e937dSGreg Kurz error_setg(errp, "attempt to add duplicate property '%s' to object (type '%s')", 1163d55e937dSGreg Kurz name, object_get_typename(obj)); 116464607d08SPaolo Bonzini return NULL; 116554852b03SPeter Maydell } 116654852b03SPeter Maydell 116754852b03SPeter Maydell prop = g_malloc0(sizeof(*prop)); 116857c9fafeSAnthony Liguori 116957c9fafeSAnthony Liguori prop->name = g_strdup(name); 117057c9fafeSAnthony Liguori prop->type = g_strdup(type); 117157c9fafeSAnthony Liguori 117257c9fafeSAnthony Liguori prop->get = get; 117357c9fafeSAnthony Liguori prop->set = set; 117457c9fafeSAnthony Liguori prop->release = release; 117557c9fafeSAnthony Liguori prop->opaque = opaque; 117657c9fafeSAnthony Liguori 1177b604a854SPavel Fedin g_hash_table_insert(obj->properties, prop->name, prop); 117864607d08SPaolo Bonzini return prop; 117957c9fafeSAnthony Liguori } 118057c9fafeSAnthony Liguori 118116bf7f52SDaniel P. Berrange ObjectProperty * 118216bf7f52SDaniel P. Berrange object_class_property_add(ObjectClass *klass, 118316bf7f52SDaniel P. Berrange const char *name, 118416bf7f52SDaniel P. Berrange const char *type, 118516bf7f52SDaniel P. Berrange ObjectPropertyAccessor *get, 118616bf7f52SDaniel P. Berrange ObjectPropertyAccessor *set, 118716bf7f52SDaniel P. Berrange ObjectPropertyRelease *release, 118816bf7f52SDaniel P. Berrange void *opaque, 118916bf7f52SDaniel P. Berrange Error **errp) 119016bf7f52SDaniel P. Berrange { 119116bf7f52SDaniel P. Berrange ObjectProperty *prop; 119216bf7f52SDaniel P. Berrange 119316bf7f52SDaniel P. Berrange if (object_class_property_find(klass, name, NULL) != NULL) { 1194d55e937dSGreg Kurz error_setg(errp, "attempt to add duplicate property '%s' to class (type '%s')", 1195d55e937dSGreg Kurz name, object_class_get_name(klass)); 119616bf7f52SDaniel P. Berrange return NULL; 119716bf7f52SDaniel P. Berrange } 119816bf7f52SDaniel P. Berrange 119916bf7f52SDaniel P. Berrange prop = g_malloc0(sizeof(*prop)); 120016bf7f52SDaniel P. Berrange 120116bf7f52SDaniel P. Berrange prop->name = g_strdup(name); 120216bf7f52SDaniel P. Berrange prop->type = g_strdup(type); 120316bf7f52SDaniel P. Berrange 120416bf7f52SDaniel P. Berrange prop->get = get; 120516bf7f52SDaniel P. Berrange prop->set = set; 120616bf7f52SDaniel P. Berrange prop->release = release; 120716bf7f52SDaniel P. Berrange prop->opaque = opaque; 120816bf7f52SDaniel P. Berrange 1209ba806ffbSMarc-André Lureau g_hash_table_insert(klass->properties, prop->name, prop); 121016bf7f52SDaniel P. Berrange 121116bf7f52SDaniel P. Berrange return prop; 121216bf7f52SDaniel P. Berrange } 121316bf7f52SDaniel P. Berrange 121489bfe000SPaolo Bonzini ObjectProperty *object_property_find(Object *obj, const char *name, 121589bfe000SPaolo Bonzini Error **errp) 121657c9fafeSAnthony Liguori { 121757c9fafeSAnthony Liguori ObjectProperty *prop; 121816bf7f52SDaniel P. Berrange ObjectClass *klass = object_get_class(obj); 121916bf7f52SDaniel P. Berrange 122016bf7f52SDaniel P. Berrange prop = object_class_property_find(klass, name, NULL); 122116bf7f52SDaniel P. Berrange if (prop) { 122216bf7f52SDaniel P. Berrange return prop; 122316bf7f52SDaniel P. Berrange } 122457c9fafeSAnthony Liguori 1225b604a854SPavel Fedin prop = g_hash_table_lookup(obj->properties, name); 1226b604a854SPavel Fedin if (prop) { 122757c9fafeSAnthony Liguori return prop; 122857c9fafeSAnthony Liguori } 122957c9fafeSAnthony Liguori 1230f231b88dSCole Robinson error_setg(errp, "Property '.%s' not found", name); 123157c9fafeSAnthony Liguori return NULL; 123257c9fafeSAnthony Liguori } 123357c9fafeSAnthony Liguori 12347746abd8SDaniel P. Berrange void object_property_iter_init(ObjectPropertyIterator *iter, 12357746abd8SDaniel P. Berrange Object *obj) 1236a00c9482SDaniel P. Berrange { 12377746abd8SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, obj->properties); 12387746abd8SDaniel P. Berrange iter->nextclass = object_get_class(obj); 1239a00c9482SDaniel P. Berrange } 1240a00c9482SDaniel P. Berrange 1241a00c9482SDaniel P. Berrange ObjectProperty *object_property_iter_next(ObjectPropertyIterator *iter) 1242a00c9482SDaniel P. Berrange { 1243b604a854SPavel Fedin gpointer key, val; 124416bf7f52SDaniel P. Berrange while (!g_hash_table_iter_next(&iter->iter, &key, &val)) { 124516bf7f52SDaniel P. Berrange if (!iter->nextclass) { 1246b604a854SPavel Fedin return NULL; 1247a00c9482SDaniel P. Berrange } 124816bf7f52SDaniel P. Berrange g_hash_table_iter_init(&iter->iter, iter->nextclass->properties); 124916bf7f52SDaniel P. Berrange iter->nextclass = object_class_get_parent(iter->nextclass); 125016bf7f52SDaniel P. Berrange } 1251b604a854SPavel Fedin return val; 1252a00c9482SDaniel P. Berrange } 1253a00c9482SDaniel P. Berrange 1254961c47bbSAlexey Kardashevskiy void object_class_property_iter_init(ObjectPropertyIterator *iter, 1255961c47bbSAlexey Kardashevskiy ObjectClass *klass) 1256961c47bbSAlexey Kardashevskiy { 1257961c47bbSAlexey Kardashevskiy g_hash_table_iter_init(&iter->iter, klass->properties); 1258684546d8SMarc-André Lureau iter->nextclass = object_class_get_parent(klass); 1259961c47bbSAlexey Kardashevskiy } 1260961c47bbSAlexey Kardashevskiy 126116bf7f52SDaniel P. Berrange ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, 126216bf7f52SDaniel P. Berrange Error **errp) 126316bf7f52SDaniel P. Berrange { 126416bf7f52SDaniel P. Berrange ObjectProperty *prop; 126516bf7f52SDaniel P. Berrange ObjectClass *parent_klass; 126616bf7f52SDaniel P. Berrange 126716bf7f52SDaniel P. Berrange parent_klass = object_class_get_parent(klass); 126816bf7f52SDaniel P. Berrange if (parent_klass) { 126916bf7f52SDaniel P. Berrange prop = object_class_property_find(parent_klass, name, NULL); 127016bf7f52SDaniel P. Berrange if (prop) { 127116bf7f52SDaniel P. Berrange return prop; 127216bf7f52SDaniel P. Berrange } 127316bf7f52SDaniel P. Berrange } 127416bf7f52SDaniel P. Berrange 127516bf7f52SDaniel P. Berrange prop = g_hash_table_lookup(klass->properties, name); 127616bf7f52SDaniel P. Berrange if (!prop) { 127716bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 127816bf7f52SDaniel P. Berrange } 127916bf7f52SDaniel P. Berrange return prop; 128016bf7f52SDaniel P. Berrange } 128116bf7f52SDaniel P. Berrange 128257c9fafeSAnthony Liguori void object_property_del(Object *obj, const char *name, Error **errp) 128357c9fafeSAnthony Liguori { 1284b604a854SPavel Fedin ObjectProperty *prop = g_hash_table_lookup(obj->properties, name); 1285b604a854SPavel Fedin 1286b604a854SPavel Fedin if (!prop) { 1287b604a854SPavel Fedin error_setg(errp, "Property '.%s' not found", name); 12880866aca1SAnthony Liguori return; 12890866aca1SAnthony Liguori } 129057c9fafeSAnthony Liguori 12910866aca1SAnthony Liguori if (prop->release) { 12920866aca1SAnthony Liguori prop->release(obj, name, prop->opaque); 12930866aca1SAnthony Liguori } 1294b604a854SPavel Fedin g_hash_table_remove(obj->properties, name); 129557c9fafeSAnthony Liguori } 129657c9fafeSAnthony Liguori 129757c9fafeSAnthony Liguori void object_property_get(Object *obj, Visitor *v, const char *name, 129857c9fafeSAnthony Liguori Error **errp) 129957c9fafeSAnthony Liguori { 130089bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 130157c9fafeSAnthony Liguori if (prop == NULL) { 130257c9fafeSAnthony Liguori return; 130357c9fafeSAnthony Liguori } 130457c9fafeSAnthony Liguori 130557c9fafeSAnthony Liguori if (!prop->get) { 1306c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 130757c9fafeSAnthony Liguori } else { 1308d7bce999SEric Blake prop->get(obj, v, name, prop->opaque, errp); 130957c9fafeSAnthony Liguori } 131057c9fafeSAnthony Liguori } 131157c9fafeSAnthony Liguori 131257c9fafeSAnthony Liguori void object_property_set(Object *obj, Visitor *v, const char *name, 131357c9fafeSAnthony Liguori Error **errp) 131457c9fafeSAnthony Liguori { 131589bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 131657c9fafeSAnthony Liguori if (prop == NULL) { 131757c9fafeSAnthony Liguori return; 131857c9fafeSAnthony Liguori } 131957c9fafeSAnthony Liguori 132057c9fafeSAnthony Liguori if (!prop->set) { 1321c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PERMISSION_DENIED); 132257c9fafeSAnthony Liguori } else { 1323d7bce999SEric Blake prop->set(obj, v, name, prop->opaque, errp); 132457c9fafeSAnthony Liguori } 132557c9fafeSAnthony Liguori } 132657c9fafeSAnthony Liguori 13277b7b7d18SPaolo Bonzini void object_property_set_str(Object *obj, const char *value, 13287b7b7d18SPaolo Bonzini const char *name, Error **errp) 13297b7b7d18SPaolo Bonzini { 13307b7b7d18SPaolo Bonzini QString *qstr = qstring_from_str(value); 13317b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qstr), name, errp); 13327b7b7d18SPaolo Bonzini 1333cb3e7f08SMarc-André Lureau qobject_unref(qstr); 13347b7b7d18SPaolo Bonzini } 13357b7b7d18SPaolo Bonzini 13367b7b7d18SPaolo Bonzini char *object_property_get_str(Object *obj, const char *name, 13377b7b7d18SPaolo Bonzini Error **errp) 13387b7b7d18SPaolo Bonzini { 13397b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 13407b7b7d18SPaolo Bonzini char *retval; 13417b7b7d18SPaolo Bonzini 13427b7b7d18SPaolo Bonzini if (!ret) { 13437b7b7d18SPaolo Bonzini return NULL; 13447b7b7d18SPaolo Bonzini } 1345aafb21a0SPeter Xu 1346aafb21a0SPeter Xu retval = g_strdup(qobject_get_try_str(ret)); 1347aafb21a0SPeter Xu if (!retval) { 1348c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); 13497b7b7d18SPaolo Bonzini } 13507b7b7d18SPaolo Bonzini 1351cb3e7f08SMarc-André Lureau qobject_unref(ret); 13527b7b7d18SPaolo Bonzini return retval; 13537b7b7d18SPaolo Bonzini } 13547b7b7d18SPaolo Bonzini 13551d9c5a12SPaolo Bonzini void object_property_set_link(Object *obj, Object *value, 13561d9c5a12SPaolo Bonzini const char *name, Error **errp) 13571d9c5a12SPaolo Bonzini { 1358d3c49316SPeter Crosthwaite if (value) { 13592d3aa28cSVlad Yasevich gchar *path = object_get_canonical_path(value); 13602d3aa28cSVlad Yasevich object_property_set_str(obj, path, name, errp); 13612d3aa28cSVlad Yasevich g_free(path); 1362d3c49316SPeter Crosthwaite } else { 1363d3c49316SPeter Crosthwaite object_property_set_str(obj, "", name, errp); 1364d3c49316SPeter Crosthwaite } 13651d9c5a12SPaolo Bonzini } 13661d9c5a12SPaolo Bonzini 13671d9c5a12SPaolo Bonzini Object *object_property_get_link(Object *obj, const char *name, 13681d9c5a12SPaolo Bonzini Error **errp) 13691d9c5a12SPaolo Bonzini { 13701d9c5a12SPaolo Bonzini char *str = object_property_get_str(obj, name, errp); 13711d9c5a12SPaolo Bonzini Object *target = NULL; 13721d9c5a12SPaolo Bonzini 13731d9c5a12SPaolo Bonzini if (str && *str) { 13741d9c5a12SPaolo Bonzini target = object_resolve_path(str, NULL); 13751d9c5a12SPaolo Bonzini if (!target) { 137675158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 137775158ebbSMarkus Armbruster "Device '%s' not found", str); 13781d9c5a12SPaolo Bonzini } 13791d9c5a12SPaolo Bonzini } 13801d9c5a12SPaolo Bonzini 13811d9c5a12SPaolo Bonzini g_free(str); 13821d9c5a12SPaolo Bonzini return target; 13831d9c5a12SPaolo Bonzini } 13841d9c5a12SPaolo Bonzini 13857b7b7d18SPaolo Bonzini void object_property_set_bool(Object *obj, bool value, 13867b7b7d18SPaolo Bonzini const char *name, Error **errp) 13877b7b7d18SPaolo Bonzini { 1388fc48ffc3SEric Blake QBool *qbool = qbool_from_bool(value); 13897b7b7d18SPaolo Bonzini object_property_set_qobject(obj, QOBJECT(qbool), name, errp); 13907b7b7d18SPaolo Bonzini 1391cb3e7f08SMarc-André Lureau qobject_unref(qbool); 13927b7b7d18SPaolo Bonzini } 13937b7b7d18SPaolo Bonzini 13947b7b7d18SPaolo Bonzini bool object_property_get_bool(Object *obj, const char *name, 13957b7b7d18SPaolo Bonzini Error **errp) 13967b7b7d18SPaolo Bonzini { 13977b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 13987b7b7d18SPaolo Bonzini QBool *qbool; 13997b7b7d18SPaolo Bonzini bool retval; 14007b7b7d18SPaolo Bonzini 14017b7b7d18SPaolo Bonzini if (!ret) { 14027b7b7d18SPaolo Bonzini return false; 14037b7b7d18SPaolo Bonzini } 14047dc847ebSMax Reitz qbool = qobject_to(QBool, ret); 14057b7b7d18SPaolo Bonzini if (!qbool) { 1406c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); 14077b7b7d18SPaolo Bonzini retval = false; 14087b7b7d18SPaolo Bonzini } else { 1409fc48ffc3SEric Blake retval = qbool_get_bool(qbool); 14107b7b7d18SPaolo Bonzini } 14117b7b7d18SPaolo Bonzini 1412cb3e7f08SMarc-André Lureau qobject_unref(ret); 14137b7b7d18SPaolo Bonzini return retval; 14147b7b7d18SPaolo Bonzini } 14157b7b7d18SPaolo Bonzini 14167b7b7d18SPaolo Bonzini void object_property_set_int(Object *obj, int64_t value, 14177b7b7d18SPaolo Bonzini const char *name, Error **errp) 14187b7b7d18SPaolo Bonzini { 141901b2ffceSMarc-André Lureau QNum *qnum = qnum_from_int(value); 142001b2ffceSMarc-André Lureau object_property_set_qobject(obj, QOBJECT(qnum), name, errp); 14217b7b7d18SPaolo Bonzini 1422cb3e7f08SMarc-André Lureau qobject_unref(qnum); 14237b7b7d18SPaolo Bonzini } 14247b7b7d18SPaolo Bonzini 14257b7b7d18SPaolo Bonzini int64_t object_property_get_int(Object *obj, const char *name, 14267b7b7d18SPaolo Bonzini Error **errp) 14277b7b7d18SPaolo Bonzini { 14287b7b7d18SPaolo Bonzini QObject *ret = object_property_get_qobject(obj, name, errp); 142901b2ffceSMarc-André Lureau QNum *qnum; 14307b7b7d18SPaolo Bonzini int64_t retval; 14317b7b7d18SPaolo Bonzini 14327b7b7d18SPaolo Bonzini if (!ret) { 14337b7b7d18SPaolo Bonzini return -1; 14347b7b7d18SPaolo Bonzini } 143501b2ffceSMarc-André Lureau 14367dc847ebSMax Reitz qnum = qobject_to(QNum, ret); 143701b2ffceSMarc-André Lureau if (!qnum || !qnum_get_try_int(qnum, &retval)) { 1438c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); 14397b7b7d18SPaolo Bonzini retval = -1; 14407b7b7d18SPaolo Bonzini } 14417b7b7d18SPaolo Bonzini 1442cb3e7f08SMarc-André Lureau qobject_unref(ret); 14437b7b7d18SPaolo Bonzini return retval; 14447b7b7d18SPaolo Bonzini } 14457b7b7d18SPaolo Bonzini 14460e76ed0aSMarc-André Lureau static void object_property_init_defval(Object *obj, ObjectProperty *prop) 14470e76ed0aSMarc-André Lureau { 14480e76ed0aSMarc-André Lureau Visitor *v = qobject_input_visitor_new(prop->defval); 14490e76ed0aSMarc-André Lureau 14500e76ed0aSMarc-André Lureau assert(prop->set != NULL); 14510e76ed0aSMarc-André Lureau prop->set(obj, v, prop->name, prop->opaque, &error_abort); 14520e76ed0aSMarc-André Lureau 14530e76ed0aSMarc-André Lureau visit_free(v); 14540e76ed0aSMarc-André Lureau } 14550e76ed0aSMarc-André Lureau 14560e76ed0aSMarc-André Lureau static void object_property_set_default(ObjectProperty *prop, QObject *defval) 14570e76ed0aSMarc-André Lureau { 14580e76ed0aSMarc-André Lureau assert(!prop->defval); 14590e76ed0aSMarc-André Lureau assert(!prop->init); 14600e76ed0aSMarc-André Lureau 14610e76ed0aSMarc-André Lureau prop->defval = defval; 14620e76ed0aSMarc-André Lureau prop->init = object_property_init_defval; 14630e76ed0aSMarc-André Lureau } 14640e76ed0aSMarc-André Lureau 14650e76ed0aSMarc-André Lureau void object_property_set_default_bool(ObjectProperty *prop, bool value) 14660e76ed0aSMarc-André Lureau { 14670e76ed0aSMarc-André Lureau object_property_set_default(prop, QOBJECT(qbool_from_bool(value))); 14680e76ed0aSMarc-André Lureau } 14690e76ed0aSMarc-André Lureau 14700e76ed0aSMarc-André Lureau void object_property_set_default_str(ObjectProperty *prop, const char *value) 14710e76ed0aSMarc-André Lureau { 14720e76ed0aSMarc-André Lureau object_property_set_default(prop, QOBJECT(qstring_from_str(value))); 14730e76ed0aSMarc-André Lureau } 14740e76ed0aSMarc-André Lureau 14750e76ed0aSMarc-André Lureau void object_property_set_default_int(ObjectProperty *prop, int64_t value) 14760e76ed0aSMarc-André Lureau { 14770e76ed0aSMarc-André Lureau object_property_set_default(prop, QOBJECT(qnum_from_int(value))); 14780e76ed0aSMarc-André Lureau } 14790e76ed0aSMarc-André Lureau 14800e76ed0aSMarc-André Lureau void object_property_set_default_uint(ObjectProperty *prop, uint64_t value) 14810e76ed0aSMarc-André Lureau { 14820e76ed0aSMarc-André Lureau object_property_set_default(prop, QOBJECT(qnum_from_uint(value))); 14830e76ed0aSMarc-André Lureau } 14840e76ed0aSMarc-André Lureau 14853152779cSMarc-André Lureau void object_property_set_uint(Object *obj, uint64_t value, 14863152779cSMarc-André Lureau const char *name, Error **errp) 14873152779cSMarc-André Lureau { 14883152779cSMarc-André Lureau QNum *qnum = qnum_from_uint(value); 14893152779cSMarc-André Lureau 14903152779cSMarc-André Lureau object_property_set_qobject(obj, QOBJECT(qnum), name, errp); 1491cb3e7f08SMarc-André Lureau qobject_unref(qnum); 14923152779cSMarc-André Lureau } 14933152779cSMarc-André Lureau 14943152779cSMarc-André Lureau uint64_t object_property_get_uint(Object *obj, const char *name, 14953152779cSMarc-André Lureau Error **errp) 14963152779cSMarc-André Lureau { 14973152779cSMarc-André Lureau QObject *ret = object_property_get_qobject(obj, name, errp); 14983152779cSMarc-André Lureau QNum *qnum; 14993152779cSMarc-André Lureau uint64_t retval; 15003152779cSMarc-André Lureau 15013152779cSMarc-André Lureau if (!ret) { 15023152779cSMarc-André Lureau return 0; 15033152779cSMarc-André Lureau } 15047dc847ebSMax Reitz qnum = qobject_to(QNum, ret); 15053152779cSMarc-André Lureau if (!qnum || !qnum_get_try_uint(qnum, &retval)) { 15063152779cSMarc-André Lureau error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "uint"); 15073152779cSMarc-André Lureau retval = 0; 15083152779cSMarc-André Lureau } 15093152779cSMarc-André Lureau 1510cb3e7f08SMarc-André Lureau qobject_unref(ret); 15113152779cSMarc-André Lureau return retval; 15123152779cSMarc-André Lureau } 15133152779cSMarc-André Lureau 1514a8e3fbedSDaniel P. Berrange typedef struct EnumProperty { 1515f7abe0ecSMarc-André Lureau const QEnumLookup *lookup; 1516a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **); 1517a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **); 1518a8e3fbedSDaniel P. Berrange } EnumProperty; 1519a8e3fbedSDaniel P. Berrange 15201f21772dSHu Tao int object_property_get_enum(Object *obj, const char *name, 1521a3590dacSDaniel P. Berrange const char *typename, Error **errp) 15221f21772dSHu Tao { 15234715d42eSMarkus Armbruster Error *err = NULL; 15247a0525c7SEric Blake Visitor *v; 1525976620acSChen Fan char *str; 15261f21772dSHu Tao int ret; 1527a3590dacSDaniel P. Berrange ObjectProperty *prop = object_property_find(obj, name, errp); 1528a3590dacSDaniel P. Berrange EnumProperty *enumprop; 1529a3590dacSDaniel P. Berrange 1530a3590dacSDaniel P. Berrange if (prop == NULL) { 1531a3590dacSDaniel P. Berrange return 0; 1532a3590dacSDaniel P. Berrange } 1533a3590dacSDaniel P. Berrange 1534a3590dacSDaniel P. Berrange if (!g_str_equal(prop->type, typename)) { 1535a3590dacSDaniel P. Berrange error_setg(errp, "Property %s on %s is not '%s' enum type", 1536a3590dacSDaniel P. Berrange name, object_class_get_name( 1537a3590dacSDaniel P. Berrange object_get_class(obj)), typename); 1538a3590dacSDaniel P. Berrange return 0; 1539a3590dacSDaniel P. Berrange } 1540a3590dacSDaniel P. Berrange 1541a3590dacSDaniel P. Berrange enumprop = prop->opaque; 15421f21772dSHu Tao 15433b098d56SEric Blake v = string_output_visitor_new(false, &str); 1544e7ca5656SEric Blake object_property_get(obj, v, name, &err); 15454715d42eSMarkus Armbruster if (err) { 15464715d42eSMarkus Armbruster error_propagate(errp, err); 1547e7ca5656SEric Blake visit_free(v); 15484715d42eSMarkus Armbruster return 0; 15494715d42eSMarkus Armbruster } 15503b098d56SEric Blake visit_complete(v, &str); 1551e7ca5656SEric Blake visit_free(v); 15527a0525c7SEric Blake v = string_input_visitor_new(str); 1553f7abe0ecSMarc-André Lureau visit_type_enum(v, name, &ret, enumprop->lookup, errp); 1554976620acSChen Fan 1555976620acSChen Fan g_free(str); 15567a0525c7SEric Blake visit_free(v); 15571f21772dSHu Tao 15581f21772dSHu Tao return ret; 15591f21772dSHu Tao } 15601f21772dSHu Tao 15611f21772dSHu Tao void object_property_get_uint16List(Object *obj, const char *name, 15621f21772dSHu Tao uint16List **list, Error **errp) 15631f21772dSHu Tao { 15644715d42eSMarkus Armbruster Error *err = NULL; 15657a0525c7SEric Blake Visitor *v; 1566976620acSChen Fan char *str; 15671f21772dSHu Tao 15683b098d56SEric Blake v = string_output_visitor_new(false, &str); 15693b098d56SEric Blake object_property_get(obj, v, name, &err); 15704715d42eSMarkus Armbruster if (err) { 15714715d42eSMarkus Armbruster error_propagate(errp, err); 15724715d42eSMarkus Armbruster goto out; 15734715d42eSMarkus Armbruster } 15743b098d56SEric Blake visit_complete(v, &str); 15753b098d56SEric Blake visit_free(v); 15767a0525c7SEric Blake v = string_input_visitor_new(str); 15777a0525c7SEric Blake visit_type_uint16List(v, NULL, list, errp); 1578976620acSChen Fan 1579976620acSChen Fan g_free(str); 15804715d42eSMarkus Armbruster out: 15813b098d56SEric Blake visit_free(v); 15821f21772dSHu Tao } 15831f21772dSHu Tao 1584b2cd7deeSPaolo Bonzini void object_property_parse(Object *obj, const char *string, 1585b2cd7deeSPaolo Bonzini const char *name, Error **errp) 1586b2cd7deeSPaolo Bonzini { 15877a0525c7SEric Blake Visitor *v = string_input_visitor_new(string); 15887a0525c7SEric Blake object_property_set(obj, v, name, errp); 15897a0525c7SEric Blake visit_free(v); 1590b2cd7deeSPaolo Bonzini } 1591b2cd7deeSPaolo Bonzini 15920b7593e0SPaolo Bonzini char *object_property_print(Object *obj, const char *name, bool human, 1593b2cd7deeSPaolo Bonzini Error **errp) 1594b2cd7deeSPaolo Bonzini { 15953b098d56SEric Blake Visitor *v; 15963a53009fSGonglei char *string = NULL; 15973a53009fSGonglei Error *local_err = NULL; 1598b2cd7deeSPaolo Bonzini 15993b098d56SEric Blake v = string_output_visitor_new(human, &string); 16003b098d56SEric Blake object_property_get(obj, v, name, &local_err); 16013a53009fSGonglei if (local_err) { 16023a53009fSGonglei error_propagate(errp, local_err); 16033a53009fSGonglei goto out; 16043a53009fSGonglei } 16053a53009fSGonglei 16063b098d56SEric Blake visit_complete(v, &string); 16073a53009fSGonglei 16083a53009fSGonglei out: 16093b098d56SEric Blake visit_free(v); 1610b2cd7deeSPaolo Bonzini return string; 1611b2cd7deeSPaolo Bonzini } 1612b2cd7deeSPaolo Bonzini 161357c9fafeSAnthony Liguori const char *object_property_get_type(Object *obj, const char *name, Error **errp) 161457c9fafeSAnthony Liguori { 161589bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(obj, name, errp); 161657c9fafeSAnthony Liguori if (prop == NULL) { 161757c9fafeSAnthony Liguori return NULL; 161857c9fafeSAnthony Liguori } 161957c9fafeSAnthony Liguori 162057c9fafeSAnthony Liguori return prop->type; 162157c9fafeSAnthony Liguori } 162257c9fafeSAnthony Liguori 162357c9fafeSAnthony Liguori Object *object_get_root(void) 162457c9fafeSAnthony Liguori { 16258b45d447SAnthony Liguori static Object *root; 162657c9fafeSAnthony Liguori 16278b45d447SAnthony Liguori if (!root) { 16288b45d447SAnthony Liguori root = object_new("container"); 162957c9fafeSAnthony Liguori } 163057c9fafeSAnthony Liguori 16318b45d447SAnthony Liguori return root; 163257c9fafeSAnthony Liguori } 163357c9fafeSAnthony Liguori 1634bc2256c4SDaniel P. Berrange Object *object_get_objects_root(void) 1635bc2256c4SDaniel P. Berrange { 1636bc2256c4SDaniel P. Berrange return container_get(object_get_root(), "/objects"); 1637bc2256c4SDaniel P. Berrange } 1638bc2256c4SDaniel P. Berrange 16397c47c4eaSPeter Xu Object *object_get_internal_root(void) 16407c47c4eaSPeter Xu { 16417c47c4eaSPeter Xu static Object *internal_root; 16427c47c4eaSPeter Xu 16437c47c4eaSPeter Xu if (!internal_root) { 16447c47c4eaSPeter Xu internal_root = object_new("container"); 16457c47c4eaSPeter Xu } 16467c47c4eaSPeter Xu 16477c47c4eaSPeter Xu return internal_root; 16487c47c4eaSPeter Xu } 16497c47c4eaSPeter Xu 1650d7bce999SEric Blake static void object_get_child_property(Object *obj, Visitor *v, 1651d7bce999SEric Blake const char *name, void *opaque, 1652d7bce999SEric Blake Error **errp) 165357c9fafeSAnthony Liguori { 165457c9fafeSAnthony Liguori Object *child = opaque; 165557c9fafeSAnthony Liguori gchar *path; 165657c9fafeSAnthony Liguori 165757c9fafeSAnthony Liguori path = object_get_canonical_path(child); 165851e72bc1SEric Blake visit_type_str(v, name, &path, errp); 165957c9fafeSAnthony Liguori g_free(path); 166057c9fafeSAnthony Liguori } 166157c9fafeSAnthony Liguori 166264607d08SPaolo Bonzini static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part) 166364607d08SPaolo Bonzini { 166464607d08SPaolo Bonzini return opaque; 166564607d08SPaolo Bonzini } 166664607d08SPaolo Bonzini 1667db85b575SAnthony Liguori static void object_finalize_child_property(Object *obj, const char *name, 1668db85b575SAnthony Liguori void *opaque) 1669db85b575SAnthony Liguori { 1670db85b575SAnthony Liguori Object *child = opaque; 1671db85b575SAnthony Liguori 1672bffc687dSPaolo Bonzini if (child->class->unparent) { 1673bffc687dSPaolo Bonzini (child->class->unparent)(child); 1674bffc687dSPaolo Bonzini } 1675bffc687dSPaolo Bonzini child->parent = NULL; 1676db85b575SAnthony Liguori object_unref(child); 1677db85b575SAnthony Liguori } 1678db85b575SAnthony Liguori 167957c9fafeSAnthony Liguori void object_property_add_child(Object *obj, const char *name, 168057c9fafeSAnthony Liguori Object *child, Error **errp) 168157c9fafeSAnthony Liguori { 1682b0ed5e9fSPaolo Bonzini Error *local_err = NULL; 168357c9fafeSAnthony Liguori gchar *type; 168464607d08SPaolo Bonzini ObjectProperty *op; 168557c9fafeSAnthony Liguori 16868faa2f85SPeter Crosthwaite if (child->parent != NULL) { 16878faa2f85SPeter Crosthwaite error_setg(errp, "child object is already parented"); 16888faa2f85SPeter Crosthwaite return; 16898faa2f85SPeter Crosthwaite } 16908faa2f85SPeter Crosthwaite 169157c9fafeSAnthony Liguori type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); 169257c9fafeSAnthony Liguori 169364607d08SPaolo Bonzini op = object_property_add(obj, name, type, object_get_child_property, NULL, 1694b0ed5e9fSPaolo Bonzini object_finalize_child_property, child, &local_err); 1695b0ed5e9fSPaolo Bonzini if (local_err) { 1696b0ed5e9fSPaolo Bonzini error_propagate(errp, local_err); 1697b0ed5e9fSPaolo Bonzini goto out; 1698b0ed5e9fSPaolo Bonzini } 169964607d08SPaolo Bonzini 170064607d08SPaolo Bonzini op->resolve = object_resolve_child_property; 170157c9fafeSAnthony Liguori object_ref(child); 170257c9fafeSAnthony Liguori child->parent = obj; 170357c9fafeSAnthony Liguori 1704b0ed5e9fSPaolo Bonzini out: 170557c9fafeSAnthony Liguori g_free(type); 170657c9fafeSAnthony Liguori } 170757c9fafeSAnthony Liguori 17088f5d58efSIgor Mammedov void object_property_allow_set_link(const Object *obj, const char *name, 170939f72ef9SStefan Hajnoczi Object *val, Error **errp) 171039f72ef9SStefan Hajnoczi { 171139f72ef9SStefan Hajnoczi /* Allow the link to be set, always */ 171239f72ef9SStefan Hajnoczi } 171339f72ef9SStefan Hajnoczi 17149561fda8SStefan Hajnoczi typedef struct { 17159941d37bSMarc-André Lureau union { 171636854207SMarc-André Lureau Object **targetp; 17179941d37bSMarc-André Lureau Object *target; /* if OBJ_PROP_LINK_DIRECT, when holding the pointer */ 1718840ecdfbSMarc-André Lureau ptrdiff_t offset; /* if OBJ_PROP_LINK_CLASS */ 17199941d37bSMarc-André Lureau }; 17208f5d58efSIgor Mammedov void (*check)(const Object *, const char *, Object *, Error **); 17219561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags; 17229561fda8SStefan Hajnoczi } LinkProperty; 17239561fda8SStefan Hajnoczi 17249941d37bSMarc-André Lureau static Object ** 17259941d37bSMarc-André Lureau object_link_get_targetp(Object *obj, LinkProperty *lprop) 17269941d37bSMarc-André Lureau { 17279941d37bSMarc-André Lureau if (lprop->flags & OBJ_PROP_LINK_DIRECT) { 17289941d37bSMarc-André Lureau return &lprop->target; 1729840ecdfbSMarc-André Lureau } else if (lprop->flags & OBJ_PROP_LINK_CLASS) { 1730840ecdfbSMarc-André Lureau return (void *)obj + lprop->offset; 17319941d37bSMarc-André Lureau } else { 17329941d37bSMarc-André Lureau return lprop->targetp; 17339941d37bSMarc-André Lureau } 17349941d37bSMarc-André Lureau } 17359941d37bSMarc-André Lureau 1736d7bce999SEric Blake static void object_get_link_property(Object *obj, Visitor *v, 1737d7bce999SEric Blake const char *name, void *opaque, 1738d7bce999SEric Blake Error **errp) 173957c9fafeSAnthony Liguori { 17409561fda8SStefan Hajnoczi LinkProperty *lprop = opaque; 17419941d37bSMarc-André Lureau Object **targetp = object_link_get_targetp(obj, lprop); 174257c9fafeSAnthony Liguori gchar *path; 174357c9fafeSAnthony Liguori 174436854207SMarc-André Lureau if (*targetp) { 174536854207SMarc-André Lureau path = object_get_canonical_path(*targetp); 174651e72bc1SEric Blake visit_type_str(v, name, &path, errp); 174757c9fafeSAnthony Liguori g_free(path); 174857c9fafeSAnthony Liguori } else { 174957c9fafeSAnthony Liguori path = (gchar *)""; 175051e72bc1SEric Blake visit_type_str(v, name, &path, errp); 175157c9fafeSAnthony Liguori } 175257c9fafeSAnthony Liguori } 175357c9fafeSAnthony Liguori 1754f5ec6704SStefan Hajnoczi /* 1755f5ec6704SStefan Hajnoczi * object_resolve_link: 1756f5ec6704SStefan Hajnoczi * 1757f5ec6704SStefan Hajnoczi * Lookup an object and ensure its type matches the link property type. This 1758f5ec6704SStefan Hajnoczi * is similar to object_resolve_path() except type verification against the 1759f5ec6704SStefan Hajnoczi * link property is performed. 1760f5ec6704SStefan Hajnoczi * 1761f5ec6704SStefan Hajnoczi * Returns: The matched object or NULL on path lookup failures. 1762f5ec6704SStefan Hajnoczi */ 1763f5ec6704SStefan Hajnoczi static Object *object_resolve_link(Object *obj, const char *name, 1764f5ec6704SStefan Hajnoczi const char *path, Error **errp) 1765f5ec6704SStefan Hajnoczi { 1766f5ec6704SStefan Hajnoczi const char *type; 1767f5ec6704SStefan Hajnoczi gchar *target_type; 1768f5ec6704SStefan Hajnoczi bool ambiguous = false; 1769f5ec6704SStefan Hajnoczi Object *target; 1770f5ec6704SStefan Hajnoczi 1771f5ec6704SStefan Hajnoczi /* Go from link<FOO> to FOO. */ 1772f5ec6704SStefan Hajnoczi type = object_property_get_type(obj, name, NULL); 1773f5ec6704SStefan Hajnoczi target_type = g_strndup(&type[5], strlen(type) - 6); 1774f5ec6704SStefan Hajnoczi target = object_resolve_path_type(path, target_type, &ambiguous); 1775f5ec6704SStefan Hajnoczi 1776f5ec6704SStefan Hajnoczi if (ambiguous) { 1777455b0fdeSEric Blake error_setg(errp, "Path '%s' does not uniquely identify an object", 1778455b0fdeSEric Blake path); 1779f5ec6704SStefan Hajnoczi } else if (!target) { 1780f5ec6704SStefan Hajnoczi target = object_resolve_path(path, &ambiguous); 1781f5ec6704SStefan Hajnoczi if (target || ambiguous) { 1782c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); 1783f5ec6704SStefan Hajnoczi } else { 178475158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 178575158ebbSMarkus Armbruster "Device '%s' not found", path); 1786f5ec6704SStefan Hajnoczi } 1787f5ec6704SStefan Hajnoczi target = NULL; 1788f5ec6704SStefan Hajnoczi } 1789f5ec6704SStefan Hajnoczi g_free(target_type); 1790f5ec6704SStefan Hajnoczi 1791f5ec6704SStefan Hajnoczi return target; 1792f5ec6704SStefan Hajnoczi } 1793f5ec6704SStefan Hajnoczi 1794d7bce999SEric Blake static void object_set_link_property(Object *obj, Visitor *v, 1795d7bce999SEric Blake const char *name, void *opaque, 1796d7bce999SEric Blake Error **errp) 179757c9fafeSAnthony Liguori { 1798c6aed983SStefan Hajnoczi Error *local_err = NULL; 17999561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 18009941d37bSMarc-André Lureau Object **targetp = object_link_get_targetp(obj, prop); 180136854207SMarc-André Lureau Object *old_target = *targetp; 1802c6aed983SStefan Hajnoczi Object *new_target = NULL; 1803c6aed983SStefan Hajnoczi char *path = NULL; 180457c9fafeSAnthony Liguori 180551e72bc1SEric Blake visit_type_str(v, name, &path, &local_err); 180657c9fafeSAnthony Liguori 1807c6aed983SStefan Hajnoczi if (!local_err && strcmp(path, "") != 0) { 1808c6aed983SStefan Hajnoczi new_target = object_resolve_link(obj, name, path, &local_err); 180911e35bfdSPaolo Bonzini } 181057c9fafeSAnthony Liguori 181157c9fafeSAnthony Liguori g_free(path); 1812c6aed983SStefan Hajnoczi if (local_err) { 1813c6aed983SStefan Hajnoczi error_propagate(errp, local_err); 1814c6aed983SStefan Hajnoczi return; 1815c6aed983SStefan Hajnoczi } 1816f0cdc966SAlexander Barabash 181739f72ef9SStefan Hajnoczi prop->check(obj, name, new_target, &local_err); 181839f72ef9SStefan Hajnoczi if (local_err) { 181939f72ef9SStefan Hajnoczi error_propagate(errp, local_err); 182039f72ef9SStefan Hajnoczi return; 182139f72ef9SStefan Hajnoczi } 182239f72ef9SStefan Hajnoczi 182336854207SMarc-André Lureau *targetp = new_target; 18248770bafdSMarc-André Lureau if (prop->flags & OBJ_PROP_LINK_STRONG) { 1825265b578cSMarc-André Lureau object_ref(new_target); 1826f0cdc966SAlexander Barabash object_unref(old_target); 1827f0cdc966SAlexander Barabash } 1828265b578cSMarc-André Lureau } 182957c9fafeSAnthony Liguori 183064607d08SPaolo Bonzini static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) 183164607d08SPaolo Bonzini { 183264607d08SPaolo Bonzini LinkProperty *lprop = opaque; 183364607d08SPaolo Bonzini 18349941d37bSMarc-André Lureau return *object_link_get_targetp(parent, lprop); 183564607d08SPaolo Bonzini } 183664607d08SPaolo Bonzini 18379561fda8SStefan Hajnoczi static void object_release_link_property(Object *obj, const char *name, 18389561fda8SStefan Hajnoczi void *opaque) 18399561fda8SStefan Hajnoczi { 18409561fda8SStefan Hajnoczi LinkProperty *prop = opaque; 18419941d37bSMarc-André Lureau Object **targetp = object_link_get_targetp(obj, prop); 18429561fda8SStefan Hajnoczi 18439941d37bSMarc-André Lureau if ((prop->flags & OBJ_PROP_LINK_STRONG) && *targetp) { 18449941d37bSMarc-André Lureau object_unref(*targetp); 18459561fda8SStefan Hajnoczi } 1846840ecdfbSMarc-André Lureau if (!(prop->flags & OBJ_PROP_LINK_CLASS)) { 18479561fda8SStefan Hajnoczi g_free(prop); 18489561fda8SStefan Hajnoczi } 1849840ecdfbSMarc-André Lureau } 18509561fda8SStefan Hajnoczi 18514a8d5798SMarc-André Lureau static void object_add_link_prop(Object *obj, const char *name, 18524a8d5798SMarc-André Lureau const char *type, void *ptr, 18538f5d58efSIgor Mammedov void (*check)(const Object *, const char *, 185439f72ef9SStefan Hajnoczi Object *, Error **), 18559561fda8SStefan Hajnoczi ObjectPropertyLinkFlags flags, 185657c9fafeSAnthony Liguori Error **errp) 185757c9fafeSAnthony Liguori { 18589561fda8SStefan Hajnoczi Error *local_err = NULL; 18599561fda8SStefan Hajnoczi LinkProperty *prop = g_malloc(sizeof(*prop)); 186057c9fafeSAnthony Liguori gchar *full_type; 186164607d08SPaolo Bonzini ObjectProperty *op; 186257c9fafeSAnthony Liguori 18634a8d5798SMarc-André Lureau if (flags & OBJ_PROP_LINK_DIRECT) { 18644a8d5798SMarc-André Lureau prop->target = ptr; 18654a8d5798SMarc-André Lureau } else { 18664a8d5798SMarc-André Lureau prop->targetp = ptr; 18674a8d5798SMarc-André Lureau } 186839f72ef9SStefan Hajnoczi prop->check = check; 18699561fda8SStefan Hajnoczi prop->flags = flags; 18709561fda8SStefan Hajnoczi 187157c9fafeSAnthony Liguori full_type = g_strdup_printf("link<%s>", type); 187257c9fafeSAnthony Liguori 187364607d08SPaolo Bonzini op = object_property_add(obj, name, full_type, 187457c9fafeSAnthony Liguori object_get_link_property, 187539f72ef9SStefan Hajnoczi check ? object_set_link_property : NULL, 18769561fda8SStefan Hajnoczi object_release_link_property, 18779561fda8SStefan Hajnoczi prop, 18789561fda8SStefan Hajnoczi &local_err); 18799561fda8SStefan Hajnoczi if (local_err) { 18809561fda8SStefan Hajnoczi error_propagate(errp, local_err); 18819561fda8SStefan Hajnoczi g_free(prop); 188264607d08SPaolo Bonzini goto out; 18839561fda8SStefan Hajnoczi } 188457c9fafeSAnthony Liguori 188564607d08SPaolo Bonzini op->resolve = object_resolve_link_property; 188664607d08SPaolo Bonzini 188764607d08SPaolo Bonzini out: 188857c9fafeSAnthony Liguori g_free(full_type); 188957c9fafeSAnthony Liguori } 189057c9fafeSAnthony Liguori 18914a8d5798SMarc-André Lureau void object_property_add_link(Object *obj, const char *name, 18924a8d5798SMarc-André Lureau const char *type, Object **targetp, 18934a8d5798SMarc-André Lureau void (*check)(const Object *, const char *, 18944a8d5798SMarc-André Lureau Object *, Error **), 18954a8d5798SMarc-André Lureau ObjectPropertyLinkFlags flags, 18964a8d5798SMarc-André Lureau Error **errp) 18974a8d5798SMarc-André Lureau { 18984a8d5798SMarc-André Lureau object_add_link_prop(obj, name, type, targetp, check, flags, errp); 18994a8d5798SMarc-André Lureau } 19004a8d5798SMarc-André Lureau 1901840ecdfbSMarc-André Lureau ObjectProperty * 1902840ecdfbSMarc-André Lureau object_class_property_add_link(ObjectClass *oc, 1903840ecdfbSMarc-André Lureau const char *name, 1904840ecdfbSMarc-André Lureau const char *type, ptrdiff_t offset, 1905840ecdfbSMarc-André Lureau void (*check)(const Object *obj, const char *name, 1906840ecdfbSMarc-André Lureau Object *val, Error **errp), 1907840ecdfbSMarc-André Lureau ObjectPropertyLinkFlags flags, 1908840ecdfbSMarc-André Lureau Error **errp) 1909840ecdfbSMarc-André Lureau { 1910840ecdfbSMarc-André Lureau Error *local_err = NULL; 1911840ecdfbSMarc-André Lureau LinkProperty *prop = g_new0(LinkProperty, 1); 1912840ecdfbSMarc-André Lureau gchar *full_type; 1913840ecdfbSMarc-André Lureau ObjectProperty *op; 1914840ecdfbSMarc-André Lureau 1915840ecdfbSMarc-André Lureau prop->offset = offset; 1916840ecdfbSMarc-André Lureau prop->check = check; 1917840ecdfbSMarc-André Lureau prop->flags = flags | OBJ_PROP_LINK_CLASS; 1918840ecdfbSMarc-André Lureau 1919840ecdfbSMarc-André Lureau full_type = g_strdup_printf("link<%s>", type); 1920840ecdfbSMarc-André Lureau 1921840ecdfbSMarc-André Lureau op = object_class_property_add(oc, name, full_type, 1922840ecdfbSMarc-André Lureau object_get_link_property, 1923840ecdfbSMarc-André Lureau check ? object_set_link_property : NULL, 1924840ecdfbSMarc-André Lureau object_release_link_property, 1925840ecdfbSMarc-André Lureau prop, 1926840ecdfbSMarc-André Lureau &local_err); 1927840ecdfbSMarc-André Lureau if (local_err) { 1928840ecdfbSMarc-André Lureau error_propagate(errp, local_err); 1929840ecdfbSMarc-André Lureau g_free(prop); 1930840ecdfbSMarc-André Lureau goto out; 1931840ecdfbSMarc-André Lureau } 1932840ecdfbSMarc-André Lureau 1933840ecdfbSMarc-André Lureau op->resolve = object_resolve_link_property; 1934840ecdfbSMarc-André Lureau 1935840ecdfbSMarc-André Lureau out: 1936840ecdfbSMarc-André Lureau g_free(full_type); 1937840ecdfbSMarc-André Lureau return op; 1938840ecdfbSMarc-André Lureau } 1939840ecdfbSMarc-André Lureau 1940fb9e7e33SPaolo Bonzini void object_property_add_const_link(Object *obj, const char *name, 1941fb9e7e33SPaolo Bonzini Object *target, Error **errp) 1942fb9e7e33SPaolo Bonzini { 19434a8d5798SMarc-André Lureau object_add_link_prop(obj, name, object_get_typename(target), target, 19444a8d5798SMarc-André Lureau NULL, OBJ_PROP_LINK_DIRECT, errp); 1945fb9e7e33SPaolo Bonzini } 1946fb9e7e33SPaolo Bonzini 194711f590b1SStefan Hajnoczi gchar *object_get_canonical_path_component(Object *obj) 194857c9fafeSAnthony Liguori { 194957c9fafeSAnthony Liguori ObjectProperty *prop = NULL; 1950b604a854SPavel Fedin GHashTableIter iter; 195157c9fafeSAnthony Liguori 1952770dec26SPaolo Bonzini if (obj->parent == NULL) { 1953770dec26SPaolo Bonzini return NULL; 1954770dec26SPaolo Bonzini } 195557c9fafeSAnthony Liguori 1956b604a854SPavel Fedin g_hash_table_iter_init(&iter, obj->parent->properties); 1957b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 19585d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 195957c9fafeSAnthony Liguori continue; 196057c9fafeSAnthony Liguori } 196157c9fafeSAnthony Liguori 196257c9fafeSAnthony Liguori if (prop->opaque == obj) { 196311f590b1SStefan Hajnoczi return g_strdup(prop->name); 196457c9fafeSAnthony Liguori } 196557c9fafeSAnthony Liguori } 196657c9fafeSAnthony Liguori 196711f590b1SStefan Hajnoczi /* obj had a parent but was not a child, should never happen */ 196811f590b1SStefan Hajnoczi g_assert_not_reached(); 196911f590b1SStefan Hajnoczi return NULL; 197011f590b1SStefan Hajnoczi } 197111f590b1SStefan Hajnoczi 197211f590b1SStefan Hajnoczi gchar *object_get_canonical_path(Object *obj) 197311f590b1SStefan Hajnoczi { 197411f590b1SStefan Hajnoczi Object *root = object_get_root(); 197511f590b1SStefan Hajnoczi char *newpath, *path = NULL; 197611f590b1SStefan Hajnoczi 1977e40077fdSPaolo Bonzini if (obj == root) { 1978e40077fdSPaolo Bonzini return g_strdup("/"); 1979e40077fdSPaolo Bonzini } 1980e40077fdSPaolo Bonzini 1981e40077fdSPaolo Bonzini do { 198211f590b1SStefan Hajnoczi char *component = object_get_canonical_path_component(obj); 198311f590b1SStefan Hajnoczi 1984e40077fdSPaolo Bonzini if (!component) { 1985e40077fdSPaolo Bonzini /* A canonical path must be complete, so discard what was 1986e40077fdSPaolo Bonzini * collected so far. 1987e40077fdSPaolo Bonzini */ 1988e40077fdSPaolo Bonzini g_free(path); 1989e40077fdSPaolo Bonzini return NULL; 1990e40077fdSPaolo Bonzini } 1991e40077fdSPaolo Bonzini 1992e40077fdSPaolo Bonzini newpath = g_strdup_printf("/%s%s", component, path ? path : ""); 1993e40077fdSPaolo Bonzini g_free(path); 199411f590b1SStefan Hajnoczi g_free(component); 199511f590b1SStefan Hajnoczi path = newpath; 199657c9fafeSAnthony Liguori obj = obj->parent; 1997e40077fdSPaolo Bonzini } while (obj != root); 199857c9fafeSAnthony Liguori 1999e40077fdSPaolo Bonzini return path; 200057c9fafeSAnthony Liguori } 200157c9fafeSAnthony Liguori 20023e84b483SAndreas Färber Object *object_resolve_path_component(Object *parent, const gchar *part) 2003a612b2a6SPaolo Bonzini { 200489bfe000SPaolo Bonzini ObjectProperty *prop = object_property_find(parent, part, NULL); 2005a612b2a6SPaolo Bonzini if (prop == NULL) { 2006a612b2a6SPaolo Bonzini return NULL; 2007a612b2a6SPaolo Bonzini } 2008a612b2a6SPaolo Bonzini 200964607d08SPaolo Bonzini if (prop->resolve) { 201064607d08SPaolo Bonzini return prop->resolve(parent, prop->opaque, part); 2011a612b2a6SPaolo Bonzini } else { 2012a612b2a6SPaolo Bonzini return NULL; 2013a612b2a6SPaolo Bonzini } 2014a612b2a6SPaolo Bonzini } 2015a612b2a6SPaolo Bonzini 201657c9fafeSAnthony Liguori static Object *object_resolve_abs_path(Object *parent, 201757c9fafeSAnthony Liguori gchar **parts, 201802fe2db6SPaolo Bonzini const char *typename, 201957c9fafeSAnthony Liguori int index) 202057c9fafeSAnthony Liguori { 202157c9fafeSAnthony Liguori Object *child; 202257c9fafeSAnthony Liguori 202357c9fafeSAnthony Liguori if (parts[index] == NULL) { 202402fe2db6SPaolo Bonzini return object_dynamic_cast(parent, typename); 202557c9fafeSAnthony Liguori } 202657c9fafeSAnthony Liguori 202757c9fafeSAnthony Liguori if (strcmp(parts[index], "") == 0) { 202802fe2db6SPaolo Bonzini return object_resolve_abs_path(parent, parts, typename, index + 1); 202957c9fafeSAnthony Liguori } 203057c9fafeSAnthony Liguori 2031a612b2a6SPaolo Bonzini child = object_resolve_path_component(parent, parts[index]); 203257c9fafeSAnthony Liguori if (!child) { 203357c9fafeSAnthony Liguori return NULL; 203457c9fafeSAnthony Liguori } 203557c9fafeSAnthony Liguori 203602fe2db6SPaolo Bonzini return object_resolve_abs_path(child, parts, typename, index + 1); 203757c9fafeSAnthony Liguori } 203857c9fafeSAnthony Liguori 203957c9fafeSAnthony Liguori static Object *object_resolve_partial_path(Object *parent, 204057c9fafeSAnthony Liguori gchar **parts, 204102fe2db6SPaolo Bonzini const char *typename, 204257c9fafeSAnthony Liguori bool *ambiguous) 204357c9fafeSAnthony Liguori { 204457c9fafeSAnthony Liguori Object *obj; 2045b604a854SPavel Fedin GHashTableIter iter; 204657c9fafeSAnthony Liguori ObjectProperty *prop; 204757c9fafeSAnthony Liguori 204802fe2db6SPaolo Bonzini obj = object_resolve_abs_path(parent, parts, typename, 0); 204957c9fafeSAnthony Liguori 2050b604a854SPavel Fedin g_hash_table_iter_init(&iter, parent->properties); 2051b604a854SPavel Fedin while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&prop)) { 205257c9fafeSAnthony Liguori Object *found; 205357c9fafeSAnthony Liguori 20545d9d3f47SAndreas Färber if (!object_property_is_child(prop)) { 205557c9fafeSAnthony Liguori continue; 205657c9fafeSAnthony Liguori } 205757c9fafeSAnthony Liguori 205802fe2db6SPaolo Bonzini found = object_resolve_partial_path(prop->opaque, parts, 205902fe2db6SPaolo Bonzini typename, ambiguous); 206057c9fafeSAnthony Liguori if (found) { 206157c9fafeSAnthony Liguori if (obj) { 206257c9fafeSAnthony Liguori *ambiguous = true; 206357c9fafeSAnthony Liguori return NULL; 206457c9fafeSAnthony Liguori } 206557c9fafeSAnthony Liguori obj = found; 206657c9fafeSAnthony Liguori } 206757c9fafeSAnthony Liguori 2068ebcc479eSEduardo Habkost if (*ambiguous) { 206957c9fafeSAnthony Liguori return NULL; 207057c9fafeSAnthony Liguori } 207157c9fafeSAnthony Liguori } 207257c9fafeSAnthony Liguori 207357c9fafeSAnthony Liguori return obj; 207457c9fafeSAnthony Liguori } 207557c9fafeSAnthony Liguori 207602fe2db6SPaolo Bonzini Object *object_resolve_path_type(const char *path, const char *typename, 2077ebcc479eSEduardo Habkost bool *ambiguousp) 207857c9fafeSAnthony Liguori { 207957c9fafeSAnthony Liguori Object *obj; 208057c9fafeSAnthony Liguori gchar **parts; 208157c9fafeSAnthony Liguori 208257c9fafeSAnthony Liguori parts = g_strsplit(path, "/", 0); 20832e1103f6SPaolo Bonzini assert(parts); 208457c9fafeSAnthony Liguori 20852e1103f6SPaolo Bonzini if (parts[0] == NULL || strcmp(parts[0], "") != 0) { 2086ebcc479eSEduardo Habkost bool ambiguous = false; 208702fe2db6SPaolo Bonzini obj = object_resolve_partial_path(object_get_root(), parts, 2088ebcc479eSEduardo Habkost typename, &ambiguous); 2089ebcc479eSEduardo Habkost if (ambiguousp) { 2090ebcc479eSEduardo Habkost *ambiguousp = ambiguous; 2091ebcc479eSEduardo Habkost } 209257c9fafeSAnthony Liguori } else { 209302fe2db6SPaolo Bonzini obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); 209457c9fafeSAnthony Liguori } 209557c9fafeSAnthony Liguori 209657c9fafeSAnthony Liguori g_strfreev(parts); 209757c9fafeSAnthony Liguori 209857c9fafeSAnthony Liguori return obj; 209957c9fafeSAnthony Liguori } 210057c9fafeSAnthony Liguori 210102fe2db6SPaolo Bonzini Object *object_resolve_path(const char *path, bool *ambiguous) 210202fe2db6SPaolo Bonzini { 210302fe2db6SPaolo Bonzini return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); 210402fe2db6SPaolo Bonzini } 210502fe2db6SPaolo Bonzini 210657c9fafeSAnthony Liguori typedef struct StringProperty 210757c9fafeSAnthony Liguori { 210857c9fafeSAnthony Liguori char *(*get)(Object *, Error **); 210957c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **); 211057c9fafeSAnthony Liguori } StringProperty; 211157c9fafeSAnthony Liguori 2112d7bce999SEric Blake static void property_get_str(Object *obj, Visitor *v, const char *name, 2113d7bce999SEric Blake void *opaque, Error **errp) 211457c9fafeSAnthony Liguori { 211557c9fafeSAnthony Liguori StringProperty *prop = opaque; 211657c9fafeSAnthony Liguori char *value; 2117e1c8237dSMarkus Armbruster Error *err = NULL; 211857c9fafeSAnthony Liguori 2119e1c8237dSMarkus Armbruster value = prop->get(obj, &err); 2120e1c8237dSMarkus Armbruster if (err) { 2121e1c8237dSMarkus Armbruster error_propagate(errp, err); 2122e1c8237dSMarkus Armbruster return; 2123e1c8237dSMarkus Armbruster } 2124e1c8237dSMarkus Armbruster 212551e72bc1SEric Blake visit_type_str(v, name, &value, errp); 212657c9fafeSAnthony Liguori g_free(value); 212757c9fafeSAnthony Liguori } 212857c9fafeSAnthony Liguori 2129d7bce999SEric Blake static void property_set_str(Object *obj, Visitor *v, const char *name, 2130d7bce999SEric Blake void *opaque, Error **errp) 213157c9fafeSAnthony Liguori { 213257c9fafeSAnthony Liguori StringProperty *prop = opaque; 213357c9fafeSAnthony Liguori char *value; 213457c9fafeSAnthony Liguori Error *local_err = NULL; 213557c9fafeSAnthony Liguori 213651e72bc1SEric Blake visit_type_str(v, name, &value, &local_err); 213757c9fafeSAnthony Liguori if (local_err) { 213857c9fafeSAnthony Liguori error_propagate(errp, local_err); 213957c9fafeSAnthony Liguori return; 214057c9fafeSAnthony Liguori } 214157c9fafeSAnthony Liguori 214257c9fafeSAnthony Liguori prop->set(obj, value, errp); 214357c9fafeSAnthony Liguori g_free(value); 214457c9fafeSAnthony Liguori } 214557c9fafeSAnthony Liguori 21467b7b7d18SPaolo Bonzini static void property_release_str(Object *obj, const char *name, 214757c9fafeSAnthony Liguori void *opaque) 214857c9fafeSAnthony Liguori { 214957c9fafeSAnthony Liguori StringProperty *prop = opaque; 215057c9fafeSAnthony Liguori g_free(prop); 215157c9fafeSAnthony Liguori } 215257c9fafeSAnthony Liguori 215357c9fafeSAnthony Liguori void object_property_add_str(Object *obj, const char *name, 215457c9fafeSAnthony Liguori char *(*get)(Object *, Error **), 215557c9fafeSAnthony Liguori void (*set)(Object *, const char *, Error **), 215657c9fafeSAnthony Liguori Error **errp) 215757c9fafeSAnthony Liguori { 2158a01aedc8SStefan Hajnoczi Error *local_err = NULL; 215957c9fafeSAnthony Liguori StringProperty *prop = g_malloc0(sizeof(*prop)); 216057c9fafeSAnthony Liguori 216157c9fafeSAnthony Liguori prop->get = get; 216257c9fafeSAnthony Liguori prop->set = set; 216357c9fafeSAnthony Liguori 216457c9fafeSAnthony Liguori object_property_add(obj, name, "string", 21657b7b7d18SPaolo Bonzini get ? property_get_str : NULL, 21667b7b7d18SPaolo Bonzini set ? property_set_str : NULL, 21677b7b7d18SPaolo Bonzini property_release_str, 2168a01aedc8SStefan Hajnoczi prop, &local_err); 2169a01aedc8SStefan Hajnoczi if (local_err) { 2170a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 2171a01aedc8SStefan Hajnoczi g_free(prop); 2172a01aedc8SStefan Hajnoczi } 217357c9fafeSAnthony Liguori } 2174745549c8SPaolo Bonzini 2175a3a16211SMarc-André Lureau ObjectProperty * 2176a3a16211SMarc-André Lureau object_class_property_add_str(ObjectClass *klass, const char *name, 217716bf7f52SDaniel P. Berrange char *(*get)(Object *, Error **), 217816bf7f52SDaniel P. Berrange void (*set)(Object *, const char *, 217916bf7f52SDaniel P. Berrange Error **), 218016bf7f52SDaniel P. Berrange Error **errp) 218116bf7f52SDaniel P. Berrange { 218216bf7f52SDaniel P. Berrange Error *local_err = NULL; 218316bf7f52SDaniel P. Berrange StringProperty *prop = g_malloc0(sizeof(*prop)); 2184a3a16211SMarc-André Lureau ObjectProperty *rv; 218516bf7f52SDaniel P. Berrange 218616bf7f52SDaniel P. Berrange prop->get = get; 218716bf7f52SDaniel P. Berrange prop->set = set; 218816bf7f52SDaniel P. Berrange 2189a3a16211SMarc-André Lureau rv = object_class_property_add(klass, name, "string", 219016bf7f52SDaniel P. Berrange get ? property_get_str : NULL, 219116bf7f52SDaniel P. Berrange set ? property_set_str : NULL, 2192fc4fe712SMarc-André Lureau NULL, 219316bf7f52SDaniel P. Berrange prop, &local_err); 219416bf7f52SDaniel P. Berrange if (local_err) { 219516bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 219616bf7f52SDaniel P. Berrange g_free(prop); 219716bf7f52SDaniel P. Berrange } 2198a3a16211SMarc-André Lureau 2199a3a16211SMarc-André Lureau return rv; 220016bf7f52SDaniel P. Berrange } 220116bf7f52SDaniel P. Berrange 22020e558843SAnthony Liguori typedef struct BoolProperty 22030e558843SAnthony Liguori { 22040e558843SAnthony Liguori bool (*get)(Object *, Error **); 22050e558843SAnthony Liguori void (*set)(Object *, bool, Error **); 22060e558843SAnthony Liguori } BoolProperty; 22070e558843SAnthony Liguori 2208d7bce999SEric Blake static void property_get_bool(Object *obj, Visitor *v, const char *name, 2209d7bce999SEric Blake void *opaque, Error **errp) 22100e558843SAnthony Liguori { 22110e558843SAnthony Liguori BoolProperty *prop = opaque; 22120e558843SAnthony Liguori bool value; 22134715d42eSMarkus Armbruster Error *err = NULL; 22140e558843SAnthony Liguori 22154715d42eSMarkus Armbruster value = prop->get(obj, &err); 22164715d42eSMarkus Armbruster if (err) { 22174715d42eSMarkus Armbruster error_propagate(errp, err); 22184715d42eSMarkus Armbruster return; 22194715d42eSMarkus Armbruster } 22204715d42eSMarkus Armbruster 222151e72bc1SEric Blake visit_type_bool(v, name, &value, errp); 22220e558843SAnthony Liguori } 22230e558843SAnthony Liguori 2224d7bce999SEric Blake static void property_set_bool(Object *obj, Visitor *v, const char *name, 2225d7bce999SEric Blake void *opaque, Error **errp) 22260e558843SAnthony Liguori { 22270e558843SAnthony Liguori BoolProperty *prop = opaque; 22280e558843SAnthony Liguori bool value; 22290e558843SAnthony Liguori Error *local_err = NULL; 22300e558843SAnthony Liguori 223151e72bc1SEric Blake visit_type_bool(v, name, &value, &local_err); 22320e558843SAnthony Liguori if (local_err) { 22330e558843SAnthony Liguori error_propagate(errp, local_err); 22340e558843SAnthony Liguori return; 22350e558843SAnthony Liguori } 22360e558843SAnthony Liguori 22370e558843SAnthony Liguori prop->set(obj, value, errp); 22380e558843SAnthony Liguori } 22390e558843SAnthony Liguori 22400e558843SAnthony Liguori static void property_release_bool(Object *obj, const char *name, 22410e558843SAnthony Liguori void *opaque) 22420e558843SAnthony Liguori { 22430e558843SAnthony Liguori BoolProperty *prop = opaque; 22440e558843SAnthony Liguori g_free(prop); 22450e558843SAnthony Liguori } 22460e558843SAnthony Liguori 22470e558843SAnthony Liguori void object_property_add_bool(Object *obj, const char *name, 22480e558843SAnthony Liguori bool (*get)(Object *, Error **), 22490e558843SAnthony Liguori void (*set)(Object *, bool, Error **), 22500e558843SAnthony Liguori Error **errp) 22510e558843SAnthony Liguori { 2252a01aedc8SStefan Hajnoczi Error *local_err = NULL; 22530e558843SAnthony Liguori BoolProperty *prop = g_malloc0(sizeof(*prop)); 22540e558843SAnthony Liguori 22550e558843SAnthony Liguori prop->get = get; 22560e558843SAnthony Liguori prop->set = set; 22570e558843SAnthony Liguori 22580e558843SAnthony Liguori object_property_add(obj, name, "bool", 22590e558843SAnthony Liguori get ? property_get_bool : NULL, 22600e558843SAnthony Liguori set ? property_set_bool : NULL, 22610e558843SAnthony Liguori property_release_bool, 2262a01aedc8SStefan Hajnoczi prop, &local_err); 2263a01aedc8SStefan Hajnoczi if (local_err) { 2264a01aedc8SStefan Hajnoczi error_propagate(errp, local_err); 2265a01aedc8SStefan Hajnoczi g_free(prop); 2266a01aedc8SStefan Hajnoczi } 22670e558843SAnthony Liguori } 22680e558843SAnthony Liguori 2269a3a16211SMarc-André Lureau ObjectProperty * 2270a3a16211SMarc-André Lureau object_class_property_add_bool(ObjectClass *klass, const char *name, 227116bf7f52SDaniel P. Berrange bool (*get)(Object *, Error **), 227216bf7f52SDaniel P. Berrange void (*set)(Object *, bool, Error **), 227316bf7f52SDaniel P. Berrange Error **errp) 227416bf7f52SDaniel P. Berrange { 227516bf7f52SDaniel P. Berrange Error *local_err = NULL; 227616bf7f52SDaniel P. Berrange BoolProperty *prop = g_malloc0(sizeof(*prop)); 2277a3a16211SMarc-André Lureau ObjectProperty *rv; 227816bf7f52SDaniel P. Berrange 227916bf7f52SDaniel P. Berrange prop->get = get; 228016bf7f52SDaniel P. Berrange prop->set = set; 228116bf7f52SDaniel P. Berrange 2282a3a16211SMarc-André Lureau rv = object_class_property_add(klass, name, "bool", 228316bf7f52SDaniel P. Berrange get ? property_get_bool : NULL, 228416bf7f52SDaniel P. Berrange set ? property_set_bool : NULL, 2285fc4fe712SMarc-André Lureau NULL, 228616bf7f52SDaniel P. Berrange prop, &local_err); 228716bf7f52SDaniel P. Berrange if (local_err) { 228816bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 228916bf7f52SDaniel P. Berrange g_free(prop); 229016bf7f52SDaniel P. Berrange } 2291a3a16211SMarc-André Lureau 2292a3a16211SMarc-André Lureau return rv; 229316bf7f52SDaniel P. Berrange } 229416bf7f52SDaniel P. Berrange 2295d7bce999SEric Blake static void property_get_enum(Object *obj, Visitor *v, const char *name, 2296d7bce999SEric Blake void *opaque, Error **errp) 2297a8e3fbedSDaniel P. Berrange { 2298a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 2299a8e3fbedSDaniel P. Berrange int value; 23004715d42eSMarkus Armbruster Error *err = NULL; 2301a8e3fbedSDaniel P. Berrange 23024715d42eSMarkus Armbruster value = prop->get(obj, &err); 23034715d42eSMarkus Armbruster if (err) { 23044715d42eSMarkus Armbruster error_propagate(errp, err); 23054715d42eSMarkus Armbruster return; 23064715d42eSMarkus Armbruster } 23074715d42eSMarkus Armbruster 2308f7abe0ecSMarc-André Lureau visit_type_enum(v, name, &value, prop->lookup, errp); 2309a8e3fbedSDaniel P. Berrange } 2310a8e3fbedSDaniel P. Berrange 2311d7bce999SEric Blake static void property_set_enum(Object *obj, Visitor *v, const char *name, 2312d7bce999SEric Blake void *opaque, Error **errp) 2313a8e3fbedSDaniel P. Berrange { 2314a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 2315a8e3fbedSDaniel P. Berrange int value; 23164715d42eSMarkus Armbruster Error *err = NULL; 2317a8e3fbedSDaniel P. Berrange 2318f7abe0ecSMarc-André Lureau visit_type_enum(v, name, &value, prop->lookup, &err); 23194715d42eSMarkus Armbruster if (err) { 23204715d42eSMarkus Armbruster error_propagate(errp, err); 23214715d42eSMarkus Armbruster return; 23224715d42eSMarkus Armbruster } 2323a8e3fbedSDaniel P. Berrange prop->set(obj, value, errp); 2324a8e3fbedSDaniel P. Berrange } 2325a8e3fbedSDaniel P. Berrange 2326a8e3fbedSDaniel P. Berrange static void property_release_enum(Object *obj, const char *name, 2327a8e3fbedSDaniel P. Berrange void *opaque) 2328a8e3fbedSDaniel P. Berrange { 2329a8e3fbedSDaniel P. Berrange EnumProperty *prop = opaque; 2330a8e3fbedSDaniel P. Berrange g_free(prop); 2331a8e3fbedSDaniel P. Berrange } 2332a8e3fbedSDaniel P. Berrange 2333a8e3fbedSDaniel P. Berrange void object_property_add_enum(Object *obj, const char *name, 2334a8e3fbedSDaniel P. Berrange const char *typename, 2335f7abe0ecSMarc-André Lureau const QEnumLookup *lookup, 2336a8e3fbedSDaniel P. Berrange int (*get)(Object *, Error **), 2337a8e3fbedSDaniel P. Berrange void (*set)(Object *, int, Error **), 2338a8e3fbedSDaniel P. Berrange Error **errp) 2339a8e3fbedSDaniel P. Berrange { 2340a8e3fbedSDaniel P. Berrange Error *local_err = NULL; 2341a8e3fbedSDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 2342a8e3fbedSDaniel P. Berrange 2343f7abe0ecSMarc-André Lureau prop->lookup = lookup; 2344a8e3fbedSDaniel P. Berrange prop->get = get; 2345a8e3fbedSDaniel P. Berrange prop->set = set; 2346a8e3fbedSDaniel P. Berrange 2347a8e3fbedSDaniel P. Berrange object_property_add(obj, name, typename, 2348a8e3fbedSDaniel P. Berrange get ? property_get_enum : NULL, 2349a8e3fbedSDaniel P. Berrange set ? property_set_enum : NULL, 2350a8e3fbedSDaniel P. Berrange property_release_enum, 2351a8e3fbedSDaniel P. Berrange prop, &local_err); 2352a8e3fbedSDaniel P. Berrange if (local_err) { 2353a8e3fbedSDaniel P. Berrange error_propagate(errp, local_err); 2354a8e3fbedSDaniel P. Berrange g_free(prop); 2355a8e3fbedSDaniel P. Berrange } 2356a8e3fbedSDaniel P. Berrange } 2357a8e3fbedSDaniel P. Berrange 2358a3a16211SMarc-André Lureau ObjectProperty * 2359a3a16211SMarc-André Lureau object_class_property_add_enum(ObjectClass *klass, const char *name, 236016bf7f52SDaniel P. Berrange const char *typename, 2361f7abe0ecSMarc-André Lureau const QEnumLookup *lookup, 236216bf7f52SDaniel P. Berrange int (*get)(Object *, Error **), 236316bf7f52SDaniel P. Berrange void (*set)(Object *, int, Error **), 236416bf7f52SDaniel P. Berrange Error **errp) 236516bf7f52SDaniel P. Berrange { 236616bf7f52SDaniel P. Berrange Error *local_err = NULL; 236716bf7f52SDaniel P. Berrange EnumProperty *prop = g_malloc(sizeof(*prop)); 2368a3a16211SMarc-André Lureau ObjectProperty *rv; 236916bf7f52SDaniel P. Berrange 2370f7abe0ecSMarc-André Lureau prop->lookup = lookup; 237116bf7f52SDaniel P. Berrange prop->get = get; 237216bf7f52SDaniel P. Berrange prop->set = set; 237316bf7f52SDaniel P. Berrange 2374a3a16211SMarc-André Lureau rv = object_class_property_add(klass, name, typename, 237516bf7f52SDaniel P. Berrange get ? property_get_enum : NULL, 237616bf7f52SDaniel P. Berrange set ? property_set_enum : NULL, 2377fc4fe712SMarc-André Lureau NULL, 237816bf7f52SDaniel P. Berrange prop, &local_err); 237916bf7f52SDaniel P. Berrange if (local_err) { 238016bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 238116bf7f52SDaniel P. Berrange g_free(prop); 238216bf7f52SDaniel P. Berrange } 2383a3a16211SMarc-André Lureau 2384a3a16211SMarc-André Lureau return rv; 238516bf7f52SDaniel P. Berrange } 238616bf7f52SDaniel P. Berrange 23878e099d14SDavid Gibson typedef struct TMProperty { 23888e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **); 23898e099d14SDavid Gibson } TMProperty; 23908e099d14SDavid Gibson 2391d7bce999SEric Blake static void property_get_tm(Object *obj, Visitor *v, const char *name, 2392d7bce999SEric Blake void *opaque, Error **errp) 23938e099d14SDavid Gibson { 23948e099d14SDavid Gibson TMProperty *prop = opaque; 23958e099d14SDavid Gibson Error *err = NULL; 23968e099d14SDavid Gibson struct tm value; 23978e099d14SDavid Gibson 23988e099d14SDavid Gibson prop->get(obj, &value, &err); 23998e099d14SDavid Gibson if (err) { 24008e099d14SDavid Gibson goto out; 24018e099d14SDavid Gibson } 24028e099d14SDavid Gibson 2403337283dfSEric Blake visit_start_struct(v, name, NULL, 0, &err); 24048e099d14SDavid Gibson if (err) { 24058e099d14SDavid Gibson goto out; 24068e099d14SDavid Gibson } 240751e72bc1SEric Blake visit_type_int32(v, "tm_year", &value.tm_year, &err); 24088e099d14SDavid Gibson if (err) { 24098e099d14SDavid Gibson goto out_end; 24108e099d14SDavid Gibson } 241151e72bc1SEric Blake visit_type_int32(v, "tm_mon", &value.tm_mon, &err); 24128e099d14SDavid Gibson if (err) { 24138e099d14SDavid Gibson goto out_end; 24148e099d14SDavid Gibson } 241551e72bc1SEric Blake visit_type_int32(v, "tm_mday", &value.tm_mday, &err); 24168e099d14SDavid Gibson if (err) { 24178e099d14SDavid Gibson goto out_end; 24188e099d14SDavid Gibson } 241951e72bc1SEric Blake visit_type_int32(v, "tm_hour", &value.tm_hour, &err); 24208e099d14SDavid Gibson if (err) { 24218e099d14SDavid Gibson goto out_end; 24228e099d14SDavid Gibson } 242351e72bc1SEric Blake visit_type_int32(v, "tm_min", &value.tm_min, &err); 24248e099d14SDavid Gibson if (err) { 24258e099d14SDavid Gibson goto out_end; 24268e099d14SDavid Gibson } 242751e72bc1SEric Blake visit_type_int32(v, "tm_sec", &value.tm_sec, &err); 24288e099d14SDavid Gibson if (err) { 24298e099d14SDavid Gibson goto out_end; 24308e099d14SDavid Gibson } 243115c2f669SEric Blake visit_check_struct(v, &err); 24328e099d14SDavid Gibson out_end: 24331158bb2aSEric Blake visit_end_struct(v, NULL); 24348e099d14SDavid Gibson out: 24358e099d14SDavid Gibson error_propagate(errp, err); 24368e099d14SDavid Gibson 24378e099d14SDavid Gibson } 24388e099d14SDavid Gibson 24398e099d14SDavid Gibson static void property_release_tm(Object *obj, const char *name, 24408e099d14SDavid Gibson void *opaque) 24418e099d14SDavid Gibson { 24428e099d14SDavid Gibson TMProperty *prop = opaque; 24438e099d14SDavid Gibson g_free(prop); 24448e099d14SDavid Gibson } 24458e099d14SDavid Gibson 24468e099d14SDavid Gibson void object_property_add_tm(Object *obj, const char *name, 24478e099d14SDavid Gibson void (*get)(Object *, struct tm *, Error **), 24488e099d14SDavid Gibson Error **errp) 24498e099d14SDavid Gibson { 24508e099d14SDavid Gibson Error *local_err = NULL; 24518e099d14SDavid Gibson TMProperty *prop = g_malloc0(sizeof(*prop)); 24528e099d14SDavid Gibson 24538e099d14SDavid Gibson prop->get = get; 24548e099d14SDavid Gibson 24558e099d14SDavid Gibson object_property_add(obj, name, "struct tm", 24568e099d14SDavid Gibson get ? property_get_tm : NULL, NULL, 24578e099d14SDavid Gibson property_release_tm, 24588e099d14SDavid Gibson prop, &local_err); 24598e099d14SDavid Gibson if (local_err) { 24608e099d14SDavid Gibson error_propagate(errp, local_err); 24618e099d14SDavid Gibson g_free(prop); 24628e099d14SDavid Gibson } 24638e099d14SDavid Gibson } 24648e099d14SDavid Gibson 2465a3a16211SMarc-André Lureau ObjectProperty * 2466a3a16211SMarc-André Lureau object_class_property_add_tm(ObjectClass *klass, const char *name, 246716bf7f52SDaniel P. Berrange void (*get)(Object *, struct tm *, Error **), 246816bf7f52SDaniel P. Berrange Error **errp) 246916bf7f52SDaniel P. Berrange { 247016bf7f52SDaniel P. Berrange Error *local_err = NULL; 247116bf7f52SDaniel P. Berrange TMProperty *prop = g_malloc0(sizeof(*prop)); 2472a3a16211SMarc-André Lureau ObjectProperty *rv; 247316bf7f52SDaniel P. Berrange 247416bf7f52SDaniel P. Berrange prop->get = get; 247516bf7f52SDaniel P. Berrange 2476a3a16211SMarc-André Lureau rv = object_class_property_add(klass, name, "struct tm", 247716bf7f52SDaniel P. Berrange get ? property_get_tm : NULL, NULL, 2478fc4fe712SMarc-André Lureau NULL, 247916bf7f52SDaniel P. Berrange prop, &local_err); 248016bf7f52SDaniel P. Berrange if (local_err) { 248116bf7f52SDaniel P. Berrange error_propagate(errp, local_err); 248216bf7f52SDaniel P. Berrange g_free(prop); 248316bf7f52SDaniel P. Berrange } 2484a3a16211SMarc-André Lureau 2485a3a16211SMarc-André Lureau return rv; 248616bf7f52SDaniel P. Berrange } 248716bf7f52SDaniel P. Berrange 24882f262e06SPaolo Bonzini static char *qdev_get_type(Object *obj, Error **errp) 24892f262e06SPaolo Bonzini { 24902f262e06SPaolo Bonzini return g_strdup(object_get_typename(obj)); 24912f262e06SPaolo Bonzini } 24922f262e06SPaolo Bonzini 2493d7bce999SEric Blake static void property_get_uint8_ptr(Object *obj, Visitor *v, const char *name, 2494d7bce999SEric Blake void *opaque, Error **errp) 2495e732ea63SMichael S. Tsirkin { 2496e732ea63SMichael S. Tsirkin uint8_t value = *(uint8_t *)opaque; 249751e72bc1SEric Blake visit_type_uint8(v, name, &value, errp); 2498e732ea63SMichael S. Tsirkin } 2499e732ea63SMichael S. Tsirkin 2500d7bce999SEric Blake static void property_get_uint16_ptr(Object *obj, Visitor *v, const char *name, 2501d7bce999SEric Blake void *opaque, Error **errp) 2502e732ea63SMichael S. Tsirkin { 2503e732ea63SMichael S. Tsirkin uint16_t value = *(uint16_t *)opaque; 250451e72bc1SEric Blake visit_type_uint16(v, name, &value, errp); 2505e732ea63SMichael S. Tsirkin } 2506e732ea63SMichael S. Tsirkin 2507d7bce999SEric Blake static void property_get_uint32_ptr(Object *obj, Visitor *v, const char *name, 2508d7bce999SEric Blake void *opaque, Error **errp) 2509e732ea63SMichael S. Tsirkin { 2510e732ea63SMichael S. Tsirkin uint32_t value = *(uint32_t *)opaque; 251151e72bc1SEric Blake visit_type_uint32(v, name, &value, errp); 2512e732ea63SMichael S. Tsirkin } 2513e732ea63SMichael S. Tsirkin 2514d7bce999SEric Blake static void property_get_uint64_ptr(Object *obj, Visitor *v, const char *name, 2515d7bce999SEric Blake void *opaque, Error **errp) 2516e732ea63SMichael S. Tsirkin { 2517e732ea63SMichael S. Tsirkin uint64_t value = *(uint64_t *)opaque; 251851e72bc1SEric Blake visit_type_uint64(v, name, &value, errp); 2519e732ea63SMichael S. Tsirkin } 2520e732ea63SMichael S. Tsirkin 2521e732ea63SMichael S. Tsirkin void object_property_add_uint8_ptr(Object *obj, const char *name, 2522e732ea63SMichael S. Tsirkin const uint8_t *v, Error **errp) 2523e732ea63SMichael S. Tsirkin { 2524e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint8", property_get_uint8_ptr, 2525e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2526e732ea63SMichael S. Tsirkin } 2527e732ea63SMichael S. Tsirkin 2528a3a16211SMarc-André Lureau ObjectProperty * 2529a3a16211SMarc-André Lureau object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, 253016bf7f52SDaniel P. Berrange const uint8_t *v, Error **errp) 253116bf7f52SDaniel P. Berrange { 2532a3a16211SMarc-André Lureau return object_class_property_add(klass, name, "uint8", 2533a3a16211SMarc-André Lureau property_get_uint8_ptr, 253416bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 253516bf7f52SDaniel P. Berrange } 253616bf7f52SDaniel P. Berrange 2537e732ea63SMichael S. Tsirkin void object_property_add_uint16_ptr(Object *obj, const char *name, 2538e732ea63SMichael S. Tsirkin const uint16_t *v, Error **errp) 2539e732ea63SMichael S. Tsirkin { 2540e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint16", property_get_uint16_ptr, 2541e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2542e732ea63SMichael S. Tsirkin } 2543e732ea63SMichael S. Tsirkin 2544a3a16211SMarc-André Lureau ObjectProperty * 2545a3a16211SMarc-André Lureau object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, 254616bf7f52SDaniel P. Berrange const uint16_t *v, Error **errp) 254716bf7f52SDaniel P. Berrange { 2548a3a16211SMarc-André Lureau return object_class_property_add(klass, name, "uint16", 2549a3a16211SMarc-André Lureau property_get_uint16_ptr, 255016bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 255116bf7f52SDaniel P. Berrange } 255216bf7f52SDaniel P. Berrange 2553e732ea63SMichael S. Tsirkin void object_property_add_uint32_ptr(Object *obj, const char *name, 2554e732ea63SMichael S. Tsirkin const uint32_t *v, Error **errp) 2555e732ea63SMichael S. Tsirkin { 2556e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint32", property_get_uint32_ptr, 2557e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2558e732ea63SMichael S. Tsirkin } 2559e732ea63SMichael S. Tsirkin 2560a3a16211SMarc-André Lureau ObjectProperty * 2561a3a16211SMarc-André Lureau object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, 256216bf7f52SDaniel P. Berrange const uint32_t *v, Error **errp) 256316bf7f52SDaniel P. Berrange { 2564a3a16211SMarc-André Lureau return object_class_property_add(klass, name, "uint32", 2565a3a16211SMarc-André Lureau property_get_uint32_ptr, 256616bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 256716bf7f52SDaniel P. Berrange } 256816bf7f52SDaniel P. Berrange 2569e732ea63SMichael S. Tsirkin void object_property_add_uint64_ptr(Object *obj, const char *name, 2570e732ea63SMichael S. Tsirkin const uint64_t *v, Error **errp) 2571e732ea63SMichael S. Tsirkin { 2572e732ea63SMichael S. Tsirkin object_property_add(obj, name, "uint64", property_get_uint64_ptr, 2573e732ea63SMichael S. Tsirkin NULL, NULL, (void *)v, errp); 2574e732ea63SMichael S. Tsirkin } 2575e732ea63SMichael S. Tsirkin 2576a3a16211SMarc-André Lureau ObjectProperty * 2577a3a16211SMarc-André Lureau object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, 257816bf7f52SDaniel P. Berrange const uint64_t *v, Error **errp) 257916bf7f52SDaniel P. Berrange { 2580a3a16211SMarc-André Lureau return object_class_property_add(klass, name, "uint64", 2581a3a16211SMarc-André Lureau property_get_uint64_ptr, 258216bf7f52SDaniel P. Berrange NULL, NULL, (void *)v, errp); 258316bf7f52SDaniel P. Berrange } 258416bf7f52SDaniel P. Berrange 2585ef7c7ff6SStefan Hajnoczi typedef struct { 2586ef7c7ff6SStefan Hajnoczi Object *target_obj; 25871590d266SEduardo Habkost char *target_name; 2588ef7c7ff6SStefan Hajnoczi } AliasProperty; 2589ef7c7ff6SStefan Hajnoczi 2590d7bce999SEric Blake static void property_get_alias(Object *obj, Visitor *v, const char *name, 2591d7bce999SEric Blake void *opaque, Error **errp) 2592ef7c7ff6SStefan Hajnoczi { 2593ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2594ef7c7ff6SStefan Hajnoczi 2595ef7c7ff6SStefan Hajnoczi object_property_get(prop->target_obj, v, prop->target_name, errp); 2596ef7c7ff6SStefan Hajnoczi } 2597ef7c7ff6SStefan Hajnoczi 2598d7bce999SEric Blake static void property_set_alias(Object *obj, Visitor *v, const char *name, 2599d7bce999SEric Blake void *opaque, Error **errp) 2600ef7c7ff6SStefan Hajnoczi { 2601ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2602ef7c7ff6SStefan Hajnoczi 2603ef7c7ff6SStefan Hajnoczi object_property_set(prop->target_obj, v, prop->target_name, errp); 2604ef7c7ff6SStefan Hajnoczi } 2605ef7c7ff6SStefan Hajnoczi 260664607d08SPaolo Bonzini static Object *property_resolve_alias(Object *obj, void *opaque, 260764607d08SPaolo Bonzini const gchar *part) 260864607d08SPaolo Bonzini { 260964607d08SPaolo Bonzini AliasProperty *prop = opaque; 261064607d08SPaolo Bonzini 261164607d08SPaolo Bonzini return object_resolve_path_component(prop->target_obj, prop->target_name); 261264607d08SPaolo Bonzini } 261364607d08SPaolo Bonzini 2614ef7c7ff6SStefan Hajnoczi static void property_release_alias(Object *obj, const char *name, void *opaque) 2615ef7c7ff6SStefan Hajnoczi { 2616ef7c7ff6SStefan Hajnoczi AliasProperty *prop = opaque; 2617ef7c7ff6SStefan Hajnoczi 26181590d266SEduardo Habkost g_free(prop->target_name); 2619ef7c7ff6SStefan Hajnoczi g_free(prop); 2620ef7c7ff6SStefan Hajnoczi } 2621ef7c7ff6SStefan Hajnoczi 2622ef7c7ff6SStefan Hajnoczi void object_property_add_alias(Object *obj, const char *name, 2623ef7c7ff6SStefan Hajnoczi Object *target_obj, const char *target_name, 2624ef7c7ff6SStefan Hajnoczi Error **errp) 2625ef7c7ff6SStefan Hajnoczi { 2626ef7c7ff6SStefan Hajnoczi AliasProperty *prop; 262764607d08SPaolo Bonzini ObjectProperty *op; 2628ef7c7ff6SStefan Hajnoczi ObjectProperty *target_prop; 2629d190698eSPaolo Bonzini gchar *prop_type; 26308ae9a9efSGonglei Error *local_err = NULL; 2631ef7c7ff6SStefan Hajnoczi 2632ef7c7ff6SStefan Hajnoczi target_prop = object_property_find(target_obj, target_name, errp); 2633ef7c7ff6SStefan Hajnoczi if (!target_prop) { 2634ef7c7ff6SStefan Hajnoczi return; 2635ef7c7ff6SStefan Hajnoczi } 2636ef7c7ff6SStefan Hajnoczi 2637d190698eSPaolo Bonzini if (object_property_is_child(target_prop)) { 2638d190698eSPaolo Bonzini prop_type = g_strdup_printf("link%s", 2639d190698eSPaolo Bonzini target_prop->type + strlen("child")); 2640d190698eSPaolo Bonzini } else { 2641d190698eSPaolo Bonzini prop_type = g_strdup(target_prop->type); 2642d190698eSPaolo Bonzini } 2643d190698eSPaolo Bonzini 2644ef7c7ff6SStefan Hajnoczi prop = g_malloc(sizeof(*prop)); 2645ef7c7ff6SStefan Hajnoczi prop->target_obj = target_obj; 26461590d266SEduardo Habkost prop->target_name = g_strdup(target_name); 2647ef7c7ff6SStefan Hajnoczi 2648d190698eSPaolo Bonzini op = object_property_add(obj, name, prop_type, 2649ef7c7ff6SStefan Hajnoczi property_get_alias, 2650ef7c7ff6SStefan Hajnoczi property_set_alias, 2651ef7c7ff6SStefan Hajnoczi property_release_alias, 26528ae9a9efSGonglei prop, &local_err); 26538ae9a9efSGonglei if (local_err) { 26548ae9a9efSGonglei error_propagate(errp, local_err); 26558ae9a9efSGonglei g_free(prop); 26568ae9a9efSGonglei goto out; 26578ae9a9efSGonglei } 265864607d08SPaolo Bonzini op->resolve = property_resolve_alias; 26590e76ed0aSMarc-André Lureau if (target_prop->defval) { 26600e76ed0aSMarc-André Lureau op->defval = qobject_ref(target_prop->defval); 26610e76ed0aSMarc-André Lureau } 2662d190698eSPaolo Bonzini 2663a18bb417SAndreas Färber object_property_set_description(obj, op->name, 266480742642SGonglei target_prop->description, 266580742642SGonglei &error_abort); 266680742642SGonglei 26678ae9a9efSGonglei out: 2668d190698eSPaolo Bonzini g_free(prop_type); 2669ef7c7ff6SStefan Hajnoczi } 2670ef7c7ff6SStefan Hajnoczi 267180742642SGonglei void object_property_set_description(Object *obj, const char *name, 267280742642SGonglei const char *description, Error **errp) 267380742642SGonglei { 267480742642SGonglei ObjectProperty *op; 267580742642SGonglei 267680742642SGonglei op = object_property_find(obj, name, errp); 267780742642SGonglei if (!op) { 267880742642SGonglei return; 267980742642SGonglei } 268080742642SGonglei 268180742642SGonglei g_free(op->description); 268280742642SGonglei op->description = g_strdup(description); 268380742642SGonglei } 268480742642SGonglei 268516bf7f52SDaniel P. Berrange void object_class_property_set_description(ObjectClass *klass, 268616bf7f52SDaniel P. Berrange const char *name, 268716bf7f52SDaniel P. Berrange const char *description, 268816bf7f52SDaniel P. Berrange Error **errp) 268916bf7f52SDaniel P. Berrange { 269016bf7f52SDaniel P. Berrange ObjectProperty *op; 269116bf7f52SDaniel P. Berrange 269216bf7f52SDaniel P. Berrange op = g_hash_table_lookup(klass->properties, name); 269316bf7f52SDaniel P. Berrange if (!op) { 269416bf7f52SDaniel P. Berrange error_setg(errp, "Property '.%s' not found", name); 269516bf7f52SDaniel P. Berrange return; 269616bf7f52SDaniel P. Berrange } 269716bf7f52SDaniel P. Berrange 269816bf7f52SDaniel P. Berrange g_free(op->description); 269916bf7f52SDaniel P. Berrange op->description = g_strdup(description); 270016bf7f52SDaniel P. Berrange } 270116bf7f52SDaniel P. Berrange 27027439a036SMarc-André Lureau static void object_class_init(ObjectClass *klass, void *data) 27032f262e06SPaolo Bonzini { 27047439a036SMarc-André Lureau object_class_property_add_str(klass, "type", qdev_get_type, 27057439a036SMarc-André Lureau NULL, &error_abort); 27062f262e06SPaolo Bonzini } 27072f262e06SPaolo Bonzini 2708745549c8SPaolo Bonzini static void register_types(void) 2709745549c8SPaolo Bonzini { 2710745549c8SPaolo Bonzini static TypeInfo interface_info = { 2711745549c8SPaolo Bonzini .name = TYPE_INTERFACE, 271233e95c63SAnthony Liguori .class_size = sizeof(InterfaceClass), 2713745549c8SPaolo Bonzini .abstract = true, 2714745549c8SPaolo Bonzini }; 2715745549c8SPaolo Bonzini 2716745549c8SPaolo Bonzini static TypeInfo object_info = { 2717745549c8SPaolo Bonzini .name = TYPE_OBJECT, 2718745549c8SPaolo Bonzini .instance_size = sizeof(Object), 27197439a036SMarc-André Lureau .class_init = object_class_init, 2720745549c8SPaolo Bonzini .abstract = true, 2721745549c8SPaolo Bonzini }; 2722745549c8SPaolo Bonzini 2723049cb3cfSPaolo Bonzini type_interface = type_register_internal(&interface_info); 2724049cb3cfSPaolo Bonzini type_register_internal(&object_info); 2725745549c8SPaolo Bonzini } 2726745549c8SPaolo Bonzini 2727745549c8SPaolo Bonzini type_init(register_types) 2728