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