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 113650b2deSMarc-André Lureau void user_creatable_complete(UserCreatable *uc, Error **errp) 12269e09f3SIgor Mammedov { 133650b2deSMarc-André Lureau UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc); 14269e09f3SIgor Mammedov 15269e09f3SIgor Mammedov if (ucc->complete) { 16269e09f3SIgor Mammedov ucc->complete(uc, errp); 17269e09f3SIgor Mammedov } 18269e09f3SIgor Mammedov } 19269e09f3SIgor Mammedov 203beacfb9SEduardo Habkost bool user_creatable_can_be_deleted(UserCreatable *uc) 21d6edb155SLin Ma { 22d6edb155SLin Ma 23d6edb155SLin Ma UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc); 24d6edb155SLin Ma 25d6edb155SLin Ma if (ucc->can_be_deleted) { 263beacfb9SEduardo Habkost return ucc->can_be_deleted(uc); 27d6edb155SLin Ma } else { 28d6edb155SLin Ma return true; 29d6edb155SLin Ma } 30d6edb155SLin Ma } 31d6edb155SLin Ma 3290998d58SDaniel P. Berrange Object *user_creatable_add_type(const char *type, const char *id, 3390998d58SDaniel P. Berrange const QDict *qdict, 3490998d58SDaniel P. Berrange Visitor *v, Error **errp) 3590998d58SDaniel P. Berrange { 3690998d58SDaniel P. Berrange Object *obj; 3790998d58SDaniel P. Berrange ObjectClass *klass; 3890998d58SDaniel P. Berrange const QDictEntry *e; 3990998d58SDaniel P. Berrange Error *local_err = NULL; 4090998d58SDaniel P. Berrange 4190998d58SDaniel P. Berrange klass = object_class_by_name(type); 4290998d58SDaniel P. Berrange if (!klass) { 4390998d58SDaniel P. Berrange error_setg(errp, "invalid object type: %s", type); 4490998d58SDaniel P. Berrange return NULL; 4590998d58SDaniel P. Berrange } 4690998d58SDaniel P. Berrange 4790998d58SDaniel P. Berrange if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) { 4890998d58SDaniel P. Berrange error_setg(errp, "object type '%s' isn't supported by object-add", 4990998d58SDaniel P. Berrange type); 5090998d58SDaniel P. Berrange return NULL; 5190998d58SDaniel P. Berrange } 5290998d58SDaniel P. Berrange 5390998d58SDaniel P. Berrange if (object_class_is_abstract(klass)) { 5490998d58SDaniel P. Berrange error_setg(errp, "object type '%s' is abstract", type); 5590998d58SDaniel P. Berrange return NULL; 5690998d58SDaniel P. Berrange } 5790998d58SDaniel P. Berrange 58ad739706SEric Blake assert(qdict); 5990998d58SDaniel P. Berrange obj = object_new(type); 60ad739706SEric Blake visit_start_struct(v, NULL, NULL, 0, &local_err); 6190998d58SDaniel P. Berrange if (local_err) { 6290998d58SDaniel P. Berrange goto out; 6390998d58SDaniel P. Berrange } 64ad739706SEric Blake for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { 65ad739706SEric Blake object_property_set(obj, v, e->key, &local_err); 66ad739706SEric Blake if (local_err) { 67ad739706SEric Blake break; 6890998d58SDaniel P. Berrange } 6990998d58SDaniel P. Berrange } 7015c2f669SEric Blake if (!local_err) { 7115c2f669SEric Blake visit_check_struct(v, &local_err); 7215c2f669SEric Blake } 731158bb2aSEric Blake visit_end_struct(v, NULL); 74ad739706SEric Blake if (local_err) { 75ad739706SEric Blake goto out; 76ad739706SEric Blake } 7790998d58SDaniel P. Berrange 78*6134d752SDaniel P. Berrangé if (id != NULL) { 7990998d58SDaniel P. Berrange object_property_add_child(object_get_objects_root(), 8090998d58SDaniel P. Berrange id, obj, &local_err); 8190998d58SDaniel P. Berrange if (local_err) { 8290998d58SDaniel P. Berrange goto out; 8390998d58SDaniel P. Berrange } 84*6134d752SDaniel P. Berrangé } 8590998d58SDaniel P. Berrange 863650b2deSMarc-André Lureau user_creatable_complete(USER_CREATABLE(obj), &local_err); 8790998d58SDaniel P. Berrange if (local_err) { 88*6134d752SDaniel P. Berrangé if (id != NULL) { 8990998d58SDaniel P. Berrange object_property_del(object_get_objects_root(), 9090998d58SDaniel P. Berrange id, &error_abort); 91*6134d752SDaniel P. Berrangé } 9290998d58SDaniel P. Berrange goto out; 9390998d58SDaniel P. Berrange } 9490998d58SDaniel P. Berrange out: 9590998d58SDaniel P. Berrange if (local_err) { 9690998d58SDaniel P. Berrange error_propagate(errp, local_err); 9790998d58SDaniel P. Berrange object_unref(obj); 9890998d58SDaniel P. Berrange return NULL; 9990998d58SDaniel P. Berrange } 10090998d58SDaniel P. Berrange return obj; 10190998d58SDaniel P. Berrange } 10290998d58SDaniel P. Berrange 10390998d58SDaniel P. Berrange 10490998d58SDaniel P. Berrange Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) 10590998d58SDaniel P. Berrange { 10609204eacSEric Blake Visitor *v; 10790998d58SDaniel P. Berrange QDict *pdict; 1083a464105SIgor Mammedov Object *obj; 1093a464105SIgor Mammedov const char *id = qemu_opts_id(opts); 1109a6d1acbSEric Blake char *type = qemu_opt_get_del(opts, "qom-type"); 1113a464105SIgor Mammedov 1123a464105SIgor Mammedov if (!type) { 1133a464105SIgor Mammedov error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); 1143a464105SIgor Mammedov return NULL; 1153a464105SIgor Mammedov } 1163a464105SIgor Mammedov if (!id) { 1173a464105SIgor Mammedov error_setg(errp, QERR_MISSING_PARAMETER, "id"); 11808329701SEric Blake qemu_opt_set(opts, "qom-type", type, &error_abort); 1199a6d1acbSEric Blake g_free(type); 1203a464105SIgor Mammedov return NULL; 1213a464105SIgor Mammedov } 1223a464105SIgor Mammedov 1239a6d1acbSEric Blake qemu_opts_set_id(opts, NULL); 1243a464105SIgor Mammedov pdict = qemu_opts_to_qdict(opts, NULL); 12590998d58SDaniel P. Berrange 12609204eacSEric Blake v = opts_visitor_new(opts); 1273a464105SIgor Mammedov obj = user_creatable_add_type(type, id, pdict, v, errp); 12809204eacSEric Blake visit_free(v); 1293a464105SIgor Mammedov 1309a6d1acbSEric Blake qemu_opts_set_id(opts, (char *) id); 13108329701SEric Blake qemu_opt_set(opts, "qom-type", type, &error_abort); 1329a6d1acbSEric Blake g_free(type); 133cb3e7f08SMarc-André Lureau qobject_unref(pdict); 13490998d58SDaniel P. Berrange return obj; 13590998d58SDaniel P. Berrange } 13690998d58SDaniel P. Berrange 13790998d58SDaniel P. Berrange 13890998d58SDaniel P. Berrange int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) 13990998d58SDaniel P. Berrange { 1401195fa2bSMarc-André Lureau bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque; 14190998d58SDaniel P. Berrange Object *obj = NULL; 14290998d58SDaniel P. Berrange const char *type; 14390998d58SDaniel P. Berrange 14490998d58SDaniel P. Berrange type = qemu_opt_get(opts, "qom-type"); 1451195fa2bSMarc-André Lureau if (type && type_opt_predicate && 1461195fa2bSMarc-André Lureau !type_opt_predicate(type, opts)) { 14790998d58SDaniel P. Berrange return 0; 14890998d58SDaniel P. Berrange } 14990998d58SDaniel P. Berrange 1507e1e0c11SMarkus Armbruster obj = user_creatable_add_opts(opts, errp); 15190998d58SDaniel P. Berrange if (!obj) { 15290998d58SDaniel P. Berrange return -1; 15390998d58SDaniel P. Berrange } 15490998d58SDaniel P. Berrange object_unref(obj); 15590998d58SDaniel P. Berrange return 0; 15690998d58SDaniel P. Berrange } 15790998d58SDaniel P. Berrange 15890998d58SDaniel P. Berrange 15990998d58SDaniel P. Berrange void user_creatable_del(const char *id, Error **errp) 16090998d58SDaniel P. Berrange { 16190998d58SDaniel P. Berrange Object *container; 16290998d58SDaniel P. Berrange Object *obj; 16390998d58SDaniel P. Berrange 16490998d58SDaniel P. Berrange container = object_get_objects_root(); 16590998d58SDaniel P. Berrange obj = object_resolve_path_component(container, id); 16690998d58SDaniel P. Berrange if (!obj) { 16790998d58SDaniel P. Berrange error_setg(errp, "object '%s' not found", id); 16890998d58SDaniel P. Berrange return; 16990998d58SDaniel P. Berrange } 17090998d58SDaniel P. Berrange 1713beacfb9SEduardo Habkost if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) { 17290998d58SDaniel P. Berrange error_setg(errp, "object '%s' is in use, can not be deleted", id); 17390998d58SDaniel P. Berrange return; 17490998d58SDaniel P. Berrange } 175c645d5acSMichael Roth 176c645d5acSMichael Roth /* 177c645d5acSMichael Roth * if object was defined on the command-line, remove its corresponding 178c645d5acSMichael Roth * option group entry 179c645d5acSMichael Roth */ 180c645d5acSMichael Roth qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort), 181c645d5acSMichael Roth id)); 182c645d5acSMichael Roth 18390998d58SDaniel P. Berrange object_unparent(obj); 18490998d58SDaniel P. Berrange } 18590998d58SDaniel P. Berrange 1869d5139e5SEduardo Habkost void user_creatable_cleanup(void) 1879d5139e5SEduardo Habkost { 1889d5139e5SEduardo Habkost object_unparent(object_get_objects_root()); 1899d5139e5SEduardo Habkost } 1909d5139e5SEduardo Habkost 191269e09f3SIgor Mammedov static void register_types(void) 192269e09f3SIgor Mammedov { 193269e09f3SIgor Mammedov static const TypeInfo uc_interface_info = { 194269e09f3SIgor Mammedov .name = TYPE_USER_CREATABLE, 195269e09f3SIgor Mammedov .parent = TYPE_INTERFACE, 196269e09f3SIgor Mammedov .class_size = sizeof(UserCreatableClass), 197269e09f3SIgor Mammedov }; 198269e09f3SIgor Mammedov 199269e09f3SIgor Mammedov type_register_static(&uc_interface_info); 200269e09f3SIgor Mammedov } 201269e09f3SIgor Mammedov 202269e09f3SIgor Mammedov type_init(register_types) 203