1 /* 2 * QMP commands related to QOM 3 * 4 * Copyright IBM, Corp. 2011 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 * 12 * Contributions after 2012-01-13 are licensed under the terms of the 13 * GNU GPL, version 2 or (at your option) any later version. 14 */ 15 16 #include "qemu/osdep.h" 17 #include "hw/qdev.h" 18 #include "qapi/error.h" 19 #include "qapi/qapi-commands-qdev.h" 20 #include "qapi/qapi-commands-qom.h" 21 #include "qapi/qmp/qdict.h" 22 #include "qapi/qmp/qerror.h" 23 #include "qapi/qobject-input-visitor.h" 24 #include "qemu/cutils.h" 25 #include "qom/object_interfaces.h" 26 #include "qom/qom-qobject.h" 27 28 ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) 29 { 30 Object *obj; 31 bool ambiguous = false; 32 ObjectPropertyInfoList *props = NULL; 33 ObjectProperty *prop; 34 ObjectPropertyIterator iter; 35 36 obj = object_resolve_path(path, &ambiguous); 37 if (obj == NULL) { 38 if (ambiguous) { 39 error_setg(errp, "Path '%s' is ambiguous", path); 40 } else { 41 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 42 "Device '%s' not found", path); 43 } 44 return NULL; 45 } 46 47 object_property_iter_init(&iter, obj); 48 while ((prop = object_property_iter_next(&iter))) { 49 ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry)); 50 51 entry->value = g_malloc0(sizeof(ObjectPropertyInfo)); 52 entry->next = props; 53 props = entry; 54 55 entry->value->name = g_strdup(prop->name); 56 entry->value->type = g_strdup(prop->type); 57 } 58 59 return props; 60 } 61 62 void qmp_qom_set(const char *path, const char *property, QObject *value, 63 Error **errp) 64 { 65 Object *obj; 66 67 obj = object_resolve_path(path, NULL); 68 if (!obj) { 69 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 70 "Device '%s' not found", path); 71 return; 72 } 73 74 object_property_set_qobject(obj, value, property, errp); 75 } 76 77 QObject *qmp_qom_get(const char *path, const char *property, Error **errp) 78 { 79 Object *obj; 80 81 obj = object_resolve_path(path, NULL); 82 if (!obj) { 83 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 84 "Device '%s' not found", path); 85 return NULL; 86 } 87 88 return object_property_get_qobject(obj, property, errp); 89 } 90 91 static void qom_list_types_tramp(ObjectClass *klass, void *data) 92 { 93 ObjectTypeInfoList *e, **pret = data; 94 ObjectTypeInfo *info; 95 ObjectClass *parent = object_class_get_parent(klass); 96 97 info = g_malloc0(sizeof(*info)); 98 info->name = g_strdup(object_class_get_name(klass)); 99 info->has_abstract = info->abstract = object_class_is_abstract(klass); 100 if (parent) { 101 info->has_parent = true; 102 info->parent = g_strdup(object_class_get_name(parent)); 103 } 104 105 e = g_malloc0(sizeof(*e)); 106 e->value = info; 107 e->next = *pret; 108 *pret = e; 109 } 110 111 ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, 112 const char *implements, 113 bool has_abstract, 114 bool abstract, 115 Error **errp) 116 { 117 ObjectTypeInfoList *ret = NULL; 118 119 object_class_foreach(qom_list_types_tramp, implements, abstract, &ret); 120 121 return ret; 122 } 123 124 /* Return a DevicePropertyInfo for a qdev property. 125 * 126 * If a qdev property with the given name does not exist, use the given default 127 * type. If the qdev property info should not be shown, return NULL. 128 * 129 * The caller must free the return value. 130 */ 131 static ObjectPropertyInfo *make_device_property_info(ObjectClass *klass, 132 const char *name, 133 const char *default_type, 134 const char *description) 135 { 136 ObjectPropertyInfo *info; 137 Property *prop; 138 139 do { 140 for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) { 141 if (strcmp(name, prop->name) != 0) { 142 continue; 143 } 144 145 /* 146 * TODO Properties without a parser are just for dirty hacks. 147 * qdev_prop_ptr is the only such PropertyInfo. It's marked 148 * for removal. This conditional should be removed along with 149 * it. 150 */ 151 if (!prop->info->set && !prop->info->create) { 152 return NULL; /* no way to set it, don't show */ 153 } 154 155 info = g_malloc0(sizeof(*info)); 156 info->name = g_strdup(prop->name); 157 info->type = default_type ? g_strdup(default_type) 158 : g_strdup(prop->info->name); 159 info->has_description = !!prop->info->description; 160 info->description = g_strdup(prop->info->description); 161 return info; 162 } 163 klass = object_class_get_parent(klass); 164 } while (klass != object_class_by_name(TYPE_DEVICE)); 165 166 /* Not a qdev property, use the default type */ 167 info = g_malloc0(sizeof(*info)); 168 info->name = g_strdup(name); 169 info->type = g_strdup(default_type); 170 info->has_description = !!description; 171 info->description = g_strdup(description); 172 173 return info; 174 } 175 176 ObjectPropertyInfoList *qmp_device_list_properties(const char *typename, 177 Error **errp) 178 { 179 ObjectClass *klass; 180 Object *obj; 181 ObjectProperty *prop; 182 ObjectPropertyIterator iter; 183 ObjectPropertyInfoList *prop_list = NULL; 184 185 klass = object_class_by_name(typename); 186 if (klass == NULL) { 187 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 188 "Device '%s' not found", typename); 189 return NULL; 190 } 191 192 klass = object_class_dynamic_cast(klass, TYPE_DEVICE); 193 if (klass == NULL) { 194 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_DEVICE); 195 return NULL; 196 } 197 198 if (object_class_is_abstract(klass)) { 199 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", 200 "non-abstract device type"); 201 return NULL; 202 } 203 204 obj = object_new(typename); 205 206 object_property_iter_init(&iter, obj); 207 while ((prop = object_property_iter_next(&iter))) { 208 ObjectPropertyInfo *info; 209 ObjectPropertyInfoList *entry; 210 211 /* Skip Object and DeviceState properties */ 212 if (strcmp(prop->name, "type") == 0 || 213 strcmp(prop->name, "realized") == 0 || 214 strcmp(prop->name, "hotpluggable") == 0 || 215 strcmp(prop->name, "hotplugged") == 0 || 216 strcmp(prop->name, "parent_bus") == 0) { 217 continue; 218 } 219 220 /* Skip legacy properties since they are just string versions of 221 * properties that we already list. 222 */ 223 if (strstart(prop->name, "legacy-", NULL)) { 224 continue; 225 } 226 227 info = make_device_property_info(klass, prop->name, prop->type, 228 prop->description); 229 if (!info) { 230 continue; 231 } 232 233 entry = g_malloc0(sizeof(*entry)); 234 entry->value = info; 235 entry->next = prop_list; 236 prop_list = entry; 237 } 238 239 object_unref(obj); 240 241 return prop_list; 242 } 243 244 ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename, 245 Error **errp) 246 { 247 ObjectClass *klass; 248 Object *obj = NULL; 249 ObjectProperty *prop; 250 ObjectPropertyIterator iter; 251 ObjectPropertyInfoList *prop_list = NULL; 252 253 klass = object_class_by_name(typename); 254 if (klass == NULL) { 255 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 256 "Class '%s' not found", typename); 257 return NULL; 258 } 259 260 klass = object_class_dynamic_cast(klass, TYPE_OBJECT); 261 if (klass == NULL) { 262 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_OBJECT); 263 return NULL; 264 } 265 266 if (object_class_is_abstract(klass)) { 267 object_class_property_iter_init(&iter, klass); 268 } else { 269 obj = object_new(typename); 270 object_property_iter_init(&iter, obj); 271 } 272 while ((prop = object_property_iter_next(&iter))) { 273 ObjectPropertyInfo *info; 274 ObjectPropertyInfoList *entry; 275 276 info = g_malloc0(sizeof(*info)); 277 info->name = g_strdup(prop->name); 278 info->type = g_strdup(prop->type); 279 info->has_description = !!prop->description; 280 info->description = g_strdup(prop->description); 281 282 entry = g_malloc0(sizeof(*entry)); 283 entry->value = info; 284 entry->next = prop_list; 285 prop_list = entry; 286 } 287 288 object_unref(obj); 289 290 return prop_list; 291 } 292 293 void qmp_object_add(const char *type, const char *id, 294 bool has_props, QObject *props, Error **errp) 295 { 296 QDict *pdict; 297 Visitor *v; 298 Object *obj; 299 300 if (props) { 301 pdict = qobject_to(QDict, props); 302 if (!pdict) { 303 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); 304 return; 305 } 306 qobject_ref(pdict); 307 } else { 308 pdict = qdict_new(); 309 } 310 311 v = qobject_input_visitor_new(QOBJECT(pdict)); 312 obj = user_creatable_add_type(type, id, pdict, v, errp); 313 visit_free(v); 314 if (obj) { 315 object_unref(obj); 316 } 317 qobject_unref(pdict); 318 } 319 320 void qmp_object_del(const char *id, Error **errp) 321 { 322 user_creatable_del(id, errp); 323 } 324