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