]> Git Repo - qemu.git/blob - qom/object.c
qom: fix canonical paths vs. interfaces
[qemu.git] / qom / object.c
1 /*
2  * QEMU Object Model
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *  Anthony Liguori   <[email protected]>
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     /* Registering an interface object in the composition tree will mightily
809      * confuse object_get_canonical_path (which, on the other hand, knows how
810      * to get the canonical path of an interface object).
811      */
812     assert(!object_is_type(obj, type_interface));
813
814     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
815
816     object_property_add(obj, name, type, object_get_child_property,
817                         NULL, object_finalize_child_property, child, errp);
818
819     object_ref(child);
820     g_assert(child->parent == NULL);
821     child->parent = obj;
822
823     g_free(type);
824 }
825
826 static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
827                                      const char *name, Error **errp)
828 {
829     Object **child = opaque;
830     gchar *path;
831
832     if (*child) {
833         path = object_get_canonical_path(*child);
834         visit_type_str(v, &path, name, errp);
835         g_free(path);
836     } else {
837         path = (gchar *)"";
838         visit_type_str(v, &path, name, errp);
839     }
840 }
841
842 static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
843                                      const char *name, Error **errp)
844 {
845     Object **child = opaque;
846     bool ambiguous = false;
847     const char *type;
848     char *path;
849     gchar *target_type;
850
851     type = object_property_get_type(obj, name, NULL);
852
853     visit_type_str(v, &path, name, errp);
854
855     if (*child) {
856         object_unref(*child);
857         *child = NULL;
858     }
859
860     if (strcmp(path, "") != 0) {
861         Object *target;
862
863         /* Go from link<FOO> to FOO.  */
864         target_type = g_strndup(&type[5], strlen(type) - 6);
865         target = object_resolve_path_type(path, target_type, &ambiguous);
866
867         if (ambiguous) {
868             error_set(errp, QERR_AMBIGUOUS_PATH, path);
869         } else if (target) {
870             object_ref(target);
871             *child = target;
872         } else {
873             target = object_resolve_path(path, &ambiguous);
874             if (target || ambiguous) {
875                 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
876             } else {
877                 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
878             }
879         }
880         g_free(target_type);
881     }
882
883     g_free(path);
884 }
885
886 void object_property_add_link(Object *obj, const char *name,
887                               const char *type, Object **child,
888                               Error **errp)
889 {
890     gchar *full_type;
891
892     full_type = g_strdup_printf("link<%s>", type);
893
894     object_property_add(obj, name, full_type,
895                         object_get_link_property,
896                         object_set_link_property,
897                         NULL, child, errp);
898
899     g_free(full_type);
900 }
901
902 gchar *object_get_canonical_path(Object *obj)
903 {
904     Object *root = object_get_root();
905     char *newpath = NULL, *path = NULL;
906
907     if (object_is_type(obj, type_interface)) {
908         obj = INTERFACE(obj)->obj;
909     }
910
911     while (obj != root) {
912         ObjectProperty *prop = NULL;
913
914         g_assert(obj->parent != NULL);
915
916         QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
917             if (!strstart(prop->type, "child<", NULL)) {
918                 continue;
919             }
920
921             if (prop->opaque == obj) {
922                 if (path) {
923                     newpath = g_strdup_printf("%s/%s", prop->name, path);
924                     g_free(path);
925                     path = newpath;
926                 } else {
927                     path = g_strdup(prop->name);
928                 }
929                 break;
930             }
931         }
932
933         g_assert(prop != NULL);
934
935         obj = obj->parent;
936     }
937
938     newpath = g_strdup_printf("/%s", path);
939     g_free(path);
940
941     return newpath;
942 }
943
944 static Object *object_resolve_abs_path(Object *parent,
945                                           gchar **parts,
946                                           const char *typename,
947                                           int index)
948 {
949     ObjectProperty *prop;
950     Object *child;
951
952     if (parts[index] == NULL) {
953         return object_dynamic_cast(parent, typename);
954     }
955
956     if (strcmp(parts[index], "") == 0) {
957         return object_resolve_abs_path(parent, parts, typename, index + 1);
958     }
959
960     prop = object_property_find(parent, parts[index]);
961     if (prop == NULL) {
962         return NULL;
963     }
964
965     child = NULL;
966     if (strstart(prop->type, "link<", NULL)) {
967         Object **pchild = prop->opaque;
968         if (*pchild) {
969             child = *pchild;
970         }
971     } else if (strstart(prop->type, "child<", NULL)) {
972         child = prop->opaque;
973     }
974
975     if (!child) {
976         return NULL;
977     }
978
979     return object_resolve_abs_path(child, parts, typename, index + 1);
980 }
981
982 static Object *object_resolve_partial_path(Object *parent,
983                                               gchar **parts,
984                                               const char *typename,
985                                               bool *ambiguous)
986 {
987     Object *obj;
988     ObjectProperty *prop;
989
990     obj = object_resolve_abs_path(parent, parts, typename, 0);
991
992     QTAILQ_FOREACH(prop, &parent->properties, node) {
993         Object *found;
994
995         if (!strstart(prop->type, "child<", NULL)) {
996             continue;
997         }
998
999         found = object_resolve_partial_path(prop->opaque, parts,
1000                                             typename, ambiguous);
1001         if (found) {
1002             if (obj) {
1003                 if (ambiguous) {
1004                     *ambiguous = true;
1005                 }
1006                 return NULL;
1007             }
1008             obj = found;
1009         }
1010
1011         if (ambiguous && *ambiguous) {
1012             return NULL;
1013         }
1014     }
1015
1016     return obj;
1017 }
1018
1019 Object *object_resolve_path_type(const char *path, const char *typename,
1020                                  bool *ambiguous)
1021 {
1022     bool partial_path = true;
1023     Object *obj;
1024     gchar **parts;
1025
1026     parts = g_strsplit(path, "/", 0);
1027     if (parts == NULL || parts[0] == NULL) {
1028         g_strfreev(parts);
1029         return object_get_root();
1030     }
1031
1032     if (strcmp(parts[0], "") == 0) {
1033         partial_path = false;
1034     }
1035
1036     if (partial_path) {
1037         if (ambiguous) {
1038             *ambiguous = false;
1039         }
1040         obj = object_resolve_partial_path(object_get_root(), parts,
1041                                           typename, ambiguous);
1042     } else {
1043         obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
1044     }
1045
1046     g_strfreev(parts);
1047
1048     return obj;
1049 }
1050
1051 Object *object_resolve_path(const char *path, bool *ambiguous)
1052 {
1053     return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
1054 }
1055
1056 typedef struct StringProperty
1057 {
1058     char *(*get)(Object *, Error **);
1059     void (*set)(Object *, const char *, Error **);
1060 } StringProperty;
1061
1062 static void property_get_str(Object *obj, Visitor *v, void *opaque,
1063                              const char *name, Error **errp)
1064 {
1065     StringProperty *prop = opaque;
1066     char *value;
1067
1068     value = prop->get(obj, errp);
1069     if (value) {
1070         visit_type_str(v, &value, name, errp);
1071         g_free(value);
1072     }
1073 }
1074
1075 static void property_set_str(Object *obj, Visitor *v, void *opaque,
1076                              const char *name, Error **errp)
1077 {
1078     StringProperty *prop = opaque;
1079     char *value;
1080     Error *local_err = NULL;
1081
1082     visit_type_str(v, &value, name, &local_err);
1083     if (local_err) {
1084         error_propagate(errp, local_err);
1085         return;
1086     }
1087
1088     prop->set(obj, value, errp);
1089     g_free(value);
1090 }
1091
1092 static void property_release_str(Object *obj, const char *name,
1093                                  void *opaque)
1094 {
1095     StringProperty *prop = opaque;
1096     g_free(prop);
1097 }
1098
1099 void object_property_add_str(Object *obj, const char *name,
1100                            char *(*get)(Object *, Error **),
1101                            void (*set)(Object *, const char *, Error **),
1102                            Error **errp)
1103 {
1104     StringProperty *prop = g_malloc0(sizeof(*prop));
1105
1106     prop->get = get;
1107     prop->set = set;
1108
1109     object_property_add(obj, name, "string",
1110                         get ? property_get_str : NULL,
1111                         set ? property_set_str : NULL,
1112                         property_release_str,
1113                         prop, errp);
1114 }
This page took 0.0817 seconds and 4 git commands to generate.