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