blob: 7d31589b047cf3486ff877ff0de5fa05717ade4f [file] [log] [blame]
Peter Maydell9bbc8532016-01-29 17:50:02 +00001#include "qemu/osdep.h"
Kevin Wolf3e9297f2019-10-11 19:20:12 +02002
3#include "qemu/cutils.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +01004#include "qapi/error.h"
Kevin Wolff3750262021-02-17 12:06:20 +01005#include "qapi/qapi-visit-qom.h"
Philippe Mathieu-Daudé919a0422022-12-19 14:31:00 +01006#include "qapi/qmp/qobject.h"
Markus Armbruster452fcdb2018-02-01 12:18:39 +01007#include "qapi/qmp/qdict.h"
Markus Armbruster0dd13582018-02-11 10:35:39 +01008#include "qapi/qmp/qerror.h"
Marc-André Lureau4df81612020-01-10 19:30:37 +04009#include "qapi/qmp/qjson.h"
Kevin Wolfd6a5bee2020-04-16 17:04:20 +020010#include "qapi/qobject-input-visitor.h"
Kevin Wolff3750262021-02-17 12:06:20 +010011#include "qapi/qobject-output-visitor.h"
Igor Mammedov269e09f2014-01-16 17:34:38 +010012#include "qom/object_interfaces.h"
Kevin Wolf3e9297f2019-10-11 19:20:12 +020013#include "qemu/help_option.h"
Kevin Wolf0bd5a2e2021-03-02 18:16:23 +010014#include "qemu/id.h"
Igor Mammedov269e09f2014-01-16 17:34:38 +010015#include "qemu/module.h"
Markus Armbruster922a01a2018-02-01 12:18:46 +010016#include "qemu/option.h"
Kevin Wolfda0a9322021-02-17 15:27:54 +010017#include "qemu/qemu-print.h"
Daniel P. Berrange90998d52016-02-10 18:40:59 +000018#include "qapi/opts-visitor.h"
Michael Rothc645d5a2017-06-03 18:13:32 -050019#include "qemu/config-file.h"
Marc-André Lureau9ca9c892022-04-20 17:26:06 +040020#include "qemu/keyval.h"
Igor Mammedov269e09f2014-01-16 17:34:38 +010021
Markus Armbruster6fd5bef2020-07-07 18:05:55 +020022bool user_creatable_complete(UserCreatable *uc, Error **errp)
Igor Mammedov269e09f2014-01-16 17:34:38 +010023{
Marc-André Lureau3650b2d2018-12-04 18:20:07 +040024 UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
Markus Armbruster6fd5bef2020-07-07 18:05:55 +020025 Error *err = NULL;
Igor Mammedov269e09f2014-01-16 17:34:38 +010026
Igor Mammedov269e09f2014-01-16 17:34:38 +010027 if (ucc->complete) {
Markus Armbruster6fd5bef2020-07-07 18:05:55 +020028 ucc->complete(uc, &err);
29 error_propagate(errp, err);
Igor Mammedov269e09f2014-01-16 17:34:38 +010030 }
Markus Armbruster6fd5bef2020-07-07 18:05:55 +020031 return !err;
Igor Mammedov269e09f2014-01-16 17:34:38 +010032}
33
Eduardo Habkost3beacfb2017-08-29 19:03:37 -030034bool user_creatable_can_be_deleted(UserCreatable *uc)
Lin Mad6edb152015-03-30 16:36:28 +080035{
36
37 UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
38
39 if (ucc->can_be_deleted) {
Eduardo Habkost3beacfb2017-08-29 19:03:37 -030040 return ucc->can_be_deleted(uc);
Lin Mad6edb152015-03-30 16:36:28 +080041 } else {
42 return true;
43 }
44}
45
Paolo Bonzini3bb69442020-11-02 11:08:07 -050046static void object_set_properties_from_qdict(Object *obj, const QDict *qdict,
47 Visitor *v, Error **errp)
48{
49 const QDictEntry *e;
Paolo Bonzini3bb69442020-11-02 11:08:07 -050050
Kevin Wolfdbc82212021-10-08 15:34:31 +020051 if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
52 return;
Paolo Bonzini3bb69442020-11-02 11:08:07 -050053 }
54 for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
Kevin Wolfdbc82212021-10-08 15:34:31 +020055 if (!object_property_set(obj, e->key, v, errp)) {
56 goto out;
Paolo Bonzini3bb69442020-11-02 11:08:07 -050057 }
58 }
Kevin Wolfdbc82212021-10-08 15:34:31 +020059 visit_check_struct(v, errp);
Paolo Bonzini3bb69442020-11-02 11:08:07 -050060out:
Kevin Wolfdbc82212021-10-08 15:34:31 +020061 visit_end_struct(v, NULL);
Paolo Bonzini3bb69442020-11-02 11:08:07 -050062}
63
64void object_set_properties_from_keyval(Object *obj, const QDict *qdict,
65 bool from_json, Error **errp)
66{
67 Visitor *v;
68 if (from_json) {
69 v = qobject_input_visitor_new(QOBJECT(qdict));
70 } else {
71 v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
72 }
73 object_set_properties_from_qdict(obj, qdict, v, errp);
74 visit_free(v);
75}
76
Daniel P. Berrange90998d52016-02-10 18:40:59 +000077Object *user_creatable_add_type(const char *type, const char *id,
78 const QDict *qdict,
79 Visitor *v, Error **errp)
80{
Kevin Wolf0bd5a2e2021-03-02 18:16:23 +010081 ERRP_GUARD();
Daniel P. Berrange90998d52016-02-10 18:40:59 +000082 Object *obj;
83 ObjectClass *klass;
Daniel P. Berrange90998d52016-02-10 18:40:59 +000084 Error *local_err = NULL;
85
Kevin Wolf0bd5a2e2021-03-02 18:16:23 +010086 if (id != NULL && !id_wellformed(id)) {
87 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
88 error_append_hint(errp, "Identifiers consist of letters, digits, "
89 "'-', '.', '_', starting with a letter.\n");
90 return NULL;
91 }
92
Daniel P. Berrange90998d52016-02-10 18:40:59 +000093 klass = object_class_by_name(type);
94 if (!klass) {
95 error_setg(errp, "invalid object type: %s", type);
96 return NULL;
97 }
98
99 if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
100 error_setg(errp, "object type '%s' isn't supported by object-add",
101 type);
102 return NULL;
103 }
104
105 if (object_class_is_abstract(klass)) {
106 error_setg(errp, "object type '%s' is abstract", type);
107 return NULL;
108 }
109
Eric Blakead739702016-04-28 15:45:17 -0600110 assert(qdict);
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000111 obj = object_new(type);
Paolo Bonzini3bb69442020-11-02 11:08:07 -0500112 object_set_properties_from_qdict(obj, qdict, v, &local_err);
Eric Blakead739702016-04-28 15:45:17 -0600113 if (local_err) {
114 goto out;
115 }
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000116
Daniel P. Berrangé6134d752018-06-15 16:39:35 +0100117 if (id != NULL) {
Eric Augerdb57fef2020-06-29 21:34:22 +0200118 object_property_try_add_child(object_get_objects_root(),
119 id, obj, &local_err);
120 if (local_err) {
121 goto out;
122 }
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000123 }
124
Markus Armbruster778a2dc2020-07-07 18:05:56 +0200125 if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) {
Daniel P. Berrangé6134d752018-06-15 16:39:35 +0100126 if (id != NULL) {
Markus Armbrusterdf4fe0b2020-05-05 17:29:26 +0200127 object_property_del(object_get_objects_root(), id);
Daniel P. Berrangé6134d752018-06-15 16:39:35 +0100128 }
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000129 goto out;
130 }
131out:
132 if (local_err) {
133 error_propagate(errp, local_err);
134 object_unref(obj);
135 return NULL;
136 }
137 return obj;
138}
139
Kevin Wolff3750262021-02-17 12:06:20 +0100140void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
141{
142 Visitor *v;
143 QObject *qobj;
144 QDict *props;
145 Object *obj;
146
147 v = qobject_output_visitor_new(&qobj);
148 visit_type_ObjectOptions(v, NULL, &options, &error_abort);
149 visit_complete(v, &qobj);
150 visit_free(v);
151
152 props = qobject_to(QDict, qobj);
153 qdict_del(props, "qom-type");
154 qdict_del(props, "id");
155
156 v = qobject_input_visitor_new(QOBJECT(props));
157 obj = user_creatable_add_type(ObjectType_str(options->qom_type),
158 options->id, props, v, errp);
159 object_unref(obj);
160 qobject_unref(qobj);
161 visit_free(v);
162}
163
Marc-André Lureau4df81612020-01-10 19:30:37 +0400164char *object_property_help(const char *name, const char *type,
165 QObject *defval, const char *description)
166{
167 GString *str = g_string_new(NULL);
168
169 g_string_append_printf(str, " %s=<%s>", name, type);
170 if (description || defval) {
171 if (str->len < 24) {
172 g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
173 }
174 g_string_append(str, " - ");
175 }
176 if (description) {
177 g_string_append(str, description);
178 }
179 if (defval) {
Markus Armbrustereab3a462020-12-11 18:11:37 +0100180 g_autofree char *def_json = g_string_free(qobject_to_json(defval),
Markus Armbrusterbd74ecd2021-03-24 09:41:30 +0100181 false);
Marc-André Lureau4df81612020-01-10 19:30:37 +0400182 g_string_append_printf(str, " (default: %s)", def_json);
183 }
184
185 return g_string_free(str, false);
186}
187
Kevin Wolf0e301d42020-10-07 18:49:01 +0200188static void user_creatable_print_types(void)
189{
190 GSList *l, *list;
191
Kevin Wolfda0a9322021-02-17 15:27:54 +0100192 qemu_printf("List of user creatable objects:\n");
Kevin Wolf0e301d42020-10-07 18:49:01 +0200193 list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
194 for (l = list; l != NULL; l = l->next) {
195 ObjectClass *oc = OBJECT_CLASS(l->data);
Kevin Wolfda0a9322021-02-17 15:27:54 +0100196 qemu_printf(" %s\n", object_class_get_name(oc));
Kevin Wolf0e301d42020-10-07 18:49:01 +0200197 }
198 g_slist_free(list);
199}
200
Paolo Bonzini3bb69442020-11-02 11:08:07 -0500201bool type_print_class_properties(const char *type)
Kevin Wolf3e9297f2019-10-11 19:20:12 +0200202{
203 ObjectClass *klass;
Kevin Wolf0e301d42020-10-07 18:49:01 +0200204 ObjectPropertyIterator iter;
205 ObjectProperty *prop;
206 GPtrArray *array;
207 int i;
Kevin Wolf3e9297f2019-10-11 19:20:12 +0200208
Kevin Wolf0e301d42020-10-07 18:49:01 +0200209 klass = object_class_by_name(type);
210 if (!klass) {
211 return false;
212 }
Kevin Wolf3e9297f2019-10-11 19:20:12 +0200213
Kevin Wolf0e301d42020-10-07 18:49:01 +0200214 array = g_ptr_array_new();
215 object_class_property_iter_init(&iter, klass);
216 while ((prop = object_property_iter_next(&iter))) {
217 if (!prop->set) {
218 continue;
Kevin Wolf3e9297f2019-10-11 19:20:12 +0200219 }
Kevin Wolf0e301d42020-10-07 18:49:01 +0200220
221 g_ptr_array_add(array,
222 object_property_help(prop->name, prop->type,
223 prop->defval, prop->description));
224 }
225 g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
226 if (array->len > 0) {
Kevin Wolfda0a9322021-02-17 15:27:54 +0100227 qemu_printf("%s options:\n", type);
Kevin Wolf0e301d42020-10-07 18:49:01 +0200228 } else {
Kevin Wolfda0a9322021-02-17 15:27:54 +0100229 qemu_printf("There are no options for %s.\n", type);
Kevin Wolf0e301d42020-10-07 18:49:01 +0200230 }
231 for (i = 0; i < array->len; i++) {
Kevin Wolfda0a9322021-02-17 15:27:54 +0100232 qemu_printf("%s\n", (char *)array->pdata[i]);
Kevin Wolf0e301d42020-10-07 18:49:01 +0200233 }
234 g_ptr_array_set_free_func(array, g_free);
235 g_ptr_array_free(array, true);
236 return true;
237}
238
239bool user_creatable_print_help(const char *type, QemuOpts *opts)
240{
241 if (is_help_option(type)) {
242 user_creatable_print_types();
Kevin Wolf3e9297f2019-10-11 19:20:12 +0200243 return true;
244 }
245
Kevin Wolf0e301d42020-10-07 18:49:01 +0200246 if (qemu_opt_has_help_opt(opts)) {
Paolo Bonzini3bb69442020-11-02 11:08:07 -0500247 return type_print_class_properties(type);
Kevin Wolf3e9297f2019-10-11 19:20:12 +0200248 }
249
250 return false;
251}
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000252
Kevin Wolff3750262021-02-17 12:06:20 +0100253static void user_creatable_print_help_from_qdict(QDict *args)
Kevin Wolfc9ac1452020-10-07 18:49:02 +0200254{
255 const char *type = qdict_get_try_str(args, "qom-type");
256
Paolo Bonzini3bb69442020-11-02 11:08:07 -0500257 if (!type || !type_print_class_properties(type)) {
Kevin Wolfc9ac1452020-10-07 18:49:02 +0200258 user_creatable_print_types();
259 }
260}
261
Kevin Wolfddf6dae2021-02-19 18:14:01 +0100262ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp)
Kevin Wolff3750262021-02-17 12:06:20 +0100263{
Kevin Wolfffd58ef2021-02-17 14:59:06 +0100264 ERRP_GUARD();
Kevin Wolf155b5f82021-03-12 14:19:21 +0100265 QObject *obj;
Kevin Wolff3750262021-02-17 12:06:20 +0100266 bool help;
267 Visitor *v;
268 ObjectOptions *options;
269
Kevin Wolf155b5f82021-03-12 14:19:21 +0100270 if (optarg[0] == '{') {
271 obj = qobject_from_json(optarg, errp);
272 if (!obj) {
273 return NULL;
274 }
275 v = qobject_input_visitor_new(obj);
276 } else {
277 QDict *args = keyval_parse(optarg, "qom-type", &help, errp);
278 if (*errp) {
279 return NULL;
280 }
281 if (help) {
282 user_creatable_print_help_from_qdict(args);
283 qobject_unref(args);
284 return NULL;
285 }
286
287 obj = QOBJECT(args);
288 v = qobject_input_visitor_new_keyval(obj);
Kevin Wolff3750262021-02-17 12:06:20 +0100289 }
290
Kevin Wolfffd58ef2021-02-17 14:59:06 +0100291 visit_type_ObjectOptions(v, NULL, &options, errp);
Kevin Wolff3750262021-02-17 12:06:20 +0100292 visit_free(v);
Kevin Wolf155b5f82021-03-12 14:19:21 +0100293 qobject_unref(obj);
Kevin Wolff3750262021-02-17 12:06:20 +0100294
Kevin Wolfddf6dae2021-02-19 18:14:01 +0100295 return options;
296}
297
298bool user_creatable_add_from_str(const char *optarg, Error **errp)
299{
300 ERRP_GUARD();
301 ObjectOptions *options;
302
303 options = user_creatable_parse_str(optarg, errp);
304 if (!options) {
305 return false;
Kevin Wolfffd58ef2021-02-17 14:59:06 +0100306 }
307
308 user_creatable_add_qapi(options, errp);
Kevin Wolff3750262021-02-17 12:06:20 +0100309 qapi_free_ObjectOptions(options);
Kevin Wolfffd58ef2021-02-17 14:59:06 +0100310 return !*errp;
311}
312
313void user_creatable_process_cmdline(const char *optarg)
314{
315 if (!user_creatable_add_from_str(optarg, &error_fatal)) {
316 /* Help was printed */
317 exit(EXIT_SUCCESS);
318 }
Kevin Wolff3750262021-02-17 12:06:20 +0100319}
320
Markus Armbruster6fd5bef2020-07-07 18:05:55 +0200321bool user_creatable_del(const char *id, Error **errp)
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000322{
Kevin Wolf98c43b72021-02-22 15:29:27 +0100323 QemuOptsList *opts_list;
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000324 Object *container;
325 Object *obj;
326
327 container = object_get_objects_root();
328 obj = object_resolve_path_component(container, id);
329 if (!obj) {
330 error_setg(errp, "object '%s' not found", id);
Markus Armbruster6fd5bef2020-07-07 18:05:55 +0200331 return false;
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000332 }
333
Eduardo Habkost3beacfb2017-08-29 19:03:37 -0300334 if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000335 error_setg(errp, "object '%s' is in use, can not be deleted", id);
Markus Armbruster6fd5bef2020-07-07 18:05:55 +0200336 return false;
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000337 }
Michael Rothc645d5a2017-06-03 18:13:32 -0500338
339 /*
340 * if object was defined on the command-line, remove its corresponding
341 * option group entry
342 */
Kevin Wolf98c43b72021-02-22 15:29:27 +0100343 opts_list = qemu_find_opts_err("object", NULL);
344 if (opts_list) {
345 qemu_opts_del(qemu_opts_find(opts_list, id));
346 }
Michael Rothc645d5a2017-06-03 18:13:32 -0500347
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000348 object_unparent(obj);
Markus Armbruster6fd5bef2020-07-07 18:05:55 +0200349 return true;
Daniel P. Berrange90998d52016-02-10 18:40:59 +0000350}
351
Eduardo Habkost9d5139e2017-08-24 16:23:13 -0300352void user_creatable_cleanup(void)
353{
354 object_unparent(object_get_objects_root());
355}
356
Igor Mammedov269e09f2014-01-16 17:34:38 +0100357static void register_types(void)
358{
359 static const TypeInfo uc_interface_info = {
360 .name = TYPE_USER_CREATABLE,
361 .parent = TYPE_INTERFACE,
362 .class_size = sizeof(UserCreatableClass),
363 };
364
365 type_register_static(&uc_interface_info);
366}
367
368type_init(register_types)