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