xref: /qemu/qom/object_interfaces.c (revision db57fef1)
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