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 "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, property, value, 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 module_load_qom_all(); 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 = module_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 if (!object_class_dynamic_cast(klass, TYPE_DEVICE) 142 || object_class_is_abstract(klass)) { 143 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", 144 "a non-abstract device type"); 145 return NULL; 146 } 147 148 obj = object_new(typename); 149 150 object_property_iter_init(&iter, obj); 151 while ((prop = object_property_iter_next(&iter))) { 152 ObjectPropertyInfo *info; 153 ObjectPropertyInfoList *entry; 154 155 /* Skip Object and DeviceState properties */ 156 if (strcmp(prop->name, "type") == 0 || 157 strcmp(prop->name, "realized") == 0 || 158 strcmp(prop->name, "hotpluggable") == 0 || 159 strcmp(prop->name, "hotplugged") == 0 || 160 strcmp(prop->name, "parent_bus") == 0) { 161 continue; 162 } 163 164 /* Skip legacy properties since they are just string versions of 165 * properties that we already list. 166 */ 167 if (strstart(prop->name, "legacy-", NULL)) { 168 continue; 169 } 170 171 info = g_new0(ObjectPropertyInfo, 1); 172 info->name = g_strdup(prop->name); 173 info->type = g_strdup(prop->type); 174 info->has_description = !!prop->description; 175 info->description = g_strdup(prop->description); 176 info->default_value = qobject_ref(prop->defval); 177 info->has_default_value = !!info->default_value; 178 179 entry = g_malloc0(sizeof(*entry)); 180 entry->value = info; 181 entry->next = prop_list; 182 prop_list = entry; 183 } 184 185 object_unref(obj); 186 187 return prop_list; 188 } 189 190 ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename, 191 Error **errp) 192 { 193 ObjectClass *klass; 194 Object *obj = NULL; 195 ObjectProperty *prop; 196 ObjectPropertyIterator iter; 197 ObjectPropertyInfoList *prop_list = NULL; 198 199 klass = object_class_by_name(typename); 200 if (klass == NULL) { 201 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 202 "Class '%s' not found", typename); 203 return NULL; 204 } 205 206 if (!object_class_dynamic_cast(klass, TYPE_OBJECT)) { 207 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", 208 "a QOM type"); 209 return NULL; 210 } 211 212 if (object_class_is_abstract(klass)) { 213 object_class_property_iter_init(&iter, klass); 214 } else { 215 obj = object_new(typename); 216 object_property_iter_init(&iter, obj); 217 } 218 while ((prop = object_property_iter_next(&iter))) { 219 ObjectPropertyInfo *info; 220 ObjectPropertyInfoList *entry; 221 222 info = g_malloc0(sizeof(*info)); 223 info->name = g_strdup(prop->name); 224 info->type = g_strdup(prop->type); 225 info->has_description = !!prop->description; 226 info->description = g_strdup(prop->description); 227 228 entry = g_malloc0(sizeof(*entry)); 229 entry->value = info; 230 entry->next = prop_list; 231 prop_list = entry; 232 } 233 234 object_unref(obj); 235 236 return prop_list; 237 } 238 239 void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) 240 { 241 QObject *props; 242 QDict *pdict; 243 244 props = qdict_get(qdict, "props"); 245 if (props) { 246 pdict = qobject_to(QDict, props); 247 if (!pdict) { 248 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); 249 return; 250 } 251 qobject_ref(pdict); 252 qdict_del(qdict, "props"); 253 qdict_join(qdict, pdict, false); 254 if (qdict_size(pdict) != 0) { 255 error_setg(errp, "Option in 'props' conflicts with top level"); 256 qobject_unref(pdict); 257 return; 258 } 259 qobject_unref(pdict); 260 } 261 262 user_creatable_add_dict(qdict, false, errp); 263 } 264 265 void qmp_object_del(const char *id, Error **errp) 266 { 267 user_creatable_del(id, errp); 268 } 269