19bbc853bSPeter Maydell #include "qemu/osdep.h" 2da34e65cSMarkus Armbruster #include "qapi/error.h" 3452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 40dd13589SMarkus Armbruster #include "qapi/qmp/qerror.h" 5269e09f3SIgor Mammedov #include "qom/object_interfaces.h" 6269e09f3SIgor Mammedov #include "qemu/module.h" 7922a01a0SMarkus Armbruster #include "qemu/option.h" 890998d58SDaniel P. Berrange #include "qapi/opts-visitor.h" 9c645d5acSMichael Roth #include "qemu/config-file.h" 10269e09f3SIgor Mammedov 11269e09f3SIgor Mammedov void user_creatable_complete(Object *obj, Error **errp) 12269e09f3SIgor Mammedov { 13269e09f3SIgor Mammedov 14269e09f3SIgor Mammedov UserCreatableClass *ucc; 15269e09f3SIgor Mammedov UserCreatable *uc = 16269e09f3SIgor Mammedov (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE); 17269e09f3SIgor Mammedov 18269e09f3SIgor Mammedov if (!uc) { 19269e09f3SIgor Mammedov return; 20269e09f3SIgor Mammedov } 21269e09f3SIgor Mammedov 22269e09f3SIgor Mammedov ucc = USER_CREATABLE_GET_CLASS(uc); 23269e09f3SIgor Mammedov if (ucc->complete) { 24269e09f3SIgor Mammedov ucc->complete(uc, errp); 25269e09f3SIgor Mammedov } 26269e09f3SIgor Mammedov } 27269e09f3SIgor Mammedov 283beacfb9SEduardo Habkost bool user_creatable_can_be_deleted(UserCreatable *uc) 29d6edb155SLin Ma { 30d6edb155SLin Ma 31d6edb155SLin Ma UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc); 32d6edb155SLin Ma 33d6edb155SLin Ma if (ucc->can_be_deleted) { 343beacfb9SEduardo Habkost return ucc->can_be_deleted(uc); 35d6edb155SLin Ma } else { 36d6edb155SLin Ma return true; 37d6edb155SLin Ma } 38d6edb155SLin Ma } 39d6edb155SLin Ma 4090998d58SDaniel P. Berrange Object *user_creatable_add_type(const char *type, const char *id, 4190998d58SDaniel P. Berrange const QDict *qdict, 4290998d58SDaniel P. Berrange Visitor *v, Error **errp) 4390998d58SDaniel P. Berrange { 4490998d58SDaniel P. Berrange Object *obj; 4590998d58SDaniel P. Berrange ObjectClass *klass; 4690998d58SDaniel P. Berrange const QDictEntry *e; 4790998d58SDaniel P. Berrange Error *local_err = NULL; 4890998d58SDaniel P. Berrange 4990998d58SDaniel P. Berrange klass = object_class_by_name(type); 5090998d58SDaniel P. Berrange if (!klass) { 5190998d58SDaniel P. Berrange error_setg(errp, "invalid object type: %s", type); 5290998d58SDaniel P. Berrange return NULL; 5390998d58SDaniel P. Berrange } 5490998d58SDaniel P. Berrange 5590998d58SDaniel P. Berrange if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) { 5690998d58SDaniel P. Berrange error_setg(errp, "object type '%s' isn't supported by object-add", 5790998d58SDaniel P. Berrange type); 5890998d58SDaniel P. Berrange return NULL; 5990998d58SDaniel P. Berrange } 6090998d58SDaniel P. Berrange 6190998d58SDaniel P. Berrange if (object_class_is_abstract(klass)) { 6290998d58SDaniel P. Berrange error_setg(errp, "object type '%s' is abstract", type); 6390998d58SDaniel P. Berrange return NULL; 6490998d58SDaniel P. Berrange } 6590998d58SDaniel P. Berrange 66ad739706SEric Blake assert(qdict); 6790998d58SDaniel P. Berrange obj = object_new(type); 68ad739706SEric Blake visit_start_struct(v, NULL, NULL, 0, &local_err); 6990998d58SDaniel P. Berrange if (local_err) { 7090998d58SDaniel P. Berrange goto out; 7190998d58SDaniel P. Berrange } 72ad739706SEric Blake for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { 73ad739706SEric Blake object_property_set(obj, v, e->key, &local_err); 74ad739706SEric Blake if (local_err) { 75ad739706SEric Blake break; 7690998d58SDaniel P. Berrange } 7790998d58SDaniel P. Berrange } 7815c2f669SEric Blake if (!local_err) { 7915c2f669SEric Blake visit_check_struct(v, &local_err); 8015c2f669SEric Blake } 811158bb2aSEric Blake visit_end_struct(v, NULL); 82ad739706SEric Blake if (local_err) { 83ad739706SEric Blake goto out; 84ad739706SEric Blake } 8590998d58SDaniel P. Berrange 8690998d58SDaniel P. Berrange object_property_add_child(object_get_objects_root(), 8790998d58SDaniel P. Berrange id, obj, &local_err); 8890998d58SDaniel P. Berrange if (local_err) { 8990998d58SDaniel P. Berrange goto out; 9090998d58SDaniel P. Berrange } 9190998d58SDaniel P. Berrange 9290998d58SDaniel P. Berrange user_creatable_complete(obj, &local_err); 9390998d58SDaniel P. Berrange if (local_err) { 9490998d58SDaniel P. Berrange object_property_del(object_get_objects_root(), 9590998d58SDaniel P. Berrange id, &error_abort); 9690998d58SDaniel P. Berrange goto out; 9790998d58SDaniel P. Berrange } 9890998d58SDaniel P. Berrange out: 9990998d58SDaniel P. Berrange if (local_err) { 10090998d58SDaniel P. Berrange error_propagate(errp, local_err); 10190998d58SDaniel P. Berrange object_unref(obj); 10290998d58SDaniel P. Berrange return NULL; 10390998d58SDaniel P. Berrange } 10490998d58SDaniel P. Berrange return obj; 10590998d58SDaniel P. Berrange } 10690998d58SDaniel P. Berrange 10790998d58SDaniel P. Berrange 10890998d58SDaniel P. Berrange Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) 10990998d58SDaniel P. Berrange { 11009204eacSEric Blake Visitor *v; 11190998d58SDaniel P. Berrange QDict *pdict; 1123a464105SIgor Mammedov Object *obj; 1133a464105SIgor Mammedov const char *id = qemu_opts_id(opts); 1149a6d1acbSEric Blake char *type = qemu_opt_get_del(opts, "qom-type"); 1153a464105SIgor Mammedov 1163a464105SIgor Mammedov if (!type) { 1173a464105SIgor Mammedov error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); 1183a464105SIgor Mammedov return NULL; 1193a464105SIgor Mammedov } 1203a464105SIgor Mammedov if (!id) { 1213a464105SIgor Mammedov error_setg(errp, QERR_MISSING_PARAMETER, "id"); 12208329701SEric Blake qemu_opt_set(opts, "qom-type", type, &error_abort); 1239a6d1acbSEric Blake g_free(type); 1243a464105SIgor Mammedov return NULL; 1253a464105SIgor Mammedov } 1263a464105SIgor Mammedov 1279a6d1acbSEric Blake qemu_opts_set_id(opts, NULL); 1283a464105SIgor Mammedov pdict = qemu_opts_to_qdict(opts, NULL); 12990998d58SDaniel P. Berrange 13009204eacSEric Blake v = opts_visitor_new(opts); 1313a464105SIgor Mammedov obj = user_creatable_add_type(type, id, pdict, v, errp); 13209204eacSEric Blake visit_free(v); 1333a464105SIgor Mammedov 1349a6d1acbSEric Blake qemu_opts_set_id(opts, (char *) id); 13508329701SEric Blake qemu_opt_set(opts, "qom-type", type, &error_abort); 1369a6d1acbSEric Blake g_free(type); 137cb3e7f08SMarc-André Lureau qobject_unref(pdict); 13890998d58SDaniel P. Berrange return obj; 13990998d58SDaniel P. Berrange } 14090998d58SDaniel P. Berrange 14190998d58SDaniel P. Berrange 14290998d58SDaniel P. Berrange int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) 14390998d58SDaniel P. Berrange { 144*1195fa2bSMarc-André Lureau bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque; 14590998d58SDaniel P. Berrange Object *obj = NULL; 14651b9b478SMarkus Armbruster Error *err = NULL; 14790998d58SDaniel P. Berrange const char *type; 14890998d58SDaniel P. Berrange 14990998d58SDaniel P. Berrange type = qemu_opt_get(opts, "qom-type"); 150*1195fa2bSMarc-André Lureau if (type && type_opt_predicate && 151*1195fa2bSMarc-André Lureau !type_opt_predicate(type, opts)) { 15290998d58SDaniel P. Berrange return 0; 15390998d58SDaniel P. Berrange } 15490998d58SDaniel P. Berrange 15551b9b478SMarkus Armbruster obj = user_creatable_add_opts(opts, &err); 15690998d58SDaniel P. Berrange if (!obj) { 15751b9b478SMarkus Armbruster error_report_err(err); 15890998d58SDaniel P. Berrange return -1; 15990998d58SDaniel P. Berrange } 16090998d58SDaniel P. Berrange object_unref(obj); 16190998d58SDaniel P. Berrange return 0; 16290998d58SDaniel P. Berrange } 16390998d58SDaniel P. Berrange 16490998d58SDaniel P. Berrange 16590998d58SDaniel P. Berrange void user_creatable_del(const char *id, Error **errp) 16690998d58SDaniel P. Berrange { 16790998d58SDaniel P. Berrange Object *container; 16890998d58SDaniel P. Berrange Object *obj; 16990998d58SDaniel P. Berrange 17090998d58SDaniel P. Berrange container = object_get_objects_root(); 17190998d58SDaniel P. Berrange obj = object_resolve_path_component(container, id); 17290998d58SDaniel P. Berrange if (!obj) { 17390998d58SDaniel P. Berrange error_setg(errp, "object '%s' not found", id); 17490998d58SDaniel P. Berrange return; 17590998d58SDaniel P. Berrange } 17690998d58SDaniel P. Berrange 1773beacfb9SEduardo Habkost if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) { 17890998d58SDaniel P. Berrange error_setg(errp, "object '%s' is in use, can not be deleted", id); 17990998d58SDaniel P. Berrange return; 18090998d58SDaniel P. Berrange } 181c645d5acSMichael Roth 182c645d5acSMichael Roth /* 183c645d5acSMichael Roth * if object was defined on the command-line, remove its corresponding 184c645d5acSMichael Roth * option group entry 185c645d5acSMichael Roth */ 186c645d5acSMichael Roth qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort), 187c645d5acSMichael Roth id)); 188c645d5acSMichael Roth 18990998d58SDaniel P. Berrange object_unparent(obj); 19090998d58SDaniel P. Berrange } 19190998d58SDaniel P. Berrange 1929d5139e5SEduardo Habkost void user_creatable_cleanup(void) 1939d5139e5SEduardo Habkost { 1949d5139e5SEduardo Habkost object_unparent(object_get_objects_root()); 1959d5139e5SEduardo Habkost } 1969d5139e5SEduardo Habkost 197269e09f3SIgor Mammedov static void register_types(void) 198269e09f3SIgor Mammedov { 199269e09f3SIgor Mammedov static const TypeInfo uc_interface_info = { 200269e09f3SIgor Mammedov .name = TYPE_USER_CREATABLE, 201269e09f3SIgor Mammedov .parent = TYPE_INTERFACE, 202269e09f3SIgor Mammedov .class_size = sizeof(UserCreatableClass), 203269e09f3SIgor Mammedov }; 204269e09f3SIgor Mammedov 205269e09f3SIgor Mammedov type_register_static(&uc_interface_info); 206269e09f3SIgor Mammedov } 207269e09f3SIgor Mammedov 208269e09f3SIgor Mammedov type_init(register_types) 209