xref: /qemu/qom/object_interfaces.c (revision e0c7de8d)
19bbc853bSPeter Maydell #include "qemu/osdep.h"
23e9297f3SKevin Wolf 
33e9297f3SKevin Wolf #include "qemu/cutils.h"
4da34e65cSMarkus Armbruster #include "qapi/error.h"
5f3750266SKevin Wolf #include "qapi/qapi-visit-qom.h"
6919a0423SPhilippe Mathieu-Daudé #include "qapi/qmp/qobject.h"
7452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
80dd13589SMarkus Armbruster #include "qapi/qmp/qerror.h"
94df81616SMarc-André Lureau #include "qapi/qmp/qjson.h"
10d6a5beebSKevin Wolf #include "qapi/qobject-input-visitor.h"
11f3750266SKevin Wolf #include "qapi/qobject-output-visitor.h"
12269e09f3SIgor Mammedov #include "qom/object_interfaces.h"
133e9297f3SKevin Wolf #include "qemu/help_option.h"
140bd5a2ebSKevin Wolf #include "qemu/id.h"
15269e09f3SIgor Mammedov #include "qemu/module.h"
16922a01a0SMarkus Armbruster #include "qemu/option.h"
17da0a932bSKevin Wolf #include "qemu/qemu-print.h"
1890998d58SDaniel P. Berrange #include "qapi/opts-visitor.h"
19c645d5acSMichael Roth #include "qemu/config-file.h"
209ca9c893SMarc-André Lureau #include "qemu/keyval.h"
21269e09f3SIgor Mammedov 
user_creatable_complete(UserCreatable * uc,Error ** errp)226fd5bef1SMarkus Armbruster bool user_creatable_complete(UserCreatable *uc, Error **errp)
23269e09f3SIgor Mammedov {
243650b2deSMarc-André Lureau     UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
256fd5bef1SMarkus Armbruster     Error *err = NULL;
26269e09f3SIgor Mammedov 
27269e09f3SIgor Mammedov     if (ucc->complete) {
286fd5bef1SMarkus Armbruster         ucc->complete(uc, &err);
296fd5bef1SMarkus Armbruster         error_propagate(errp, err);
30269e09f3SIgor Mammedov     }
316fd5bef1SMarkus Armbruster     return !err;
32269e09f3SIgor Mammedov }
33269e09f3SIgor Mammedov 
user_creatable_can_be_deleted(UserCreatable * uc)343beacfb9SEduardo Habkost bool user_creatable_can_be_deleted(UserCreatable *uc)
35d6edb155SLin Ma {
36d6edb155SLin Ma 
37d6edb155SLin Ma     UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
38d6edb155SLin Ma 
39d6edb155SLin Ma     if (ucc->can_be_deleted) {
403beacfb9SEduardo Habkost         return ucc->can_be_deleted(uc);
41d6edb155SLin Ma     } else {
42d6edb155SLin Ma         return true;
43d6edb155SLin Ma     }
44d6edb155SLin Ma }
45d6edb155SLin Ma 
object_set_properties_from_qdict(Object * obj,const QDict * qdict,Visitor * v,Error ** errp)463bb69445SPaolo Bonzini static void object_set_properties_from_qdict(Object *obj, const QDict *qdict,
473bb69445SPaolo Bonzini                                              Visitor *v, Error **errp)
483bb69445SPaolo Bonzini {
493bb69445SPaolo Bonzini     const QDictEntry *e;
503bb69445SPaolo Bonzini 
51dbc8221fSKevin Wolf     if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
52dbc8221fSKevin Wolf         return;
533bb69445SPaolo Bonzini     }
543bb69445SPaolo Bonzini     for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
55dbc8221fSKevin Wolf         if (!object_property_set(obj, e->key, v, errp)) {
56dbc8221fSKevin Wolf             goto out;
573bb69445SPaolo Bonzini         }
583bb69445SPaolo Bonzini     }
59dbc8221fSKevin Wolf     visit_check_struct(v, errp);
603bb69445SPaolo Bonzini out:
61dbc8221fSKevin Wolf     visit_end_struct(v, NULL);
623bb69445SPaolo Bonzini }
633bb69445SPaolo Bonzini 
object_set_properties_from_keyval(Object * obj,const QDict * qdict,bool from_json,Error ** errp)643bb69445SPaolo Bonzini void object_set_properties_from_keyval(Object *obj, const QDict *qdict,
653bb69445SPaolo Bonzini                                        bool from_json, Error **errp)
663bb69445SPaolo Bonzini {
673bb69445SPaolo Bonzini     Visitor *v;
683bb69445SPaolo Bonzini     if (from_json) {
693bb69445SPaolo Bonzini         v = qobject_input_visitor_new(QOBJECT(qdict));
703bb69445SPaolo Bonzini     } else {
713bb69445SPaolo Bonzini         v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
723bb69445SPaolo Bonzini     }
733bb69445SPaolo Bonzini     object_set_properties_from_qdict(obj, qdict, v, errp);
743bb69445SPaolo Bonzini     visit_free(v);
753bb69445SPaolo Bonzini }
763bb69445SPaolo Bonzini 
user_creatable_add_type(const char * type,const char * id,const QDict * qdict,Visitor * v,Error ** errp)7790998d58SDaniel P. Berrange Object *user_creatable_add_type(const char *type, const char *id,
7890998d58SDaniel P. Berrange                                 const QDict *qdict,
7990998d58SDaniel P. Berrange                                 Visitor *v, Error **errp)
8090998d58SDaniel P. Berrange {
810bd5a2ebSKevin Wolf     ERRP_GUARD();
8290998d58SDaniel P. Berrange     Object *obj;
8390998d58SDaniel P. Berrange     ObjectClass *klass;
8490998d58SDaniel P. Berrange     Error *local_err = NULL;
8590998d58SDaniel P. Berrange 
860bd5a2ebSKevin Wolf     if (id != NULL && !id_wellformed(id)) {
870bd5a2ebSKevin Wolf         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
880bd5a2ebSKevin Wolf         error_append_hint(errp, "Identifiers consist of letters, digits, "
890bd5a2ebSKevin Wolf                           "'-', '.', '_', starting with a letter.\n");
900bd5a2ebSKevin Wolf         return NULL;
910bd5a2ebSKevin Wolf     }
920bd5a2ebSKevin Wolf 
9390998d58SDaniel P. Berrange     klass = object_class_by_name(type);
9490998d58SDaniel P. Berrange     if (!klass) {
9590998d58SDaniel P. Berrange         error_setg(errp, "invalid object type: %s", type);
9690998d58SDaniel P. Berrange         return NULL;
9790998d58SDaniel P. Berrange     }
9890998d58SDaniel P. Berrange 
9990998d58SDaniel P. Berrange     if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
10090998d58SDaniel P. Berrange         error_setg(errp, "object type '%s' isn't supported by object-add",
10190998d58SDaniel P. Berrange                    type);
10290998d58SDaniel P. Berrange         return NULL;
10390998d58SDaniel P. Berrange     }
10490998d58SDaniel P. Berrange 
10590998d58SDaniel P. Berrange     if (object_class_is_abstract(klass)) {
10690998d58SDaniel P. Berrange         error_setg(errp, "object type '%s' is abstract", type);
10790998d58SDaniel P. Berrange         return NULL;
10890998d58SDaniel P. Berrange     }
10990998d58SDaniel P. Berrange 
110ad739706SEric Blake     assert(qdict);
11190998d58SDaniel P. Berrange     obj = object_new(type);
1123bb69445SPaolo Bonzini     object_set_properties_from_qdict(obj, qdict, v, &local_err);
113ad739706SEric Blake     if (local_err) {
114ad739706SEric Blake         goto out;
115ad739706SEric Blake     }
11690998d58SDaniel P. Berrange 
1176134d752SDaniel P. Berrangé     if (id != NULL) {
118db57fef1SEric Auger         object_property_try_add_child(object_get_objects_root(),
119db57fef1SEric Auger                                       id, obj, &local_err);
120db57fef1SEric Auger         if (local_err) {
121db57fef1SEric Auger             goto out;
122db57fef1SEric Auger         }
1236134d752SDaniel P. Berrangé     }
12490998d58SDaniel P. Berrange 
125778a2dc5SMarkus Armbruster     if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) {
1266134d752SDaniel P. Berrangé         if (id != NULL) {
127df4fe0b2SMarkus Armbruster             object_property_del(object_get_objects_root(), id);
1286134d752SDaniel P. Berrangé         }
12990998d58SDaniel P. Berrange         goto out;
13090998d58SDaniel P. Berrange     }
13190998d58SDaniel P. Berrange out:
13290998d58SDaniel P. Berrange     if (local_err) {
13390998d58SDaniel P. Berrange         error_propagate(errp, local_err);
13490998d58SDaniel P. Berrange         object_unref(obj);
13590998d58SDaniel P. Berrange         return NULL;
13690998d58SDaniel P. Berrange     }
13790998d58SDaniel P. Berrange     return obj;
13890998d58SDaniel P. Berrange }
13990998d58SDaniel P. Berrange 
user_creatable_add_qapi(ObjectOptions * options,Error ** errp)140f3750266SKevin Wolf void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
141f3750266SKevin Wolf {
142f3750266SKevin Wolf     Visitor *v;
143f3750266SKevin Wolf     QObject *qobj;
144f3750266SKevin Wolf     QDict *props;
145f3750266SKevin Wolf     Object *obj;
146f3750266SKevin Wolf 
147f3750266SKevin Wolf     v = qobject_output_visitor_new(&qobj);
148f3750266SKevin Wolf     visit_type_ObjectOptions(v, NULL, &options, &error_abort);
149f3750266SKevin Wolf     visit_complete(v, &qobj);
150f3750266SKevin Wolf     visit_free(v);
151f3750266SKevin Wolf 
152f3750266SKevin Wolf     props = qobject_to(QDict, qobj);
153f3750266SKevin Wolf     qdict_del(props, "qom-type");
154f3750266SKevin Wolf     qdict_del(props, "id");
155f3750266SKevin Wolf 
156f3750266SKevin Wolf     v = qobject_input_visitor_new(QOBJECT(props));
157f3750266SKevin Wolf     obj = user_creatable_add_type(ObjectType_str(options->qom_type),
158f3750266SKevin Wolf                                   options->id, props, v, errp);
159f3750266SKevin Wolf     object_unref(obj);
160f3750266SKevin Wolf     qobject_unref(qobj);
161f3750266SKevin Wolf     visit_free(v);
162f3750266SKevin Wolf }
163f3750266SKevin Wolf 
object_property_help(const char * name,const char * type,QObject * defval,const char * description)1644df81616SMarc-André Lureau char *object_property_help(const char *name, const char *type,
1654df81616SMarc-André Lureau                            QObject *defval, const char *description)
1664df81616SMarc-André Lureau {
1674df81616SMarc-André Lureau     GString *str = g_string_new(NULL);
1684df81616SMarc-André Lureau 
1694df81616SMarc-André Lureau     g_string_append_printf(str, "  %s=<%s>", name, type);
1704df81616SMarc-André Lureau     if (description || defval) {
1714df81616SMarc-André Lureau         if (str->len < 24) {
1724df81616SMarc-André Lureau             g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
1734df81616SMarc-André Lureau         }
1744df81616SMarc-André Lureau         g_string_append(str, " - ");
1754df81616SMarc-André Lureau     }
1764df81616SMarc-André Lureau     if (description) {
1774df81616SMarc-André Lureau         g_string_append(str, description);
1784df81616SMarc-André Lureau     }
1794df81616SMarc-André Lureau     if (defval) {
180eab3a467SMarkus Armbruster         g_autofree char *def_json = g_string_free(qobject_to_json(defval),
181bd74ecd1SMarkus Armbruster                                                   false);
1824df81616SMarc-André Lureau         g_string_append_printf(str, " (default: %s)", def_json);
1834df81616SMarc-André Lureau     }
1844df81616SMarc-André Lureau 
1854df81616SMarc-André Lureau     return g_string_free(str, false);
1864df81616SMarc-André Lureau }
1874df81616SMarc-André Lureau 
user_creatable_print_types(void)1880e301d44SKevin Wolf static void user_creatable_print_types(void)
1893e9297f3SKevin Wolf {
1903e9297f3SKevin Wolf     GSList *l, *list;
1913e9297f3SKevin Wolf 
192da0a932bSKevin Wolf     qemu_printf("List of user creatable objects:\n");
1933e9297f3SKevin Wolf     list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
1943e9297f3SKevin Wolf     for (l = list; l != NULL; l = l->next) {
1953e9297f3SKevin Wolf         ObjectClass *oc = OBJECT_CLASS(l->data);
196da0a932bSKevin Wolf         qemu_printf("  %s\n", object_class_get_name(oc));
1973e9297f3SKevin Wolf     }
1983e9297f3SKevin Wolf     g_slist_free(list);
1993e9297f3SKevin Wolf }
2003e9297f3SKevin Wolf 
type_print_class_properties(const char * type)2013bb69445SPaolo Bonzini bool type_print_class_properties(const char *type)
2020e301d44SKevin Wolf {
2030e301d44SKevin Wolf     ObjectClass *klass;
2043e9297f3SKevin Wolf     ObjectPropertyIterator iter;
2053e9297f3SKevin Wolf     ObjectProperty *prop;
2060e301d44SKevin Wolf     GPtrArray *array;
2073e9297f3SKevin Wolf     int i;
2083e9297f3SKevin Wolf 
2090e301d44SKevin Wolf     klass = object_class_by_name(type);
2100e301d44SKevin Wolf     if (!klass) {
2110e301d44SKevin Wolf         return false;
2120e301d44SKevin Wolf     }
2130e301d44SKevin Wolf 
2140e301d44SKevin Wolf     array = g_ptr_array_new();
2153e9297f3SKevin Wolf     object_class_property_iter_init(&iter, klass);
2163e9297f3SKevin Wolf     while ((prop = object_property_iter_next(&iter))) {
2173e9297f3SKevin Wolf         if (!prop->set) {
2183e9297f3SKevin Wolf             continue;
2193e9297f3SKevin Wolf         }
2203e9297f3SKevin Wolf 
2214df81616SMarc-André Lureau         g_ptr_array_add(array,
2224df81616SMarc-André Lureau                         object_property_help(prop->name, prop->type,
2234df81616SMarc-André Lureau                                              prop->defval, prop->description));
2243e9297f3SKevin Wolf     }
2253e9297f3SKevin Wolf     g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
2263e9297f3SKevin Wolf     if (array->len > 0) {
227da0a932bSKevin Wolf         qemu_printf("%s options:\n", type);
2283e9297f3SKevin Wolf     } else {
229da0a932bSKevin Wolf         qemu_printf("There are no options for %s.\n", type);
2303e9297f3SKevin Wolf     }
2313e9297f3SKevin Wolf     for (i = 0; i < array->len; i++) {
232da0a932bSKevin Wolf         qemu_printf("%s\n", (char *)array->pdata[i]);
2333e9297f3SKevin Wolf     }
2343e9297f3SKevin Wolf     g_ptr_array_set_free_func(array, g_free);
2353e9297f3SKevin Wolf     g_ptr_array_free(array, true);
2363e9297f3SKevin Wolf     return true;
2373e9297f3SKevin Wolf }
2383e9297f3SKevin Wolf 
user_creatable_print_help(const char * type,QemuOpts * opts)2390e301d44SKevin Wolf bool user_creatable_print_help(const char *type, QemuOpts *opts)
2400e301d44SKevin Wolf {
2410e301d44SKevin Wolf     if (is_help_option(type)) {
2420e301d44SKevin Wolf         user_creatable_print_types();
2430e301d44SKevin Wolf         return true;
2440e301d44SKevin Wolf     }
2450e301d44SKevin Wolf 
2460e301d44SKevin Wolf     if (qemu_opt_has_help_opt(opts)) {
2473bb69445SPaolo Bonzini         return type_print_class_properties(type);
2480e301d44SKevin Wolf     }
2490e301d44SKevin Wolf 
2503e9297f3SKevin Wolf     return false;
2513e9297f3SKevin Wolf }
25290998d58SDaniel P. Berrange 
user_creatable_print_help_from_qdict(QDict * args)253f3750266SKevin Wolf static void user_creatable_print_help_from_qdict(QDict *args)
254c9ac1458SKevin Wolf {
255c9ac1458SKevin Wolf     const char *type = qdict_get_try_str(args, "qom-type");
256c9ac1458SKevin Wolf 
2573bb69445SPaolo Bonzini     if (!type || !type_print_class_properties(type)) {
258c9ac1458SKevin Wolf         user_creatable_print_types();
259c9ac1458SKevin Wolf     }
260c9ac1458SKevin Wolf }
261c9ac1458SKevin Wolf 
user_creatable_parse_str(const char * str,Error ** errp)262e0c7de8dSPhilippe Mathieu-Daudé ObjectOptions *user_creatable_parse_str(const char *str, Error **errp)
263f3750266SKevin Wolf {
264ffd58ef8SKevin Wolf     ERRP_GUARD();
265155b5f8bSKevin Wolf     QObject *obj;
266f3750266SKevin Wolf     bool help;
267f3750266SKevin Wolf     Visitor *v;
268f3750266SKevin Wolf     ObjectOptions *options;
269f3750266SKevin Wolf 
270e0c7de8dSPhilippe Mathieu-Daudé     if (str[0] == '{') {
271e0c7de8dSPhilippe Mathieu-Daudé         obj = qobject_from_json(str, errp);
272155b5f8bSKevin Wolf         if (!obj) {
273155b5f8bSKevin Wolf             return NULL;
274155b5f8bSKevin Wolf         }
275155b5f8bSKevin Wolf         v = qobject_input_visitor_new(obj);
276155b5f8bSKevin Wolf     } else {
277e0c7de8dSPhilippe Mathieu-Daudé         QDict *args = keyval_parse(str, "qom-type", &help, errp);
278ffd58ef8SKevin Wolf         if (*errp) {
279ddf6dae7SKevin Wolf             return NULL;
280ffd58ef8SKevin Wolf         }
281f3750266SKevin Wolf         if (help) {
282f3750266SKevin Wolf             user_creatable_print_help_from_qdict(args);
283ffd58ef8SKevin Wolf             qobject_unref(args);
284ddf6dae7SKevin Wolf             return NULL;
285f3750266SKevin Wolf         }
286f3750266SKevin Wolf 
287155b5f8bSKevin Wolf         obj = QOBJECT(args);
288155b5f8bSKevin Wolf         v = qobject_input_visitor_new_keyval(obj);
289155b5f8bSKevin Wolf     }
290155b5f8bSKevin Wolf 
291ffd58ef8SKevin Wolf     visit_type_ObjectOptions(v, NULL, &options, errp);
292f3750266SKevin Wolf     visit_free(v);
293155b5f8bSKevin Wolf     qobject_unref(obj);
294f3750266SKevin Wolf 
295ddf6dae7SKevin Wolf     return options;
296ddf6dae7SKevin Wolf }
297ddf6dae7SKevin Wolf 
user_creatable_add_from_str(const char * str,Error ** errp)298e0c7de8dSPhilippe Mathieu-Daudé bool user_creatable_add_from_str(const char *str, Error **errp)
299ddf6dae7SKevin Wolf {
300ddf6dae7SKevin Wolf     ERRP_GUARD();
301ddf6dae7SKevin Wolf     ObjectOptions *options;
302ddf6dae7SKevin Wolf 
303e0c7de8dSPhilippe Mathieu-Daudé     options = user_creatable_parse_str(str, errp);
304ddf6dae7SKevin Wolf     if (!options) {
305ddf6dae7SKevin Wolf         return false;
306ffd58ef8SKevin Wolf     }
307ffd58ef8SKevin Wolf 
308ffd58ef8SKevin Wolf     user_creatable_add_qapi(options, errp);
309f3750266SKevin Wolf     qapi_free_ObjectOptions(options);
310ffd58ef8SKevin Wolf     return !*errp;
311ffd58ef8SKevin Wolf }
312ffd58ef8SKevin Wolf 
user_creatable_process_cmdline(const char * cmdline)313e0c7de8dSPhilippe Mathieu-Daudé void user_creatable_process_cmdline(const char *cmdline)
314ffd58ef8SKevin Wolf {
315e0c7de8dSPhilippe Mathieu-Daudé     if (!user_creatable_add_from_str(cmdline, &error_fatal)) {
316ffd58ef8SKevin Wolf         /* Help was printed */
317ffd58ef8SKevin Wolf         exit(EXIT_SUCCESS);
318ffd58ef8SKevin Wolf     }
319f3750266SKevin Wolf }
320f3750266SKevin Wolf 
user_creatable_del(const char * id,Error ** errp)3216fd5bef1SMarkus Armbruster bool user_creatable_del(const char *id, Error **errp)
32290998d58SDaniel P. Berrange {
32398c43b7bSKevin Wolf     QemuOptsList *opts_list;
32490998d58SDaniel P. Berrange     Object *container;
32590998d58SDaniel P. Berrange     Object *obj;
32690998d58SDaniel P. Berrange 
32790998d58SDaniel P. Berrange     container = object_get_objects_root();
32890998d58SDaniel P. Berrange     obj = object_resolve_path_component(container, id);
32990998d58SDaniel P. Berrange     if (!obj) {
33090998d58SDaniel P. Berrange         error_setg(errp, "object '%s' not found", id);
3316fd5bef1SMarkus Armbruster         return false;
33290998d58SDaniel P. Berrange     }
33390998d58SDaniel P. Berrange 
3343beacfb9SEduardo Habkost     if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
33590998d58SDaniel P. Berrange         error_setg(errp, "object '%s' is in use, can not be deleted", id);
3366fd5bef1SMarkus Armbruster         return false;
33790998d58SDaniel P. Berrange     }
338c645d5acSMichael Roth 
339c645d5acSMichael Roth     /*
340c645d5acSMichael Roth      * if object was defined on the command-line, remove its corresponding
341c645d5acSMichael Roth      * option group entry
342c645d5acSMichael Roth      */
34398c43b7bSKevin Wolf     opts_list = qemu_find_opts_err("object", NULL);
34498c43b7bSKevin Wolf     if (opts_list) {
34598c43b7bSKevin Wolf         qemu_opts_del(qemu_opts_find(opts_list, id));
34698c43b7bSKevin Wolf     }
347c645d5acSMichael Roth 
34890998d58SDaniel P. Berrange     object_unparent(obj);
3496fd5bef1SMarkus Armbruster     return true;
35090998d58SDaniel P. Berrange }
35190998d58SDaniel P. Berrange 
user_creatable_cleanup(void)3529d5139e5SEduardo Habkost void user_creatable_cleanup(void)
3539d5139e5SEduardo Habkost {
3549d5139e5SEduardo Habkost     object_unparent(object_get_objects_root());
3559d5139e5SEduardo Habkost }
3569d5139e5SEduardo Habkost 
register_types(void)357269e09f3SIgor Mammedov static void register_types(void)
358269e09f3SIgor Mammedov {
359269e09f3SIgor Mammedov     static const TypeInfo uc_interface_info = {
360269e09f3SIgor Mammedov         .name          = TYPE_USER_CREATABLE,
361269e09f3SIgor Mammedov         .parent        = TYPE_INTERFACE,
362269e09f3SIgor Mammedov         .class_size = sizeof(UserCreatableClass),
363269e09f3SIgor Mammedov     };
364269e09f3SIgor Mammedov 
365269e09f3SIgor Mammedov     type_register_static(&uc_interface_info);
366269e09f3SIgor Mammedov }
367269e09f3SIgor Mammedov 
368269e09f3SIgor Mammedov type_init(register_types)
369