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