19bbc853bSPeter Maydell #include "qemu/osdep.h" 23e9297f3SKevin Wolf 33e9297f3SKevin Wolf #include "qemu/cutils.h" 4da34e65cSMarkus Armbruster #include "qapi/error.h" 5452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 60dd13589SMarkus Armbruster #include "qapi/qmp/qerror.h" 74df81616SMarc-André Lureau #include "qapi/qmp/qjson.h" 84df81616SMarc-André Lureau #include "qapi/qmp/qstring.h" 9d6a5beebSKevin Wolf #include "qapi/qobject-input-visitor.h" 10269e09f3SIgor Mammedov #include "qom/object_interfaces.h" 113e9297f3SKevin Wolf #include "qemu/help_option.h" 12269e09f3SIgor Mammedov #include "qemu/module.h" 13922a01a0SMarkus Armbruster #include "qemu/option.h" 1490998d58SDaniel P. Berrange #include "qapi/opts-visitor.h" 15c645d5acSMichael Roth #include "qemu/config-file.h" 16269e09f3SIgor Mammedov 176fd5bef1SMarkus Armbruster bool user_creatable_complete(UserCreatable *uc, Error **errp) 18269e09f3SIgor Mammedov { 193650b2deSMarc-André Lureau UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc); 206fd5bef1SMarkus Armbruster Error *err = NULL; 21269e09f3SIgor Mammedov 22269e09f3SIgor Mammedov if (ucc->complete) { 236fd5bef1SMarkus Armbruster ucc->complete(uc, &err); 246fd5bef1SMarkus Armbruster error_propagate(errp, err); 25269e09f3SIgor Mammedov } 266fd5bef1SMarkus Armbruster return !err; 27269e09f3SIgor Mammedov } 28269e09f3SIgor Mammedov 293beacfb9SEduardo Habkost bool user_creatable_can_be_deleted(UserCreatable *uc) 30d6edb155SLin Ma { 31d6edb155SLin Ma 32d6edb155SLin Ma UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc); 33d6edb155SLin Ma 34d6edb155SLin Ma if (ucc->can_be_deleted) { 353beacfb9SEduardo Habkost return ucc->can_be_deleted(uc); 36d6edb155SLin Ma } else { 37d6edb155SLin Ma return true; 38d6edb155SLin Ma } 39d6edb155SLin Ma } 40d6edb155SLin Ma 4190998d58SDaniel P. Berrange Object *user_creatable_add_type(const char *type, const char *id, 4290998d58SDaniel P. Berrange const QDict *qdict, 4390998d58SDaniel P. Berrange Visitor *v, Error **errp) 4490998d58SDaniel P. Berrange { 4590998d58SDaniel P. Berrange Object *obj; 4690998d58SDaniel P. Berrange ObjectClass *klass; 4790998d58SDaniel P. Berrange const QDictEntry *e; 4890998d58SDaniel P. Berrange Error *local_err = NULL; 4990998d58SDaniel P. Berrange 5090998d58SDaniel P. Berrange klass = object_class_by_name(type); 5190998d58SDaniel P. Berrange if (!klass) { 5290998d58SDaniel P. Berrange error_setg(errp, "invalid object type: %s", type); 5390998d58SDaniel P. Berrange return NULL; 5490998d58SDaniel P. Berrange } 5590998d58SDaniel P. Berrange 5690998d58SDaniel P. Berrange if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) { 5790998d58SDaniel P. Berrange error_setg(errp, "object type '%s' isn't supported by object-add", 5890998d58SDaniel P. Berrange type); 5990998d58SDaniel P. Berrange return NULL; 6090998d58SDaniel P. Berrange } 6190998d58SDaniel P. Berrange 6290998d58SDaniel P. Berrange if (object_class_is_abstract(klass)) { 6390998d58SDaniel P. Berrange error_setg(errp, "object type '%s' is abstract", type); 6490998d58SDaniel P. Berrange return NULL; 6590998d58SDaniel P. Berrange } 6690998d58SDaniel P. Berrange 67ad739706SEric Blake assert(qdict); 6890998d58SDaniel P. Berrange obj = object_new(type); 6962a35aaaSMarkus Armbruster if (!visit_start_struct(v, NULL, NULL, 0, &local_err)) { 7090998d58SDaniel P. Berrange goto out; 7190998d58SDaniel P. Berrange } 72ad739706SEric Blake for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { 73778a2dc5SMarkus Armbruster if (!object_property_set(obj, e->key, v, &local_err)) { 74ad739706SEric Blake break; 7590998d58SDaniel P. Berrange } 7690998d58SDaniel P. Berrange } 7715c2f669SEric Blake if (!local_err) { 7815c2f669SEric Blake visit_check_struct(v, &local_err); 7915c2f669SEric Blake } 801158bb2aSEric Blake visit_end_struct(v, NULL); 81ad739706SEric Blake if (local_err) { 82ad739706SEric Blake goto out; 83ad739706SEric Blake } 8490998d58SDaniel P. Berrange 856134d752SDaniel P. Berrangé if (id != NULL) { 86*db57fef1SEric Auger object_property_try_add_child(object_get_objects_root(), 87*db57fef1SEric Auger id, obj, &local_err); 88*db57fef1SEric Auger if (local_err) { 89*db57fef1SEric Auger goto out; 90*db57fef1SEric Auger } 916134d752SDaniel P. Berrangé } 9290998d58SDaniel P. Berrange 93778a2dc5SMarkus Armbruster if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) { 946134d752SDaniel P. Berrangé if (id != NULL) { 95df4fe0b2SMarkus Armbruster object_property_del(object_get_objects_root(), id); 966134d752SDaniel P. Berrangé } 9790998d58SDaniel P. Berrange goto out; 9890998d58SDaniel P. Berrange } 9990998d58SDaniel P. Berrange out: 10090998d58SDaniel P. Berrange if (local_err) { 10190998d58SDaniel P. Berrange error_propagate(errp, local_err); 10290998d58SDaniel P. Berrange object_unref(obj); 10390998d58SDaniel P. Berrange return NULL; 10490998d58SDaniel P. Berrange } 10590998d58SDaniel P. Berrange return obj; 10690998d58SDaniel P. Berrange } 10790998d58SDaniel P. Berrange 1086fd5bef1SMarkus Armbruster bool user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp) 109d6a5beebSKevin Wolf { 110d6a5beebSKevin Wolf Visitor *v; 111d6a5beebSKevin Wolf Object *obj; 112d6a5beebSKevin Wolf g_autofree char *type = NULL; 113d6a5beebSKevin Wolf g_autofree char *id = NULL; 114d6a5beebSKevin Wolf 115d6a5beebSKevin Wolf type = g_strdup(qdict_get_try_str(qdict, "qom-type")); 116d6a5beebSKevin Wolf if (!type) { 117d6a5beebSKevin Wolf error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); 1186fd5bef1SMarkus Armbruster return false; 119d6a5beebSKevin Wolf } 120d6a5beebSKevin Wolf qdict_del(qdict, "qom-type"); 121d6a5beebSKevin Wolf 122d6a5beebSKevin Wolf id = g_strdup(qdict_get_try_str(qdict, "id")); 123d6a5beebSKevin Wolf if (!id) { 124d6a5beebSKevin Wolf error_setg(errp, QERR_MISSING_PARAMETER, "id"); 1256fd5bef1SMarkus Armbruster return false; 126d6a5beebSKevin Wolf } 127d6a5beebSKevin Wolf qdict_del(qdict, "id"); 128d6a5beebSKevin Wolf 129eaae29efSKevin Wolf if (keyval) { 130eaae29efSKevin Wolf v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); 131eaae29efSKevin Wolf } else { 132d6a5beebSKevin Wolf v = qobject_input_visitor_new(QOBJECT(qdict)); 133eaae29efSKevin Wolf } 134d6a5beebSKevin Wolf obj = user_creatable_add_type(type, id, qdict, v, errp); 135d6a5beebSKevin Wolf visit_free(v); 136d6a5beebSKevin Wolf object_unref(obj); 1376fd5bef1SMarkus Armbruster return !!obj; 138d6a5beebSKevin Wolf } 13990998d58SDaniel P. Berrange 14090998d58SDaniel P. Berrange Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) 14190998d58SDaniel P. Berrange { 14209204eacSEric Blake Visitor *v; 14390998d58SDaniel P. Berrange QDict *pdict; 1443a464105SIgor Mammedov Object *obj; 1453a464105SIgor Mammedov const char *id = qemu_opts_id(opts); 1469a6d1acbSEric Blake char *type = qemu_opt_get_del(opts, "qom-type"); 1473a464105SIgor Mammedov 1483a464105SIgor Mammedov if (!type) { 1493a464105SIgor Mammedov error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); 1503a464105SIgor Mammedov return NULL; 1513a464105SIgor Mammedov } 1523a464105SIgor Mammedov if (!id) { 1533a464105SIgor Mammedov error_setg(errp, QERR_MISSING_PARAMETER, "id"); 15408329701SEric Blake qemu_opt_set(opts, "qom-type", type, &error_abort); 1559a6d1acbSEric Blake g_free(type); 1563a464105SIgor Mammedov return NULL; 1573a464105SIgor Mammedov } 1583a464105SIgor Mammedov 1599a6d1acbSEric Blake qemu_opts_set_id(opts, NULL); 1603a464105SIgor Mammedov pdict = qemu_opts_to_qdict(opts, NULL); 16190998d58SDaniel P. Berrange 16209204eacSEric Blake v = opts_visitor_new(opts); 1633a464105SIgor Mammedov obj = user_creatable_add_type(type, id, pdict, v, errp); 16409204eacSEric Blake visit_free(v); 1653a464105SIgor Mammedov 1669a6d1acbSEric Blake qemu_opts_set_id(opts, (char *) id); 16708329701SEric Blake qemu_opt_set(opts, "qom-type", type, &error_abort); 1689a6d1acbSEric Blake g_free(type); 169cb3e7f08SMarc-André Lureau qobject_unref(pdict); 17090998d58SDaniel P. Berrange return obj; 17190998d58SDaniel P. Berrange } 17290998d58SDaniel P. Berrange 17390998d58SDaniel P. Berrange 17490998d58SDaniel P. Berrange int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) 17590998d58SDaniel P. Berrange { 1761195fa2bSMarc-André Lureau bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque; 17790998d58SDaniel P. Berrange Object *obj = NULL; 17890998d58SDaniel P. Berrange const char *type; 17990998d58SDaniel P. Berrange 18090998d58SDaniel P. Berrange type = qemu_opt_get(opts, "qom-type"); 1811195fa2bSMarc-André Lureau if (type && type_opt_predicate && 1821195fa2bSMarc-André Lureau !type_opt_predicate(type, opts)) { 18390998d58SDaniel P. Berrange return 0; 18490998d58SDaniel P. Berrange } 18590998d58SDaniel P. Berrange 1867e1e0c11SMarkus Armbruster obj = user_creatable_add_opts(opts, errp); 18790998d58SDaniel P. Berrange if (!obj) { 18890998d58SDaniel P. Berrange return -1; 18990998d58SDaniel P. Berrange } 19090998d58SDaniel P. Berrange object_unref(obj); 19190998d58SDaniel P. Berrange return 0; 19290998d58SDaniel P. Berrange } 19390998d58SDaniel P. Berrange 1944df81616SMarc-André Lureau char *object_property_help(const char *name, const char *type, 1954df81616SMarc-André Lureau QObject *defval, const char *description) 1964df81616SMarc-André Lureau { 1974df81616SMarc-André Lureau GString *str = g_string_new(NULL); 1984df81616SMarc-André Lureau 1994df81616SMarc-André Lureau g_string_append_printf(str, " %s=<%s>", name, type); 2004df81616SMarc-André Lureau if (description || defval) { 2014df81616SMarc-André Lureau if (str->len < 24) { 2024df81616SMarc-André Lureau g_string_append_printf(str, "%*s", 24 - (int)str->len, ""); 2034df81616SMarc-André Lureau } 2044df81616SMarc-André Lureau g_string_append(str, " - "); 2054df81616SMarc-André Lureau } 2064df81616SMarc-André Lureau if (description) { 2074df81616SMarc-André Lureau g_string_append(str, description); 2084df81616SMarc-André Lureau } 2094df81616SMarc-André Lureau if (defval) { 2104df81616SMarc-André Lureau g_autofree char *def_json = qstring_free(qobject_to_json(defval), TRUE); 2114df81616SMarc-André Lureau g_string_append_printf(str, " (default: %s)", def_json); 2124df81616SMarc-André Lureau } 2134df81616SMarc-André Lureau 2144df81616SMarc-André Lureau return g_string_free(str, false); 2154df81616SMarc-André Lureau } 2164df81616SMarc-André Lureau 2173e9297f3SKevin Wolf bool user_creatable_print_help(const char *type, QemuOpts *opts) 2183e9297f3SKevin Wolf { 2193e9297f3SKevin Wolf ObjectClass *klass; 2203e9297f3SKevin Wolf 2213e9297f3SKevin Wolf if (is_help_option(type)) { 2223e9297f3SKevin Wolf GSList *l, *list; 2233e9297f3SKevin Wolf 2243e9297f3SKevin Wolf printf("List of user creatable objects:\n"); 2253e9297f3SKevin Wolf list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false); 2263e9297f3SKevin Wolf for (l = list; l != NULL; l = l->next) { 2273e9297f3SKevin Wolf ObjectClass *oc = OBJECT_CLASS(l->data); 2283e9297f3SKevin Wolf printf(" %s\n", object_class_get_name(oc)); 2293e9297f3SKevin Wolf } 2303e9297f3SKevin Wolf g_slist_free(list); 2313e9297f3SKevin Wolf return true; 2323e9297f3SKevin Wolf } 2333e9297f3SKevin Wolf 2343e9297f3SKevin Wolf klass = object_class_by_name(type); 2353e9297f3SKevin Wolf if (klass && qemu_opt_has_help_opt(opts)) { 2363e9297f3SKevin Wolf ObjectPropertyIterator iter; 2373e9297f3SKevin Wolf ObjectProperty *prop; 2383e9297f3SKevin Wolf GPtrArray *array = g_ptr_array_new(); 2393e9297f3SKevin Wolf int i; 2403e9297f3SKevin Wolf 2413e9297f3SKevin Wolf object_class_property_iter_init(&iter, klass); 2423e9297f3SKevin Wolf while ((prop = object_property_iter_next(&iter))) { 2433e9297f3SKevin Wolf if (!prop->set) { 2443e9297f3SKevin Wolf continue; 2453e9297f3SKevin Wolf } 2463e9297f3SKevin Wolf 2474df81616SMarc-André Lureau g_ptr_array_add(array, 2484df81616SMarc-André Lureau object_property_help(prop->name, prop->type, 2494df81616SMarc-André Lureau prop->defval, prop->description)); 2503e9297f3SKevin Wolf } 2513e9297f3SKevin Wolf g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0); 2523e9297f3SKevin Wolf if (array->len > 0) { 2533e9297f3SKevin Wolf printf("%s options:\n", type); 2543e9297f3SKevin Wolf } else { 2553e9297f3SKevin Wolf printf("There are no options for %s.\n", type); 2563e9297f3SKevin Wolf } 2573e9297f3SKevin Wolf for (i = 0; i < array->len; i++) { 2583e9297f3SKevin Wolf printf("%s\n", (char *)array->pdata[i]); 2593e9297f3SKevin Wolf } 2603e9297f3SKevin Wolf g_ptr_array_set_free_func(array, g_free); 2613e9297f3SKevin Wolf g_ptr_array_free(array, true); 2623e9297f3SKevin Wolf return true; 2633e9297f3SKevin Wolf } 2643e9297f3SKevin Wolf 2653e9297f3SKevin Wolf return false; 2663e9297f3SKevin Wolf } 26790998d58SDaniel P. Berrange 2686fd5bef1SMarkus Armbruster bool user_creatable_del(const char *id, Error **errp) 26990998d58SDaniel P. Berrange { 27090998d58SDaniel P. Berrange Object *container; 27190998d58SDaniel P. Berrange Object *obj; 27290998d58SDaniel P. Berrange 27390998d58SDaniel P. Berrange container = object_get_objects_root(); 27490998d58SDaniel P. Berrange obj = object_resolve_path_component(container, id); 27590998d58SDaniel P. Berrange if (!obj) { 27690998d58SDaniel P. Berrange error_setg(errp, "object '%s' not found", id); 2776fd5bef1SMarkus Armbruster return false; 27890998d58SDaniel P. Berrange } 27990998d58SDaniel P. Berrange 2803beacfb9SEduardo Habkost if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) { 28190998d58SDaniel P. Berrange error_setg(errp, "object '%s' is in use, can not be deleted", id); 2826fd5bef1SMarkus Armbruster return false; 28390998d58SDaniel P. Berrange } 284c645d5acSMichael Roth 285c645d5acSMichael Roth /* 286c645d5acSMichael Roth * if object was defined on the command-line, remove its corresponding 287c645d5acSMichael Roth * option group entry 288c645d5acSMichael Roth */ 289c645d5acSMichael Roth qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort), 290c645d5acSMichael Roth id)); 291c645d5acSMichael Roth 29290998d58SDaniel P. Berrange object_unparent(obj); 2936fd5bef1SMarkus Armbruster return true; 29490998d58SDaniel P. Berrange } 29590998d58SDaniel P. Berrange 2969d5139e5SEduardo Habkost void user_creatable_cleanup(void) 2979d5139e5SEduardo Habkost { 2989d5139e5SEduardo Habkost object_unparent(object_get_objects_root()); 2999d5139e5SEduardo Habkost } 3009d5139e5SEduardo Habkost 301269e09f3SIgor Mammedov static void register_types(void) 302269e09f3SIgor Mammedov { 303269e09f3SIgor Mammedov static const TypeInfo uc_interface_info = { 304269e09f3SIgor Mammedov .name = TYPE_USER_CREATABLE, 305269e09f3SIgor Mammedov .parent = TYPE_INTERFACE, 306269e09f3SIgor Mammedov .class_size = sizeof(UserCreatableClass), 307269e09f3SIgor Mammedov }; 308269e09f3SIgor Mammedov 309269e09f3SIgor Mammedov type_register_static(&uc_interface_info); 310269e09f3SIgor Mammedov } 311269e09f3SIgor Mammedov 312269e09f3SIgor Mammedov type_init(register_types) 313