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 ObjectPropertyInfo *value = g_malloc0(sizeof(ObjectPropertyInfo)); 50 51 QAPI_LIST_PREPEND(props, value); 52 53 value->name = g_strdup(prop->name); 54 value->type = g_strdup(prop->type); 55 } 56 57 return props; 58 } 59 60 void qmp_qom_set(const char *path, const char *property, QObject *value, 61 Error **errp) 62 { 63 Object *obj; 64 65 obj = object_resolve_path(path, NULL); 66 if (!obj) { 67 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 68 "Device '%s' not found", path); 69 return; 70 } 71 72 object_property_set_qobject(obj, property, value, errp); 73 } 74 75 QObject *qmp_qom_get(const char *path, const char *property, Error **errp) 76 { 77 Object *obj; 78 79 obj = object_resolve_path(path, NULL); 80 if (!obj) { 81 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 82 "Device '%s' not found", path); 83 return NULL; 84 } 85 86 return object_property_get_qobject(obj, property, errp); 87 } 88 89 static void qom_list_types_tramp(ObjectClass *klass, void *data) 90 { 91 ObjectTypeInfoList **pret = data; 92 ObjectTypeInfo *info; 93 ObjectClass *parent = object_class_get_parent(klass); 94 95 info = g_malloc0(sizeof(*info)); 96 info->name = g_strdup(object_class_get_name(klass)); 97 info->has_abstract = info->abstract = object_class_is_abstract(klass); 98 if (parent) { 99 info->has_parent = true; 100 info->parent = g_strdup(object_class_get_name(parent)); 101 } 102 103 QAPI_LIST_PREPEND(*pret, info); 104 } 105 106 ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, 107 const char *implements, 108 bool has_abstract, 109 bool abstract, 110 Error **errp) 111 { 112 ObjectTypeInfoList *ret = NULL; 113 114 module_load_qom_all(); 115 object_class_foreach(qom_list_types_tramp, implements, abstract, &ret); 116 117 return ret; 118 } 119 120 ObjectPropertyInfoList *qmp_device_list_properties(const char *typename, 121 Error **errp) 122 { 123 ObjectClass *klass; 124 Object *obj; 125 ObjectProperty *prop; 126 ObjectPropertyIterator iter; 127 ObjectPropertyInfoList *prop_list = NULL; 128 129 klass = module_object_class_by_name(typename); 130 if (klass == NULL) { 131 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 132 "Device '%s' not found", typename); 133 return NULL; 134 } 135 136 if (!object_class_dynamic_cast(klass, TYPE_DEVICE) 137 || object_class_is_abstract(klass)) { 138 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", 139 "a non-abstract device type"); 140 return NULL; 141 } 142 143 obj = object_new(typename); 144 145 object_property_iter_init(&iter, obj); 146 while ((prop = object_property_iter_next(&iter))) { 147 ObjectPropertyInfo *info; 148 149 /* Skip Object and DeviceState properties */ 150 if (strcmp(prop->name, "type") == 0 || 151 strcmp(prop->name, "realized") == 0 || 152 strcmp(prop->name, "hotpluggable") == 0 || 153 strcmp(prop->name, "hotplugged") == 0 || 154 strcmp(prop->name, "parent_bus") == 0) { 155 continue; 156 } 157 158 /* Skip legacy properties since they are just string versions of 159 * properties that we already list. 160 */ 161 if (strstart(prop->name, "legacy-", NULL)) { 162 continue; 163 } 164 165 info = g_new0(ObjectPropertyInfo, 1); 166 info->name = g_strdup(prop->name); 167 info->type = g_strdup(prop->type); 168 info->has_description = !!prop->description; 169 info->description = g_strdup(prop->description); 170 info->default_value = qobject_ref(prop->defval); 171 info->has_default_value = !!info->default_value; 172 173 QAPI_LIST_PREPEND(prop_list, info); 174 } 175 176 object_unref(obj); 177 178 return prop_list; 179 } 180 181 ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename, 182 Error **errp) 183 { 184 ObjectClass *klass; 185 Object *obj = NULL; 186 ObjectProperty *prop; 187 ObjectPropertyIterator iter; 188 ObjectPropertyInfoList *prop_list = NULL; 189 190 klass = object_class_by_name(typename); 191 if (klass == NULL) { 192 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 193 "Class '%s' not found", typename); 194 return NULL; 195 } 196 197 if (!object_class_dynamic_cast(klass, TYPE_OBJECT)) { 198 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "typename", 199 "a QOM type"); 200 return NULL; 201 } 202 203 if (object_class_is_abstract(klass)) { 204 object_class_property_iter_init(&iter, klass); 205 } else { 206 obj = object_new(typename); 207 object_property_iter_init(&iter, obj); 208 } 209 while ((prop = object_property_iter_next(&iter))) { 210 ObjectPropertyInfo *info; 211 212 info = g_malloc0(sizeof(*info)); 213 info->name = g_strdup(prop->name); 214 info->type = g_strdup(prop->type); 215 info->has_description = !!prop->description; 216 info->description = g_strdup(prop->description); 217 218 QAPI_LIST_PREPEND(prop_list, info); 219 } 220 221 object_unref(obj); 222 223 return prop_list; 224 } 225 226 void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp) 227 { 228 QObject *props; 229 QDict *pdict; 230 231 props = qdict_get(qdict, "props"); 232 if (props) { 233 pdict = qobject_to(QDict, props); 234 if (!pdict) { 235 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); 236 return; 237 } 238 qobject_ref(pdict); 239 qdict_del(qdict, "props"); 240 qdict_join(qdict, pdict, false); 241 if (qdict_size(pdict) != 0) { 242 error_setg(errp, "Option in 'props' conflicts with top level"); 243 qobject_unref(pdict); 244 return; 245 } 246 qobject_unref(pdict); 247 } 248 249 user_creatable_add_dict(qdict, false, errp); 250 } 251 252 void qmp_object_del(const char *id, Error **errp) 253 { 254 user_creatable_del(id, errp); 255 } 256