1 /* 2 * HMP commands related to QOM 3 * 4 * This work is licensed under the terms of the GNU GPL, version 2 or 5 * later. See the COPYING file in the top-level directory. 6 */ 7 8 #include "qemu/osdep.h" 9 #include "hw/qdev-core.h" 10 #include "monitor/hmp.h" 11 #include "monitor/monitor.h" 12 #include "qapi/error.h" 13 #include "qapi/qapi-commands-qom.h" 14 #include "qapi/qmp/qdict.h" 15 #include "qapi/qmp/qjson.h" 16 #include "qemu/readline.h" 17 #include "qom/object.h" 18 #include "qom/object_interfaces.h" 19 20 void hmp_qom_list(Monitor *mon, const QDict *qdict) 21 { 22 const char *path = qdict_get_try_str(qdict, "path"); 23 ObjectPropertyInfoList *list; 24 Error *err = NULL; 25 26 if (path == NULL) { 27 monitor_printf(mon, "/\n"); 28 return; 29 } 30 31 list = qmp_qom_list(path, &err); 32 if (err == NULL) { 33 ObjectPropertyInfoList *start = list; 34 while (list != NULL) { 35 ObjectPropertyInfo *value = list->value; 36 37 monitor_printf(mon, "%s (%s)\n", 38 value->name, value->type); 39 list = list->next; 40 } 41 qapi_free_ObjectPropertyInfoList(start); 42 } 43 hmp_handle_error(mon, err); 44 } 45 46 void hmp_qom_set(Monitor *mon, const QDict *qdict) 47 { 48 const bool json = qdict_get_try_bool(qdict, "json", false); 49 const char *path = qdict_get_str(qdict, "path"); 50 const char *property = qdict_get_str(qdict, "property"); 51 const char *value = qdict_get_str(qdict, "value"); 52 Error *err = NULL; 53 54 if (!json) { 55 Object *obj = object_resolve_path(path, NULL); 56 57 if (!obj) { 58 error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND, 59 "Device '%s' not found", path); 60 } else { 61 object_property_parse(obj, property, value, &err); 62 } 63 } else { 64 QObject *obj = qobject_from_json(value, &err); 65 66 if (!err) { 67 qmp_qom_set(path, property, obj, &err); 68 } 69 } 70 71 hmp_handle_error(mon, err); 72 } 73 74 void hmp_qom_get(Monitor *mon, const QDict *qdict) 75 { 76 const char *path = qdict_get_str(qdict, "path"); 77 const char *property = qdict_get_str(qdict, "property"); 78 Error *err = NULL; 79 QObject *obj = qmp_qom_get(path, property, &err); 80 81 if (err == NULL) { 82 GString *str = qobject_to_json_pretty(obj, true); 83 monitor_printf(mon, "%s\n", str->str); 84 g_string_free(str, true); 85 } 86 87 qobject_unref(obj); 88 hmp_handle_error(mon, err); 89 } 90 91 typedef struct QOMCompositionState { 92 Monitor *mon; 93 int indent; 94 } QOMCompositionState; 95 96 static void print_qom_composition(Monitor *mon, Object *obj, int indent); 97 98 static int qom_composition_compare(const void *a, const void *b) 99 { 100 return g_strcmp0(object_get_canonical_path_component(*(Object **)a), 101 object_get_canonical_path_component(*(Object **)b)); 102 } 103 104 static int insert_qom_composition_child(Object *obj, void *opaque) 105 { 106 g_array_append_val(opaque, obj); 107 return 0; 108 } 109 110 static void print_qom_composition(Monitor *mon, Object *obj, int indent) 111 { 112 GArray *children = g_array_new(false, false, sizeof(Object *)); 113 const char *name; 114 int i; 115 116 if (obj == object_get_root()) { 117 name = ""; 118 } else { 119 name = object_get_canonical_path_component(obj); 120 } 121 monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name, 122 object_get_typename(obj)); 123 124 object_child_foreach(obj, insert_qom_composition_child, children); 125 g_array_sort(children, qom_composition_compare); 126 127 for (i = 0; i < children->len; i++) { 128 print_qom_composition(mon, g_array_index(children, Object *, i), 129 indent + 2); 130 } 131 g_array_free(children, TRUE); 132 } 133 134 void hmp_info_qom_tree(Monitor *mon, const QDict *dict) 135 { 136 const char *path = qdict_get_try_str(dict, "path"); 137 Object *obj; 138 bool ambiguous = false; 139 140 if (path) { 141 obj = object_resolve_path(path, &ambiguous); 142 if (!obj) { 143 monitor_printf(mon, "Path '%s' could not be resolved.\n", path); 144 return; 145 } 146 if (ambiguous) { 147 monitor_printf(mon, "Warning: Path '%s' is ambiguous.\n", path); 148 return; 149 } 150 } else { 151 obj = qdev_get_machine(); 152 } 153 print_qom_composition(mon, obj, 0); 154 } 155 156 void hmp_object_add(Monitor *mon, const QDict *qdict) 157 { 158 const char *options = qdict_get_str(qdict, "object"); 159 Error *err = NULL; 160 161 user_creatable_add_from_str(options, &err); 162 hmp_handle_error(mon, err); 163 } 164 165 void hmp_object_del(Monitor *mon, const QDict *qdict) 166 { 167 const char *id = qdict_get_str(qdict, "id"); 168 Error *err = NULL; 169 170 user_creatable_del(id, &err); 171 hmp_handle_error(mon, err); 172 } 173 174 void object_add_completion(ReadLineState *rs, int nb_args, const char *str) 175 { 176 GSList *list, *elt; 177 size_t len; 178 179 if (nb_args != 2) { 180 return; 181 } 182 183 len = strlen(str); 184 readline_set_completion_index(rs, len); 185 list = elt = object_class_get_list(TYPE_USER_CREATABLE, false); 186 while (elt) { 187 const char *name; 188 189 name = object_class_get_name(OBJECT_CLASS(elt->data)); 190 if (strcmp(name, TYPE_USER_CREATABLE)) { 191 readline_add_completion_of(rs, str, name); 192 } 193 elt = elt->next; 194 } 195 g_slist_free(list); 196 } 197 198 void object_del_completion(ReadLineState *rs, int nb_args, const char *str) 199 { 200 ObjectPropertyInfoList *list, *start; 201 size_t len; 202 203 if (nb_args != 2) { 204 return; 205 } 206 len = strlen(str); 207 readline_set_completion_index(rs, len); 208 209 start = list = qmp_qom_list("/objects", NULL); 210 while (list) { 211 ObjectPropertyInfo *info = list->value; 212 213 if (!strncmp(info->type, "child<", 5)) { 214 readline_add_completion_of(rs, str, info->name); 215 } 216 list = list->next; 217 } 218 qapi_free_ObjectPropertyInfoList(start); 219 } 220