diff options
Diffstat (limited to 'qemu/qom/object_interfaces.c')
-rw-r--r-- | qemu/qom/object_interfaces.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/qemu/qom/object_interfaces.c b/qemu/qom/object_interfaces.c index a66cd6026..393189024 100644 --- a/qemu/qom/object_interfaces.c +++ b/qemu/qom/object_interfaces.c @@ -1,5 +1,10 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "qom/object_interfaces.h" #include "qemu/module.h" +#include "qapi-visit.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi/opts-visitor.h" void user_creatable_complete(Object *obj, Error **errp) { @@ -30,6 +35,179 @@ bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp) } } + +Object *user_creatable_add(const QDict *qdict, + Visitor *v, Error **errp) +{ + char *type = NULL; + char *id = NULL; + Object *obj = NULL; + Error *local_err = NULL, *end_err = NULL; + QDict *pdict; + + pdict = qdict_clone_shallow(qdict); + + visit_start_struct(v, NULL, NULL, 0, &local_err); + if (local_err) { + goto out; + } + + qdict_del(pdict, "qom-type"); + visit_type_str(v, "qom-type", &type, &local_err); + if (local_err) { + goto out_visit; + } + + qdict_del(pdict, "id"); + visit_type_str(v, "id", &id, &local_err); + if (local_err) { + goto out_visit; + } + + obj = user_creatable_add_type(type, id, pdict, v, &local_err); + if (local_err) { + goto out_visit; + } + + out_visit: + visit_end_struct(v, &end_err); + if (end_err) { + error_propagate(&local_err, end_err); + if (obj) { + user_creatable_del(id, NULL); + } + goto out; + } + +out: + QDECREF(pdict); + g_free(id); + g_free(type); + if (local_err) { + error_propagate(errp, local_err); + object_unref(obj); + return NULL; + } + return obj; +} + + +Object *user_creatable_add_type(const char *type, const char *id, + const QDict *qdict, + Visitor *v, Error **errp) +{ + Object *obj; + ObjectClass *klass; + const QDictEntry *e; + Error *local_err = NULL; + + klass = object_class_by_name(type); + if (!klass) { + error_setg(errp, "invalid object type: %s", type); + return NULL; + } + + if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) { + error_setg(errp, "object type '%s' isn't supported by object-add", + type); + return NULL; + } + + if (object_class_is_abstract(klass)) { + error_setg(errp, "object type '%s' is abstract", type); + return NULL; + } + + obj = object_new(type); + if (qdict) { + for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { + object_property_set(obj, v, e->key, &local_err); + if (local_err) { + goto out; + } + } + } + + object_property_add_child(object_get_objects_root(), + id, obj, &local_err); + if (local_err) { + goto out; + } + + user_creatable_complete(obj, &local_err); + if (local_err) { + object_property_del(object_get_objects_root(), + id, &error_abort); + goto out; + } +out: + if (local_err) { + error_propagate(errp, local_err); + object_unref(obj); + return NULL; + } + return obj; +} + + +Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) +{ + OptsVisitor *ov; + QDict *pdict; + Object *obj = NULL; + + ov = opts_visitor_new(opts); + pdict = qemu_opts_to_qdict(opts, NULL); + + obj = user_creatable_add(pdict, opts_get_visitor(ov), errp); + opts_visitor_cleanup(ov); + QDECREF(pdict); + return obj; +} + + +int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) +{ + bool (*type_predicate)(const char *) = opaque; + Object *obj = NULL; + Error *err = NULL; + const char *type; + + type = qemu_opt_get(opts, "qom-type"); + if (type && type_predicate && + !type_predicate(type)) { + return 0; + } + + obj = user_creatable_add_opts(opts, &err); + if (!obj) { + error_report_err(err); + return -1; + } + object_unref(obj); + return 0; +} + + +void user_creatable_del(const char *id, Error **errp) +{ + Object *container; + Object *obj; + + container = object_get_objects_root(); + obj = object_resolve_path_component(container, id); + if (!obj) { + error_setg(errp, "object '%s' not found", id); + return; + } + + if (!user_creatable_can_be_deleted(USER_CREATABLE(obj), errp)) { + error_setg(errp, "object '%s' is in use, can not be deleted", id); + return; + } + object_unparent(obj); +} + static void register_types(void) { static const TypeInfo uc_interface_info = { |