xref: /qemu/qom/object.c (revision 7b7b7d18)
1 /*
2  * QEMU Object Model
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  */
12 
13 #include "qemu/object.h"
14 #include "qemu-common.h"
15 #include "qapi/qapi-visit-core.h"
16 
17 /* TODO: replace QObject with a simpler visitor to avoid a dependency
18  * of the QOM core on QObject?  */
19 #include "qemu/qom-qobject.h"
20 #include "qobject.h"
21 #include "qbool.h"
22 #include "qint.h"
23 #include "qstring.h"
24 
25 #define MAX_INTERFACES 32
26 
27 typedef struct InterfaceImpl InterfaceImpl;
28 typedef struct TypeImpl TypeImpl;
29 
30 struct InterfaceImpl
31 {
32     const char *parent;
33     void (*interface_initfn)(ObjectClass *class, void *data);
34     TypeImpl *type;
35 };
36 
37 struct TypeImpl
38 {
39     const char *name;
40 
41     size_t class_size;
42 
43     size_t instance_size;
44 
45     void (*class_init)(ObjectClass *klass, void *data);
46     void (*class_finalize)(ObjectClass *klass, void *data);
47 
48     void *class_data;
49 
50     void (*instance_init)(Object *obj);
51     void (*instance_finalize)(Object *obj);
52 
53     bool abstract;
54 
55     const char *parent;
56     TypeImpl *parent_type;
57 
58     ObjectClass *class;
59 
60     int num_interfaces;
61     InterfaceImpl interfaces[MAX_INTERFACES];
62 };
63 
64 typedef struct Interface
65 {
66     Object parent;
67     Object *obj;
68 } Interface;
69 
70 #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
71 
72 static Type type_interface;
73 
74 static GHashTable *type_table_get(void)
75 {
76     static GHashTable *type_table;
77 
78     if (type_table == NULL) {
79         type_table = g_hash_table_new(g_str_hash, g_str_equal);
80     }
81 
82     return type_table;
83 }
84 
85 static void type_table_add(TypeImpl *ti)
86 {
87     g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
88 }
89 
90 static TypeImpl *type_table_lookup(const char *name)
91 {
92     return g_hash_table_lookup(type_table_get(), name);
93 }
94 
95 TypeImpl *type_register(const TypeInfo *info)
96 {
97     TypeImpl *ti = g_malloc0(sizeof(*ti));
98 
99     g_assert(info->name != NULL);
100 
101     if (type_table_lookup(info->name) != NULL) {
102         fprintf(stderr, "Registering `%s' which already exists\n", info->name);
103         abort();
104     }
105 
106     ti->name = g_strdup(info->name);
107     ti->parent = g_strdup(info->parent);
108 
109     ti->class_size = info->class_size;
110     ti->instance_size = info->instance_size;
111 
112     ti->class_init = info->class_init;
113     ti->class_finalize = info->class_finalize;
114     ti->class_data = info->class_data;
115 
116     ti->instance_init = info->instance_init;
117     ti->instance_finalize = info->instance_finalize;
118 
119     ti->abstract = info->abstract;
120 
121     if (info->interfaces) {
122         int i;
123 
124         for (i = 0; info->interfaces[i].type; i++) {
125             ti->interfaces[i].parent = info->interfaces[i].type;
126             ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
127             ti->num_interfaces++;
128         }
129     }
130 
131     type_table_add(ti);
132 
133     return ti;
134 }
135 
136 TypeImpl *type_register_static(const TypeInfo *info)
137 {
138     return type_register(info);
139 }
140 
141 static TypeImpl *type_get_by_name(const char *name)
142 {
143     if (name == NULL) {
144         return NULL;
145     }
146 
147     return type_table_lookup(name);
148 }
149 
150 static TypeImpl *type_get_parent(TypeImpl *type)
151 {
152     if (!type->parent_type && type->parent) {
153         type->parent_type = type_get_by_name(type->parent);
154         g_assert(type->parent_type != NULL);
155     }
156 
157     return type->parent_type;
158 }
159 
160 static bool type_has_parent(TypeImpl *type)
161 {
162     return (type->parent != NULL);
163 }
164 
165 static size_t type_class_get_size(TypeImpl *ti)
166 {
167     if (ti->class_size) {
168         return ti->class_size;
169     }
170 
171     if (type_has_parent(ti)) {
172         return type_class_get_size(type_get_parent(ti));
173     }
174 
175     return sizeof(ObjectClass);
176 }
177 
178 static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
179 {
180     TypeInfo info = {
181         .instance_size = sizeof(Interface),
182         .parent = iface->parent,
183         .class_size = sizeof(InterfaceClass),
184         .class_init = iface->interface_initfn,
185         .abstract = true,
186     };
187     char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
188 
189     info.name = name;
190     iface->type = type_register(&info);
191     g_free(name);
192 }
193 
194 static void type_class_init(TypeImpl *ti)
195 {
196     size_t class_size = sizeof(ObjectClass);
197     int i;
198 
199     if (ti->class) {
200         return;
201     }
202 
203     ti->class_size = type_class_get_size(ti);
204 
205     ti->class = g_malloc0(ti->class_size);
206     ti->class->type = ti;
207 
208     if (type_has_parent(ti)) {
209         TypeImpl *parent = type_get_parent(ti);
210 
211         type_class_init(parent);
212 
213         class_size = parent->class_size;
214         g_assert(parent->class_size <= ti->class_size);
215 
216         memcpy((void *)ti->class + sizeof(ObjectClass),
217                (void *)parent->class + sizeof(ObjectClass),
218                parent->class_size - sizeof(ObjectClass));
219     }
220 
221     memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
222 
223     for (i = 0; i < ti->num_interfaces; i++) {
224         type_class_interface_init(ti, &ti->interfaces[i]);
225     }
226 
227     if (ti->class_init) {
228         ti->class_init(ti->class, ti->class_data);
229     }
230 }
231 
232 static void object_interface_init(Object *obj, InterfaceImpl *iface)
233 {
234     TypeImpl *ti = iface->type;
235     Interface *iface_obj;
236 
237     iface_obj = INTERFACE(object_new(ti->name));
238     iface_obj->obj = obj;
239 
240     obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
241 }
242 
243 static void object_init_with_type(Object *obj, TypeImpl *ti)
244 {
245     int i;
246 
247     if (type_has_parent(ti)) {
248         object_init_with_type(obj, type_get_parent(ti));
249     }
250 
251     for (i = 0; i < ti->num_interfaces; i++) {
252         object_interface_init(obj, &ti->interfaces[i]);
253     }
254 
255     if (ti->instance_init) {
256         ti->instance_init(obj);
257     }
258 }
259 
260 void object_initialize_with_type(void *data, TypeImpl *type)
261 {
262     Object *obj = data;
263 
264     g_assert(type != NULL);
265     g_assert(type->instance_size >= sizeof(ObjectClass));
266 
267     type_class_init(type);
268     g_assert(type->abstract == false);
269 
270     memset(obj, 0, type->instance_size);
271     obj->class = type->class;
272     QTAILQ_INIT(&obj->properties);
273     object_init_with_type(obj, type);
274 }
275 
276 void object_initialize(void *data, const char *typename)
277 {
278     TypeImpl *type = type_get_by_name(typename);
279 
280     object_initialize_with_type(data, type);
281 }
282 
283 static void object_property_del_all(Object *obj)
284 {
285     while (!QTAILQ_EMPTY(&obj->properties)) {
286         ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
287 
288         QTAILQ_REMOVE(&obj->properties, prop, node);
289 
290         if (prop->release) {
291             prop->release(obj, prop->name, prop->opaque);
292         }
293 
294         g_free(prop->name);
295         g_free(prop->type);
296         g_free(prop);
297     }
298 }
299 
300 static void object_property_del_child(Object *obj, Object *child, Error **errp)
301 {
302     ObjectProperty *prop;
303 
304     QTAILQ_FOREACH(prop, &obj->properties, node) {
305         if (!strstart(prop->type, "child<", NULL)) {
306             continue;
307         }
308 
309         if (prop->opaque == child) {
310             object_property_del(obj, prop->name, errp);
311         }
312     }
313 }
314 
315 void object_unparent(Object *obj)
316 {
317     if (obj->parent) {
318         object_property_del_child(obj->parent, obj, NULL);
319     }
320 }
321 
322 static void object_deinit(Object *obj, TypeImpl *type)
323 {
324     if (type->instance_finalize) {
325         type->instance_finalize(obj);
326     }
327 
328     while (obj->interfaces) {
329         Interface *iface_obj = obj->interfaces->data;
330         obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
331         object_delete(OBJECT(iface_obj));
332     }
333 
334     if (type_has_parent(type)) {
335         object_deinit(obj, type_get_parent(type));
336     }
337 
338     object_unparent(obj);
339 }
340 
341 void object_finalize(void *data)
342 {
343     Object *obj = data;
344     TypeImpl *ti = obj->class->type;
345 
346     object_deinit(obj, ti);
347     object_property_del_all(obj);
348 
349     g_assert(obj->ref == 0);
350 }
351 
352 Object *object_new_with_type(Type type)
353 {
354     Object *obj;
355 
356     g_assert(type != NULL);
357 
358     obj = g_malloc(type->instance_size);
359     object_initialize_with_type(obj, type);
360     object_ref(obj);
361 
362     return obj;
363 }
364 
365 Object *object_new(const char *typename)
366 {
367     TypeImpl *ti = type_get_by_name(typename);
368 
369     return object_new_with_type(ti);
370 }
371 
372 void object_delete(Object *obj)
373 {
374     object_unref(obj);
375     g_assert(obj->ref == 0);
376     g_free(obj);
377 }
378 
379 static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
380 {
381     assert(target_type);
382 
383     /* Check if typename is a direct ancestor of type */
384     while (type) {
385         if (type == target_type) {
386             return true;
387         }
388 
389         type = type_get_parent(type);
390     }
391 
392     return false;
393 }
394 
395 static bool object_is_type(Object *obj, TypeImpl *target_type)
396 {
397     return !target_type || type_is_ancestor(obj->class->type, target_type);
398 }
399 
400 Object *object_dynamic_cast(Object *obj, const char *typename)
401 {
402     TypeImpl *target_type = type_get_by_name(typename);
403     GSList *i;
404 
405     /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
406      * we want to go back from interfaces to the parent.
407     */
408     if (target_type && object_is_type(obj, target_type)) {
409         return obj;
410     }
411 
412     /* Check if obj is an interface and its containing object is a direct
413      * ancestor of typename.  In principle we could do this test at the very
414      * beginning of object_dynamic_cast, avoiding a second call to
415      * object_is_type.  However, casting between interfaces is relatively
416      * rare, and object_is_type(obj, type_interface) would fail almost always.
417      *
418      * Perhaps we could add a magic value to the object header for increased
419      * (run-time) type safety and to speed up tests like this one.  If we ever
420      * do that we can revisit the order here.
421      */
422     if (object_is_type(obj, type_interface)) {
423         assert(!obj->interfaces);
424         obj = INTERFACE(obj)->obj;
425         if (object_is_type(obj, target_type)) {
426             return obj;
427         }
428     }
429 
430     if (!target_type) {
431         return obj;
432     }
433 
434     /* Check if obj has an interface of typename */
435     for (i = obj->interfaces; i; i = i->next) {
436         Interface *iface = i->data;
437 
438         if (object_is_type(OBJECT(iface), target_type)) {
439             return OBJECT(iface);
440         }
441     }
442 
443     return NULL;
444 }
445 
446 
447 static void register_interface(void)
448 {
449     static TypeInfo interface_info = {
450         .name = TYPE_INTERFACE,
451         .instance_size = sizeof(Interface),
452         .abstract = true,
453     };
454 
455     type_interface = type_register_static(&interface_info);
456 }
457 
458 device_init(register_interface);
459 
460 Object *object_dynamic_cast_assert(Object *obj, const char *typename)
461 {
462     Object *inst;
463 
464     inst = object_dynamic_cast(obj, typename);
465 
466     if (!inst) {
467         fprintf(stderr, "Object %p is not an instance of type %s\n",
468                 obj, typename);
469         abort();
470     }
471 
472     return inst;
473 }
474 
475 ObjectClass *object_class_dynamic_cast(ObjectClass *class,
476                                        const char *typename)
477 {
478     TypeImpl *target_type = type_get_by_name(typename);
479     TypeImpl *type = class->type;
480 
481     while (type) {
482         if (type == target_type) {
483             return class;
484         }
485 
486         type = type_get_parent(type);
487     }
488 
489     return NULL;
490 }
491 
492 ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
493                                               const char *typename)
494 {
495     ObjectClass *ret = object_class_dynamic_cast(class, typename);
496 
497     if (!ret) {
498         fprintf(stderr, "Object %p is not an instance of type %s\n",
499                 class, typename);
500         abort();
501     }
502 
503     return ret;
504 }
505 
506 const char *object_get_typename(Object *obj)
507 {
508     return obj->class->type->name;
509 }
510 
511 ObjectClass *object_get_class(Object *obj)
512 {
513     return obj->class;
514 }
515 
516 const char *object_class_get_name(ObjectClass *klass)
517 {
518     return klass->type->name;
519 }
520 
521 ObjectClass *object_class_by_name(const char *typename)
522 {
523     TypeImpl *type = type_get_by_name(typename);
524 
525     if (!type) {
526         return NULL;
527     }
528 
529     type_class_init(type);
530 
531     return type->class;
532 }
533 
534 typedef struct OCFData
535 {
536     void (*fn)(ObjectClass *klass, void *opaque);
537     const char *implements_type;
538     bool include_abstract;
539     void *opaque;
540 } OCFData;
541 
542 static void object_class_foreach_tramp(gpointer key, gpointer value,
543                                        gpointer opaque)
544 {
545     OCFData *data = opaque;
546     TypeImpl *type = value;
547     ObjectClass *k;
548 
549     type_class_init(type);
550     k = type->class;
551 
552     if (!data->include_abstract && type->abstract) {
553         return;
554     }
555 
556     if (data->implements_type &&
557         !object_class_dynamic_cast(k, data->implements_type)) {
558         return;
559     }
560 
561     data->fn(k, data->opaque);
562 }
563 
564 void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
565                           const char *implements_type, bool include_abstract,
566                           void *opaque)
567 {
568     OCFData data = { fn, implements_type, include_abstract, opaque };
569 
570     g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
571 }
572 
573 void object_ref(Object *obj)
574 {
575     obj->ref++;
576 }
577 
578 void object_unref(Object *obj)
579 {
580     g_assert(obj->ref > 0);
581     obj->ref--;
582 
583     /* parent always holds a reference to its children */
584     if (obj->ref == 0) {
585         object_finalize(obj);
586     }
587 }
588 
589 void object_property_add(Object *obj, const char *name, const char *type,
590                          ObjectPropertyAccessor *get,
591                          ObjectPropertyAccessor *set,
592                          ObjectPropertyRelease *release,
593                          void *opaque, Error **errp)
594 {
595     ObjectProperty *prop = g_malloc0(sizeof(*prop));
596 
597     prop->name = g_strdup(name);
598     prop->type = g_strdup(type);
599 
600     prop->get = get;
601     prop->set = set;
602     prop->release = release;
603     prop->opaque = opaque;
604 
605     QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
606 }
607 
608 static ObjectProperty *object_property_find(Object *obj, const char *name)
609 {
610     ObjectProperty *prop;
611 
612     QTAILQ_FOREACH(prop, &obj->properties, node) {
613         if (strcmp(prop->name, name) == 0) {
614             return prop;
615         }
616     }
617 
618     return NULL;
619 }
620 
621 void object_property_del(Object *obj, const char *name, Error **errp)
622 {
623     ObjectProperty *prop = object_property_find(obj, name);
624 
625     QTAILQ_REMOVE(&obj->properties, prop, node);
626 
627     prop->release(obj, prop->name, prop->opaque);
628 
629     g_free(prop->name);
630     g_free(prop->type);
631     g_free(prop);
632 }
633 
634 void object_property_get(Object *obj, Visitor *v, const char *name,
635                          Error **errp)
636 {
637     ObjectProperty *prop = object_property_find(obj, name);
638 
639     if (prop == NULL) {
640         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
641         return;
642     }
643 
644     if (!prop->get) {
645         error_set(errp, QERR_PERMISSION_DENIED);
646     } else {
647         prop->get(obj, v, prop->opaque, name, errp);
648     }
649 }
650 
651 void object_property_set(Object *obj, Visitor *v, const char *name,
652                          Error **errp)
653 {
654     ObjectProperty *prop = object_property_find(obj, name);
655 
656     if (prop == NULL) {
657         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
658         return;
659     }
660 
661     if (!prop->set) {
662         error_set(errp, QERR_PERMISSION_DENIED);
663     } else {
664         prop->set(obj, v, prop->opaque, name, errp);
665     }
666 }
667 
668 void object_property_set_str(Object *obj, const char *value,
669                              const char *name, Error **errp)
670 {
671     QString *qstr = qstring_from_str(value);
672     object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
673 
674     QDECREF(qstr);
675 }
676 
677 char *object_property_get_str(Object *obj, const char *name,
678                               Error **errp)
679 {
680     QObject *ret = object_property_get_qobject(obj, name, errp);
681     QString *qstring;
682     char *retval;
683 
684     if (!ret) {
685         return NULL;
686     }
687     qstring = qobject_to_qstring(ret);
688     if (!qstring) {
689         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
690         retval = NULL;
691     } else {
692         retval = g_strdup(qstring_get_str(qstring));
693     }
694 
695     QDECREF(qstring);
696     return retval;
697 }
698 
699 void object_property_set_bool(Object *obj, bool value,
700                               const char *name, Error **errp)
701 {
702     QBool *qbool = qbool_from_int(value);
703     object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
704 
705     QDECREF(qbool);
706 }
707 
708 bool object_property_get_bool(Object *obj, const char *name,
709                               Error **errp)
710 {
711     QObject *ret = object_property_get_qobject(obj, name, errp);
712     QBool *qbool;
713     bool retval;
714 
715     if (!ret) {
716         return false;
717     }
718     qbool = qobject_to_qbool(ret);
719     if (!qbool) {
720         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
721         retval = false;
722     } else {
723         retval = qbool_get_int(qbool);
724     }
725 
726     QDECREF(qbool);
727     return retval;
728 }
729 
730 void object_property_set_int(Object *obj, int64_t value,
731                              const char *name, Error **errp)
732 {
733     QInt *qint = qint_from_int(value);
734     object_property_set_qobject(obj, QOBJECT(qint), name, errp);
735 
736     QDECREF(qint);
737 }
738 
739 int64_t object_property_get_int(Object *obj, const char *name,
740                                 Error **errp)
741 {
742     QObject *ret = object_property_get_qobject(obj, name, errp);
743     QInt *qint;
744     int64_t retval;
745 
746     if (!ret) {
747         return -1;
748     }
749     qint = qobject_to_qint(ret);
750     if (!qint) {
751         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
752         retval = -1;
753     } else {
754         retval = qint_get_int(qint);
755     }
756 
757     QDECREF(qint);
758     return retval;
759 }
760 
761 const char *object_property_get_type(Object *obj, const char *name, Error **errp)
762 {
763     ObjectProperty *prop = object_property_find(obj, name);
764 
765     if (prop == NULL) {
766         error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
767         return NULL;
768     }
769 
770     return prop->type;
771 }
772 
773 Object *object_get_root(void)
774 {
775     static Object *root;
776 
777     if (!root) {
778         root = object_new("container");
779     }
780 
781     return root;
782 }
783 
784 static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
785                                       const char *name, Error **errp)
786 {
787     Object *child = opaque;
788     gchar *path;
789 
790     path = object_get_canonical_path(child);
791     visit_type_str(v, &path, name, errp);
792     g_free(path);
793 }
794 
795 static void object_finalize_child_property(Object *obj, const char *name,
796                                            void *opaque)
797 {
798     Object *child = opaque;
799 
800     object_unref(child);
801 }
802 
803 void object_property_add_child(Object *obj, const char *name,
804                                Object *child, Error **errp)
805 {
806     gchar *type;
807 
808     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
809 
810     object_property_add(obj, name, type, object_get_child_property,
811                         NULL, object_finalize_child_property, child, errp);
812 
813     object_ref(child);
814     g_assert(child->parent == NULL);
815     child->parent = obj;
816 
817     g_free(type);
818 }
819 
820 static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
821                                      const char *name, Error **errp)
822 {
823     Object **child = opaque;
824     gchar *path;
825 
826     if (*child) {
827         path = object_get_canonical_path(*child);
828         visit_type_str(v, &path, name, errp);
829         g_free(path);
830     } else {
831         path = (gchar *)"";
832         visit_type_str(v, &path, name, errp);
833     }
834 }
835 
836 static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
837                                      const char *name, Error **errp)
838 {
839     Object **child = opaque;
840     bool ambiguous = false;
841     const char *type;
842     char *path;
843 
844     type = object_property_get_type(obj, name, NULL);
845 
846     visit_type_str(v, &path, name, errp);
847 
848     if (*child) {
849         object_unref(*child);
850     }
851 
852     if (strcmp(path, "") != 0) {
853         Object *target;
854 
855         target = object_resolve_path(path, &ambiguous);
856         if (target) {
857             gchar *target_type;
858 
859             target_type = g_strdup(&type[5]);
860             target_type[strlen(target_type) - 2] = 0;
861 
862             if (object_dynamic_cast(target, target_type)) {
863                 object_ref(target);
864                 *child = target;
865             } else {
866                 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
867             }
868 
869             g_free(target_type);
870         } else {
871             error_set(errp, QERR_DEVICE_NOT_FOUND, path);
872         }
873     } else {
874         *child = NULL;
875     }
876 
877     g_free(path);
878 }
879 
880 void object_property_add_link(Object *obj, const char *name,
881                               const char *type, Object **child,
882                               Error **errp)
883 {
884     gchar *full_type;
885 
886     full_type = g_strdup_printf("link<%s>", type);
887 
888     object_property_add(obj, name, full_type,
889                         object_get_link_property,
890                         object_set_link_property,
891                         NULL, child, errp);
892 
893     g_free(full_type);
894 }
895 
896 gchar *object_get_canonical_path(Object *obj)
897 {
898     Object *root = object_get_root();
899     char *newpath = NULL, *path = NULL;
900 
901     while (obj != root) {
902         ObjectProperty *prop = NULL;
903 
904         g_assert(obj->parent != NULL);
905 
906         QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
907             if (!strstart(prop->type, "child<", NULL)) {
908                 continue;
909             }
910 
911             if (prop->opaque == obj) {
912                 if (path) {
913                     newpath = g_strdup_printf("%s/%s", prop->name, path);
914                     g_free(path);
915                     path = newpath;
916                 } else {
917                     path = g_strdup(prop->name);
918                 }
919                 break;
920             }
921         }
922 
923         g_assert(prop != NULL);
924 
925         obj = obj->parent;
926     }
927 
928     newpath = g_strdup_printf("/%s", path);
929     g_free(path);
930 
931     return newpath;
932 }
933 
934 static Object *object_resolve_abs_path(Object *parent,
935                                           gchar **parts,
936                                           int index)
937 {
938     ObjectProperty *prop;
939     Object *child;
940 
941     if (parts[index] == NULL) {
942         return parent;
943     }
944 
945     if (strcmp(parts[index], "") == 0) {
946         return object_resolve_abs_path(parent, parts, index + 1);
947     }
948 
949     prop = object_property_find(parent, parts[index]);
950     if (prop == NULL) {
951         return NULL;
952     }
953 
954     child = NULL;
955     if (strstart(prop->type, "link<", NULL)) {
956         Object **pchild = prop->opaque;
957         if (*pchild) {
958             child = *pchild;
959         }
960     } else if (strstart(prop->type, "child<", NULL)) {
961         child = prop->opaque;
962     }
963 
964     if (!child) {
965         return NULL;
966     }
967 
968     return object_resolve_abs_path(child, parts, index + 1);
969 }
970 
971 static Object *object_resolve_partial_path(Object *parent,
972                                               gchar **parts,
973                                               bool *ambiguous)
974 {
975     Object *obj;
976     ObjectProperty *prop;
977 
978     obj = object_resolve_abs_path(parent, parts, 0);
979 
980     QTAILQ_FOREACH(prop, &parent->properties, node) {
981         Object *found;
982 
983         if (!strstart(prop->type, "child<", NULL)) {
984             continue;
985         }
986 
987         found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
988         if (found) {
989             if (obj) {
990                 if (ambiguous) {
991                     *ambiguous = true;
992                 }
993                 return NULL;
994             }
995             obj = found;
996         }
997 
998         if (ambiguous && *ambiguous) {
999             return NULL;
1000         }
1001     }
1002 
1003     return obj;
1004 }
1005 
1006 Object *object_resolve_path(const char *path, bool *ambiguous)
1007 {
1008     bool partial_path = true;
1009     Object *obj;
1010     gchar **parts;
1011 
1012     parts = g_strsplit(path, "/", 0);
1013     if (parts == NULL || parts[0] == NULL) {
1014         g_strfreev(parts);
1015         return object_get_root();
1016     }
1017 
1018     if (strcmp(parts[0], "") == 0) {
1019         partial_path = false;
1020     }
1021 
1022     if (partial_path) {
1023         if (ambiguous) {
1024             *ambiguous = false;
1025         }
1026         obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
1027     } else {
1028         obj = object_resolve_abs_path(object_get_root(), parts, 1);
1029     }
1030 
1031     g_strfreev(parts);
1032 
1033     return obj;
1034 }
1035 
1036 typedef struct StringProperty
1037 {
1038     char *(*get)(Object *, Error **);
1039     void (*set)(Object *, const char *, Error **);
1040 } StringProperty;
1041 
1042 static void property_get_str(Object *obj, Visitor *v, void *opaque,
1043                              const char *name, Error **errp)
1044 {
1045     StringProperty *prop = opaque;
1046     char *value;
1047 
1048     value = prop->get(obj, errp);
1049     if (value) {
1050         visit_type_str(v, &value, name, errp);
1051         g_free(value);
1052     }
1053 }
1054 
1055 static void property_set_str(Object *obj, Visitor *v, void *opaque,
1056                              const char *name, Error **errp)
1057 {
1058     StringProperty *prop = opaque;
1059     char *value;
1060     Error *local_err = NULL;
1061 
1062     visit_type_str(v, &value, name, &local_err);
1063     if (local_err) {
1064         error_propagate(errp, local_err);
1065         return;
1066     }
1067 
1068     prop->set(obj, value, errp);
1069     g_free(value);
1070 }
1071 
1072 static void property_release_str(Object *obj, const char *name,
1073                                  void *opaque)
1074 {
1075     StringProperty *prop = opaque;
1076     g_free(prop);
1077 }
1078 
1079 void object_property_add_str(Object *obj, const char *name,
1080                            char *(*get)(Object *, Error **),
1081                            void (*set)(Object *, const char *, Error **),
1082                            Error **errp)
1083 {
1084     StringProperty *prop = g_malloc0(sizeof(*prop));
1085 
1086     prop->get = get;
1087     prop->set = set;
1088 
1089     object_property_add(obj, name, "string",
1090                         get ? property_get_str : NULL,
1091                         set ? property_set_str : NULL,
1092                         property_release_str,
1093                         prop, errp);
1094 }
1095