Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20211016' into staging
[qemu.git] / qom / object_interfaces.c
1 #include "qemu/osdep.h"
2
3 #include "qemu/cutils.h"
4 #include "qapi/error.h"
5 #include "qapi/qapi-commands-qom.h"
6 #include "qapi/qapi-visit-qom.h"
7 #include "qapi/qmp/qdict.h"
8 #include "qapi/qmp/qerror.h"
9 #include "qapi/qmp/qjson.h"
10 #include "qapi/qobject-input-visitor.h"
11 #include "qapi/qobject-output-visitor.h"
12 #include "qom/object_interfaces.h"
13 #include "qemu/help_option.h"
14 #include "qemu/id.h"
15 #include "qemu/module.h"
16 #include "qemu/option.h"
17 #include "qemu/qemu-print.h"
18 #include "qapi/opts-visitor.h"
19 #include "qemu/config-file.h"
20
21 bool user_creatable_complete(UserCreatable *uc, Error **errp)
22 {
23 UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
24 Error *err = NULL;
25
26 if (ucc->complete) {
27 ucc->complete(uc, &err);
28 error_propagate(errp, err);
29 }
30 return !err;
31 }
32
33 bool user_creatable_can_be_deleted(UserCreatable *uc)
34 {
35
36 UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
37
38 if (ucc->can_be_deleted) {
39 return ucc->can_be_deleted(uc);
40 } else {
41 return true;
42 }
43 }
44
45 Object *user_creatable_add_type(const char *type, const char *id,
46 const QDict *qdict,
47 Visitor *v, Error **errp)
48 {
49 ERRP_GUARD();
50 Object *obj;
51 ObjectClass *klass;
52 const QDictEntry *e;
53 Error *local_err = NULL;
54
55 if (id != NULL && !id_wellformed(id)) {
56 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
57 error_append_hint(errp, "Identifiers consist of letters, digits, "
58 "'-', '.', '_', starting with a letter.\n");
59 return NULL;
60 }
61
62 klass = object_class_by_name(type);
63 if (!klass) {
64 error_setg(errp, "invalid object type: %s", type);
65 return NULL;
66 }
67
68 if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
69 error_setg(errp, "object type '%s' isn't supported by object-add",
70 type);
71 return NULL;
72 }
73
74 if (object_class_is_abstract(klass)) {
75 error_setg(errp, "object type '%s' is abstract", type);
76 return NULL;
77 }
78
79 assert(qdict);
80 obj = object_new(type);
81 if (!visit_start_struct(v, NULL, NULL, 0, &local_err)) {
82 goto out;
83 }
84 for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
85 if (!object_property_set(obj, e->key, v, &local_err)) {
86 break;
87 }
88 }
89 if (!local_err) {
90 visit_check_struct(v, &local_err);
91 }
92 visit_end_struct(v, NULL);
93 if (local_err) {
94 goto out;
95 }
96
97 if (id != NULL) {
98 object_property_try_add_child(object_get_objects_root(),
99 id, obj, &local_err);
100 if (local_err) {
101 goto out;
102 }
103 }
104
105 if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) {
106 if (id != NULL) {
107 object_property_del(object_get_objects_root(), id);
108 }
109 goto out;
110 }
111 out:
112 if (local_err) {
113 error_propagate(errp, local_err);
114 object_unref(obj);
115 return NULL;
116 }
117 return obj;
118 }
119
120 void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
121 {
122 Visitor *v;
123 QObject *qobj;
124 QDict *props;
125 Object *obj;
126
127 v = qobject_output_visitor_new(&qobj);
128 visit_type_ObjectOptions(v, NULL, &options, &error_abort);
129 visit_complete(v, &qobj);
130 visit_free(v);
131
132 props = qobject_to(QDict, qobj);
133 qdict_del(props, "qom-type");
134 qdict_del(props, "id");
135
136 v = qobject_input_visitor_new(QOBJECT(props));
137 obj = user_creatable_add_type(ObjectType_str(options->qom_type),
138 options->id, props, v, errp);
139 object_unref(obj);
140 qobject_unref(qobj);
141 visit_free(v);
142 }
143
144 char *object_property_help(const char *name, const char *type,
145 QObject *defval, const char *description)
146 {
147 GString *str = g_string_new(NULL);
148
149 g_string_append_printf(str, " %s=<%s>", name, type);
150 if (description || defval) {
151 if (str->len < 24) {
152 g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
153 }
154 g_string_append(str, " - ");
155 }
156 if (description) {
157 g_string_append(str, description);
158 }
159 if (defval) {
160 g_autofree char *def_json = g_string_free(qobject_to_json(defval),
161 false);
162 g_string_append_printf(str, " (default: %s)", def_json);
163 }
164
165 return g_string_free(str, false);
166 }
167
168 static void user_creatable_print_types(void)
169 {
170 GSList *l, *list;
171
172 qemu_printf("List of user creatable objects:\n");
173 list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
174 for (l = list; l != NULL; l = l->next) {
175 ObjectClass *oc = OBJECT_CLASS(l->data);
176 qemu_printf(" %s\n", object_class_get_name(oc));
177 }
178 g_slist_free(list);
179 }
180
181 static bool user_creatable_print_type_properites(const char *type)
182 {
183 ObjectClass *klass;
184 ObjectPropertyIterator iter;
185 ObjectProperty *prop;
186 GPtrArray *array;
187 int i;
188
189 klass = object_class_by_name(type);
190 if (!klass) {
191 return false;
192 }
193
194 array = g_ptr_array_new();
195 object_class_property_iter_init(&iter, klass);
196 while ((prop = object_property_iter_next(&iter))) {
197 if (!prop->set) {
198 continue;
199 }
200
201 g_ptr_array_add(array,
202 object_property_help(prop->name, prop->type,
203 prop->defval, prop->description));
204 }
205 g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
206 if (array->len > 0) {
207 qemu_printf("%s options:\n", type);
208 } else {
209 qemu_printf("There are no options for %s.\n", type);
210 }
211 for (i = 0; i < array->len; i++) {
212 qemu_printf("%s\n", (char *)array->pdata[i]);
213 }
214 g_ptr_array_set_free_func(array, g_free);
215 g_ptr_array_free(array, true);
216 return true;
217 }
218
219 bool user_creatable_print_help(const char *type, QemuOpts *opts)
220 {
221 if (is_help_option(type)) {
222 user_creatable_print_types();
223 return true;
224 }
225
226 if (qemu_opt_has_help_opt(opts)) {
227 return user_creatable_print_type_properites(type);
228 }
229
230 return false;
231 }
232
233 static void user_creatable_print_help_from_qdict(QDict *args)
234 {
235 const char *type = qdict_get_try_str(args, "qom-type");
236
237 if (!type || !user_creatable_print_type_properites(type)) {
238 user_creatable_print_types();
239 }
240 }
241
242 ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp)
243 {
244 ERRP_GUARD();
245 QObject *obj;
246 bool help;
247 Visitor *v;
248 ObjectOptions *options;
249
250 if (optarg[0] == '{') {
251 obj = qobject_from_json(optarg, errp);
252 if (!obj) {
253 return NULL;
254 }
255 v = qobject_input_visitor_new(obj);
256 } else {
257 QDict *args = keyval_parse(optarg, "qom-type", &help, errp);
258 if (*errp) {
259 return NULL;
260 }
261 if (help) {
262 user_creatable_print_help_from_qdict(args);
263 qobject_unref(args);
264 return NULL;
265 }
266
267 obj = QOBJECT(args);
268 v = qobject_input_visitor_new_keyval(obj);
269 }
270
271 visit_type_ObjectOptions(v, NULL, &options, errp);
272 visit_free(v);
273 qobject_unref(obj);
274
275 return options;
276 }
277
278 bool user_creatable_add_from_str(const char *optarg, Error **errp)
279 {
280 ERRP_GUARD();
281 ObjectOptions *options;
282
283 options = user_creatable_parse_str(optarg, errp);
284 if (!options) {
285 return false;
286 }
287
288 user_creatable_add_qapi(options, errp);
289 qapi_free_ObjectOptions(options);
290 return !*errp;
291 }
292
293 void user_creatable_process_cmdline(const char *optarg)
294 {
295 if (!user_creatable_add_from_str(optarg, &error_fatal)) {
296 /* Help was printed */
297 exit(EXIT_SUCCESS);
298 }
299 }
300
301 bool user_creatable_del(const char *id, Error **errp)
302 {
303 QemuOptsList *opts_list;
304 Object *container;
305 Object *obj;
306
307 container = object_get_objects_root();
308 obj = object_resolve_path_component(container, id);
309 if (!obj) {
310 error_setg(errp, "object '%s' not found", id);
311 return false;
312 }
313
314 if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
315 error_setg(errp, "object '%s' is in use, can not be deleted", id);
316 return false;
317 }
318
319 /*
320 * if object was defined on the command-line, remove its corresponding
321 * option group entry
322 */
323 opts_list = qemu_find_opts_err("object", NULL);
324 if (opts_list) {
325 qemu_opts_del(qemu_opts_find(opts_list, id));
326 }
327
328 object_unparent(obj);
329 return true;
330 }
331
332 void user_creatable_cleanup(void)
333 {
334 object_unparent(object_get_objects_root());
335 }
336
337 static void register_types(void)
338 {
339 static const TypeInfo uc_interface_info = {
340 .name = TYPE_USER_CREATABLE,
341 .parent = TYPE_INTERFACE,
342 .class_size = sizeof(UserCreatableClass),
343 };
344
345 type_register_static(&uc_interface_info);
346 }
347
348 type_init(register_types)