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