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 "block/qdict.h" 18 #include "hw/qdev-core.h" 19 #include "qapi/error.h" 20 #include "qapi/qapi-commands-qdev.h" 21 #include "qapi/qapi-commands-qom.h" 22 #include "qapi/qmp/qdict.h" 23 #include "qapi/qmp/qerror.h" 24 #include "qapi/qobject-input-visitor.h" 25 #include "qemu/cutils.h" 26 #include "qom/object_interfaces.h" 27 #include "qom/qom-qobject.h" 28 29 ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) 30 { 31 Object *obj; 32 bool ambiguous = false; 33 ObjectPropertyInfoList *props = NULL; 34 ObjectProperty *prop; 35 ObjectPropertyIterator iter; 36 37 obj = object_resolve_path(path, &ambiguous); 38 if (obj == NULL) { 39 if (ambiguous) { 40 error_setg(errp, "Path '%s' is ambiguous", path); 41 } else { 42 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 43 "Device '%s' not found", path); 44 } 45 return NULL; 46 } 47 48 object_property_iter_init(&iter, obj); 49 while ((prop = object_property_iter_next(&iter))) { 50 ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry)); 51 52 entry->value = g_malloc0(sizeof(ObjectPropertyInfo)); 53 entry->next = props; 54 props = entry; 55 56 entry->value->name = g_strdup(prop->name); 57 entry->value->type = g_strdup(prop->type); 58 } 59 60 return props; 61 } 62 63 void qmp_qom_set(const char *path, const char *property, QObject *value, 64 Error **errp) 65 { 66 Object *obj; 67 68 obj = object_resolve_path(path, NULL); 69 if (!obj) { 70 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 71 "Device '%s' not found", path); 72 return; 73 } 74 75 object_property_set_qobject(obj, value, property, errp); 76 } 77 78 QObject *qmp_qom_get(const char *path, const char *property, Error **errp) 79 { 80 Object *obj; 81 82 obj = object_resolve_path(path, NULL); 83 if (!obj) { 84 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 85 "Device '%s' not found", path); 86 return NULL; 87 } 88 89 return object_property_get_qobject(obj, property, errp); 90 } 91 92 static void qom_list_types_tramp(ObjectClass *klass, void *data) 93 { 94 ObjectTypeInfoList *e, **pret = data; 95 ObjectTypeInfo *info; 96 ObjectClass *parent = object_class_get_parent(klass); 97 98 info = g_malloc0(sizeof(*info)); 99 info->name = g_strdup(object_class_get_name(klass)); 100 info->has_abstract = info->abstract = object_class_is_abstract(klass); 101 if (parent) { 102 info->has_parent = true; 103 info->parent = g_strdup(object_class_get_name(parent)); 104 } 105 106 e = g_malloc0(sizeof(*e)); 107 e->value = info; 108 e->next = *pret; 109 *pret = e; 110 } 111 112 ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, 113 const char *implements, 114 bool has_abstract, 115 bool abstract, 116 Error **errp) 117 { 118 ObjectTypeInfoList *ret = NULL; 119 120 object_class_foreach(qom_list_types_tramp, implements, abstract, &ret); 121 122 return ret; 123 } 124 125 ObjectPropertyInfoList *qmp_device_list_properties(const char *typename, 126 Error **errp) 127 { 128 ObjectClass *klass; 129 Object *obj; 130 ObjectProperty *prop; 131 ObjectPropertyIterator iter; 132 ObjectPropertyInfoList *prop_list = NULL; 133 134 klass = object_class_by_name(typename); 135 if (klass == NULL) { 136 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 137 "Device '%s' not found", typename); 138 return NULL; 139 } 140 141 klass = object_class_dynamic_cast(klass, TYPE_DEVICE); 142 if (klass == NULL) { 143 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_DEVICE); 144 return NULL; 145 } 146 147 if (object_class_is_abstract(klass)) { 148 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", 149 "non-abstract device type"); 150 return NULL; 151 } 152 153 obj = object_new(typename); 154 155 object_property_iter_init(&iter, obj); 156 while ((prop = object_property_iter_next(&iter))) { 157 ObjectPropertyInfo *info; 158 ObjectPropertyInfoList *entry; 159 160 /* Skip Object and DeviceState properties */ 161 if (strcmp(prop->name, "type") == 0 || 162 strcmp(prop->name, "realized") == 0 || 163 strcmp(prop->name, "hotpluggable") == 0 || 164 strcmp(prop->name, "hotplugged") == 0 || 165 strcmp(prop->name, "parent_bus") == 0) { 166 continue; 167 } 168 169 /* Skip legacy properties since they are just string versions of 170 * properties that we already list. 171 */ 172 if (strstart(prop->name, "legacy-", NULL)) { 173 continue; 174 } 175 176 info = g_new0(ObjectPropertyInfo, 1); 177 info->name = g_strdup(prop->name); 178 info->type = g_strdup(prop->type); 179 info->has_description = !!prop->description; 180 info->description = g_strdup(prop->description); 181 info->default_value = qobject_ref(prop->defval); 182 info->has_default_value = !!info->default_value; 183 184 entry = g_malloc0(sizeof(*entry)); 185 entry->value = info; 186 entry->next = prop_list; 187 prop_list = entry; 188 } 189 190 object_unref(obj); 191 192 return prop_list; 193 } 194 195 ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename, 196 Error **errp) 197 { 198 ObjectClass *klass; 199 Object *obj = NULL; 200 ObjectProperty *prop; 201 ObjectPropertyIterator iter; 202 ObjectPropertyInfoList *prop_list = NULL; 203 204 klass = object_class_by_name(typename); 205 if (klass == NULL) { 206 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 207 "Class '%s' not found", typename); 208 return NULL; 209 } 210 211 klass = object_class_dynamic_cast(klass, TYPE_OBJECT); 212 if (klass == NULL) { 213 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", TYPE_OBJECT); 214 return NULL; 215 } 216 217 if (object_class_is_abstract(klass)) { 218 object_class_property_iter_init(&iter, klass); 219 } else { 220 obj = object_new(typename); 221 object_property_iter_init(&iter, obj); 222 } 223 while ((prop = object_property_iter_next(&iter))) { 224 ObjectPropertyInfo *info; 225 ObjectPropertyInfoList *entry; 226 227 info = g_malloc0(sizeof(*info)); 228 info->name = g_strdup(prop->name); 229 info->type = g_strdup(prop->type); 230 info->has_description = !!prop->description; 231 info->description = g_strdup(prop->description); 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 void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) 245 { 246 QObject *props; 247 QDict *pdict; 248 Visitor *v; 249 Object *obj; 250 g_autofree char *type = NULL; 251 g_autofree char *id = NULL; 252 253 type = g_strdup(qdict_get_try_str(qdict, "qom-type")); 254 if (!type) { 255 error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); 256 return; 257 } 258 qdict_del(qdict, "qom-type"); 259 260 id = g_strdup(qdict_get_try_str(qdict, "id")); 261 if (!id) { 262 error_setg(errp, QERR_MISSING_PARAMETER, "id"); 263 return; 264 } 265 qdict_del(qdict, "id"); 266 267 props = qdict_get(qdict, "props"); 268 if (props) { 269 pdict = qobject_to(QDict, props); 270 if (!pdict) { 271 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); 272 return; 273 } 274 qobject_ref(pdict); 275 qdict_del(qdict, "props"); 276 qdict_join(qdict, pdict, false); 277 if (qdict_size(pdict) != 0) { 278 error_setg(errp, "Option in 'props' conflicts with top level"); 279 qobject_unref(pdict); 280 return; 281 } 282 qobject_unref(pdict); 283 } 284 285 v = qobject_input_visitor_new(QOBJECT(qdict)); 286 obj = user_creatable_add_type(type, id, qdict, v, errp); 287 visit_free(v); 288 if (obj) { 289 object_unref(obj); 290 } 291 *ret_data = QOBJECT(qdict_new()); 292 } 293 294 void qmp_object_del(const char *id, Error **errp) 295 { 296 user_creatable_del(id, errp); 297 } 298