]>
Commit | Line | Data |
---|---|---|
3950a377 MA |
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" | |
89cf4fe3 | 15 | #include "qapi/qmp/qjson.h" |
cffaca0f | 16 | #include "qemu/readline.h" |
3950a377 | 17 | #include "qom/object.h" |
cffaca0f | 18 | #include "qom/object_interfaces.h" |
3950a377 MA |
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 | } | |
187c6147 | 43 | hmp_handle_error(mon, err); |
3950a377 MA |
44 | } |
45 | ||
46 | void hmp_qom_set(Monitor *mon, const QDict *qdict) | |
47 | { | |
2d9e3dd9 | 48 | const bool json = qdict_get_try_bool(qdict, "json", false); |
3950a377 MA |
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; | |
7d2ef6dc | 53 | |
2d9e3dd9 DH |
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 { | |
5325cc34 | 61 | object_property_parse(obj, property, value, &err); |
2d9e3dd9 DH |
62 | } |
63 | } else { | |
64 | QObject *obj = qobject_from_json(value, &err); | |
65 | ||
66 | if (!err) { | |
67 | qmp_qom_set(path, property, obj, &err); | |
68 | } | |
3950a377 | 69 | } |
7d2ef6dc | 70 | |
187c6147 | 71 | hmp_handle_error(mon, err); |
3950a377 MA |
72 | } |
73 | ||
89cf4fe3 DDAG |
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) { | |
eab3a467 MA |
82 | GString *str = qobject_to_json_pretty(obj, true); |
83 | monitor_printf(mon, "%s\n", str->str); | |
84 | g_string_free(str, true); | |
89cf4fe3 DDAG |
85 | } |
86 | ||
246da7db | 87 | qobject_unref(obj); |
89cf4fe3 DDAG |
88 | hmp_handle_error(mon, err); |
89 | } | |
90 | ||
3950a377 MA |
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 | ||
0dde9fd1 | 98 | static int qom_composition_compare(const void *a, const void *b) |
3950a377 | 99 | { |
0dde9fd1 MA |
100 | return g_strcmp0(object_get_canonical_path_component(*(Object **)a), |
101 | object_get_canonical_path_component(*(Object **)b)); | |
e8c9e658 | 102 | } |
3950a377 | 103 | |
e8c9e658 MA |
104 | static int insert_qom_composition_child(Object *obj, void *opaque) |
105 | { | |
0dde9fd1 | 106 | g_array_append_val(opaque, obj); |
3950a377 MA |
107 | return 0; |
108 | } | |
109 | ||
110 | static void print_qom_composition(Monitor *mon, Object *obj, int indent) | |
111 | { | |
0dde9fd1 | 112 | GArray *children = g_array_new(false, false, sizeof(Object *)); |
7a309cc9 | 113 | const char *name; |
0dde9fd1 | 114 | int i; |
3950a377 MA |
115 | |
116 | if (obj == object_get_root()) { | |
7a309cc9 | 117 | name = ""; |
3950a377 MA |
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)); | |
e8c9e658 | 123 | |
0dde9fd1 MA |
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); | |
e8c9e658 | 130 | } |
0dde9fd1 | 131 | g_array_free(children, TRUE); |
3950a377 MA |
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 | } | |
cffaca0f MA |
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 | } |