qmp-cmds-control.c (6438B)
1/* 2 * QMP commands related to the monitor (common to sysemu and tools) 3 * 4 * Copyright (c) 2003-2004 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25#include "qemu/osdep.h" 26 27#include "monitor-internal.h" 28#include "qemu-version.h" 29#include "qapi/compat-policy.h" 30#include "qapi/error.h" 31#include "qapi/qapi-commands-control.h" 32#include "qapi/qapi-commands-introspect.h" 33#include "qapi/qapi-emit-events.h" 34#include "qapi/qapi-introspect.h" 35#include "qapi/qapi-visit-introspect.h" 36#include "qapi/qobject-input-visitor.h" 37 38/* 39 * Accept QMP capabilities in @list for @mon. 40 * On success, set mon->qmp.capab[], and return true. 41 * On error, set @errp, and return false. 42 */ 43static bool qmp_caps_accept(MonitorQMP *mon, QMPCapabilityList *list, 44 Error **errp) 45{ 46 GString *unavailable = NULL; 47 bool capab[QMP_CAPABILITY__MAX]; 48 49 memset(capab, 0, sizeof(capab)); 50 51 for (; list; list = list->next) { 52 if (!mon->capab_offered[list->value]) { 53 if (!unavailable) { 54 unavailable = g_string_new(QMPCapability_str(list->value)); 55 } else { 56 g_string_append_printf(unavailable, ", %s", 57 QMPCapability_str(list->value)); 58 } 59 } 60 capab[list->value] = true; 61 } 62 63 if (unavailable) { 64 error_setg(errp, "Capability %s not available", unavailable->str); 65 g_string_free(unavailable, true); 66 return false; 67 } 68 69 memcpy(mon->capab, capab, sizeof(capab)); 70 return true; 71} 72 73void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable, 74 Error **errp) 75{ 76 Monitor *cur_mon = monitor_cur(); 77 MonitorQMP *mon; 78 79 assert(monitor_is_qmp(cur_mon)); 80 mon = container_of(cur_mon, MonitorQMP, common); 81 82 if (mon->commands == &qmp_commands) { 83 error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, 84 "Capabilities negotiation is already complete, command " 85 "ignored"); 86 return; 87 } 88 89 if (!qmp_caps_accept(mon, enable, errp)) { 90 return; 91 } 92 93 mon->commands = &qmp_commands; 94} 95 96VersionInfo *qmp_query_version(Error **errp) 97{ 98 VersionInfo *info = g_new0(VersionInfo, 1); 99 100 info->qemu = g_new0(VersionTriple, 1); 101 info->qemu->major = QEMU_VERSION_MAJOR; 102 info->qemu->minor = QEMU_VERSION_MINOR; 103 info->qemu->micro = QEMU_VERSION_MICRO; 104 info->package = g_strdup(QEMU_PKGVERSION); 105 106 return info; 107} 108 109static void query_commands_cb(const QmpCommand *cmd, void *opaque) 110{ 111 CommandInfo *info; 112 CommandInfoList **list = opaque; 113 114 if (!cmd->enabled) { 115 return; 116 } 117 118 info = g_malloc0(sizeof(*info)); 119 info->name = g_strdup(cmd->name); 120 QAPI_LIST_PREPEND(*list, info); 121} 122 123CommandInfoList *qmp_query_commands(Error **errp) 124{ 125 CommandInfoList *list = NULL; 126 Monitor *cur_mon = monitor_cur(); 127 MonitorQMP *mon; 128 129 assert(monitor_is_qmp(cur_mon)); 130 mon = container_of(cur_mon, MonitorQMP, common); 131 132 qmp_for_each_command(mon->commands, query_commands_cb, &list); 133 134 return list; 135} 136 137static void *split_off_generic_list(void *list, 138 bool (*splitp)(void *elt), 139 void **part) 140{ 141 GenericList *keep = NULL, **keep_tailp = &keep; 142 GenericList *split = NULL, **split_tailp = &split; 143 GenericList *tail; 144 145 for (tail = list; tail; tail = tail->next) { 146 if (splitp(tail)) { 147 *split_tailp = tail; 148 split_tailp = &tail->next; 149 } else { 150 *keep_tailp = tail; 151 keep_tailp = &tail->next; 152 } 153 } 154 155 *keep_tailp = *split_tailp = NULL; 156 *part = split; 157 return keep; 158} 159 160static bool is_in(const char *s, strList *list) 161{ 162 strList *tail; 163 164 for (tail = list; tail; tail = tail->next) { 165 if (!strcmp(tail->value, s)) { 166 return true; 167 } 168 } 169 return false; 170} 171 172static bool is_entity_deprecated(void *link) 173{ 174 return is_in("deprecated", ((SchemaInfoList *)link)->value->features); 175} 176 177static bool is_member_deprecated(void *link) 178{ 179 return is_in("deprecated", 180 ((SchemaInfoObjectMemberList *)link)->value->features); 181} 182 183static SchemaInfoList *zap_deprecated(SchemaInfoList *schema) 184{ 185 void *to_zap; 186 SchemaInfoList *tail; 187 SchemaInfo *ent; 188 189 schema = split_off_generic_list(schema, is_entity_deprecated, &to_zap); 190 qapi_free_SchemaInfoList(to_zap); 191 192 for (tail = schema; tail; tail = tail->next) { 193 ent = tail->value; 194 if (ent->meta_type == SCHEMA_META_TYPE_OBJECT) { 195 ent->u.object.members 196 = split_off_generic_list(ent->u.object.members, 197 is_member_deprecated, &to_zap); 198 qapi_free_SchemaInfoObjectMemberList(to_zap); 199 } 200 } 201 202 return schema; 203} 204 205SchemaInfoList *qmp_query_qmp_schema(Error **errp) 206{ 207 QObject *obj = qobject_from_qlit(&qmp_schema_qlit); 208 Visitor *v = qobject_input_visitor_new(obj); 209 SchemaInfoList *schema = NULL; 210 211 /* test_visitor_in_qmp_introspect() ensures this can't fail */ 212 visit_type_SchemaInfoList(v, NULL, &schema, &error_abort); 213 g_assert(schema); 214 215 qobject_unref(obj); 216 visit_free(v); 217 218 if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) { 219 return zap_deprecated(schema); 220 } 221 return schema; 222}