master
c 294 lines 7.38 KB
Raw
1 #include "qemu/osdep.h"
2
3 #include "qemu/cutils.h"
4 #include "qapi/error.h"
5 #include "qapi/qapi-visit-qom.h"
6 #include "qobject/qobject.h"
7 #include "qobject/qbool.h"
8 #include "qobject/qdict.h"
9 #include "qapi/qmp/qerror.h"
10 #include "qobject/qjson.h"
11 #include "qobject/qstring.h"
12 #include "qapi/qobject-input-visitor.h"
13 #include "qapi/qobject-output-visitor.h"
14 #include "qom/object_interfaces.h"
15 #include "qemu/help_option.h"
16 #include "qemu/id.h"
17 #include "qemu/module.h"
18 #include "qemu/option.h"
19 #include "qemu/qemu-print.h"
20 #include "qapi/opts-visitor.h"
21 #include "qemu/config-file.h"
22 #include "qemu/keyval.h"
23 #include "trace.h"
24
25 bool user_creatable_complete(UserCreatable *uc, Error **errp)
26 {
27 UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
28 ERRP_GUARD();
29
30 trace_user_creatable_complete(uc, object_get_typename(OBJECT(uc)));
31 if (ucc->complete) {
32 ucc->complete(uc, errp);
33 }
34 return !*errp;
35 }
36
37 bool user_creatable_prepare_delete(UserCreatable *uc, Error **errp)
38 {
39 UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
40 bool ret = true;
41
42 trace_user_creatable_prepare_delete(uc, object_get_typename(OBJECT(uc)));
43 if (ucc->prepare_delete) {
44 ret = ucc->prepare_delete(uc, errp);
45 }
46 trace_user_creatable_prepare_delete_result(
47 uc, object_get_typename(OBJECT(uc)),
48 *errp ? error_get_pretty(*errp) : NULL);
49 return ret;
50 }
51
52 void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
53 {
54 Visitor *v;
55 QObject *qobj;
56 QDict *props;
57
58 v = qobject_output_visitor_new(&qobj);
59 visit_type_ObjectOptions(v, NULL, &options, &error_abort);
60 visit_complete(v, &qobj);
61 visit_free(v);
62
63 props = qobject_to(QDict, qobj);
64 qdict_del(props, "qom-type");
65 qdict_del(props, "id");
66
67 v = qobject_input_visitor_new(QOBJECT(props));
68 object_new_with_props_from_qdict(ObjectType_str(options->qom_type),
69 object_get_objects_root(),
70 options->id, props, v, errp);
71 qobject_unref(qobj);
72 visit_free(v);
73 }
74
75 char *object_property_help(const char *name, const char *type,
76 QObject *defval, const char *description)
77 {
78 GString *str = g_string_new(NULL);
79
80 g_string_append_printf(str, " %s=<%s>", name, type);
81 if (description || defval) {
82 if (str->len < 24) {
83 g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
84 }
85 g_string_append(str, " - ");
86 }
87 if (description) {
88 g_string_append(str, description);
89 }
90 if (defval) {
91 g_autofree char *def_json = NULL;
92 const char *def;
93
94 switch (qobject_type(defval)) {
95 case QTYPE_QSTRING:
96 def = qstring_get_str(qobject_to(QString, defval));
97 break;
98
99 case QTYPE_QBOOL:
100 def = qbool_get_bool(qobject_to(QBool, defval)) ? "on" : "off";
101 break;
102
103 default:
104 def_json = g_string_free(qobject_to_json(defval), false);
105 def = def_json;
106 break;
107 }
108
109 g_string_append_printf(str, " (default: %s)", def);
110 }
111
112 return g_string_free(str, false);
113 }
114
115 static void user_creatable_print_types(void)
116 {
117 GSList *l, *list;
118
119 qemu_printf("List of user creatable objects:\n");
120 list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
121 for (l = list; l != NULL; l = l->next) {
122 ObjectClass *oc = OBJECT_CLASS(l->data);
123 qemu_printf(" %s\n", object_class_get_name(oc));
124 }
125 g_slist_free(list);
126 }
127
128 bool type_print_class_properties(const char *type)
129 {
130 ObjectClass *klass;
131 ObjectPropertyIterator iter;
132 ObjectProperty *prop;
133 GPtrArray *array;
134 int i;
135
136 klass = object_class_by_name(type);
137 if (!klass) {
138 return false;
139 }
140
141 array = g_ptr_array_new();
142 object_class_property_iter_init(&iter, klass);
143 while ((prop = object_property_iter_next(&iter))) {
144 if (!prop->set) {
145 continue;
146 }
147
148 g_ptr_array_add(array,
149 object_property_help(prop->name, prop->type,
150 prop->defval, prop->description));
151 }
152 g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
153 if (array->len > 0) {
154 qemu_printf("%s options:\n", type);
155 } else {
156 qemu_printf("There are no options for %s.\n", type);
157 }
158 for (i = 0; i < array->len; i++) {
159 qemu_printf("%s\n", (char *)array->pdata[i]);
160 }
161 g_ptr_array_set_free_func(array, g_free);
162 g_ptr_array_free(array, true);
163 return true;
164 }
165
166 bool user_creatable_print_help(const char *type, QemuOpts *opts)
167 {
168 if (is_help_option(type)) {
169 user_creatable_print_types();
170 return true;
171 }
172
173 if (qemu_opt_has_help_opt(opts)) {
174 return type_print_class_properties(type);
175 }
176
177 return false;
178 }
179
180 static void user_creatable_print_help_from_qdict(QDict *args)
181 {
182 const char *type = qdict_get_try_str(args, "qom-type");
183
184 if (!type || !type_print_class_properties(type)) {
185 user_creatable_print_types();
186 }
187 }
188
189 ObjectOptions *user_creatable_parse_str(const char *str, Error **errp)
190 {
191 ERRP_GUARD();
192 QObject *obj;
193 bool help;
194 Visitor *v;
195 ObjectOptions *options;
196
197 if (str[0] == '{') {
198 obj = qobject_from_json(str, errp);
199 if (!obj) {
200 return NULL;
201 }
202 v = qobject_input_visitor_new(obj);
203 } else {
204 QDict *args = keyval_parse(str, "qom-type", &help, errp);
205 if (*errp) {
206 return NULL;
207 }
208 if (help) {
209 user_creatable_print_help_from_qdict(args);
210 qobject_unref(args);
211 return NULL;
212 }
213
214 obj = QOBJECT(args);
215 v = qobject_input_visitor_new_keyval(obj);
216 }
217
218 visit_type_ObjectOptions(v, NULL, &options, errp);
219 visit_free(v);
220 qobject_unref(obj);
221
222 return options;
223 }
224
225 bool user_creatable_add_from_str(const char *str, Error **errp)
226 {
227 ERRP_GUARD();
228 ObjectOptions *options;
229
230 options = user_creatable_parse_str(str, errp);
231 if (!options) {
232 return false;
233 }
234
235 user_creatable_add_qapi(options, errp);
236 qapi_free_ObjectOptions(options);
237 return !*errp;
238 }
239
240 void user_creatable_process_cmdline(const char *cmdline)
241 {
242 if (!user_creatable_add_from_str(cmdline, &error_fatal)) {
243 /* Help was printed */
244 exit(EXIT_SUCCESS);
245 }
246 }
247
248 bool user_creatable_del(const char *id, Error **errp)
249 {
250 QemuOptsList *opts_list;
251 Object *container;
252 Object *obj;
253
254 container = object_get_objects_root();
255 obj = object_resolve_path_component(container, id);
256 if (!obj) {
257 error_setg(errp, "object '%s' not found", id);
258 return false;
259 }
260
261 if (!user_creatable_prepare_delete(USER_CREATABLE(obj), errp)) {
262 return false;
263 }
264
265 /*
266 * if object was defined on the command-line, remove its corresponding
267 * option group entry
268 */
269 opts_list = qemu_find_opts_err("object", NULL);
270 if (opts_list) {
271 qemu_opts_del(qemu_opts_find(opts_list, id));
272 }
273
274 object_unparent(obj);
275 return true;
276 }
277
278 void user_creatable_cleanup(void)
279 {
280 object_unparent(object_get_objects_root());
281 }
282
283 static void register_types(void)
284 {
285 static const TypeInfo uc_interface_info = {
286 .name = TYPE_USER_CREATABLE,
287 .parent = TYPE_INTERFACE,
288 .class_size = sizeof(UserCreatableClass),
289 };
290
291 type_register_static(&uc_interface_info);
292 }
293
294 type_init(register_types)