From 2df68d777c7abfb80a260021b3db3283f37843a1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 18 Mar 2021 16:55:15 +0100 Subject: [PATCH] qapi: Implement deprecated-output=hide for QMP introspection This policy suppresses deprecated bits in output, and thus permits "testing the future". Implement it for QMP command query-qmp-schema: suppress information on deprecated commands, events and object type members, i.e. anything that has the special feature flag "deprecated". Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20210318155519.1224118-8-armbru@redhat.com> --- monitor/qmp-cmds-control.c | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/monitor/qmp-cmds-control.c b/monitor/qmp-cmds-control.c index d152fd7e59..6e581713a3 100644 --- a/monitor/qmp-cmds-control.c +++ b/monitor/qmp-cmds-control.c @@ -134,6 +134,74 @@ CommandInfoList *qmp_query_commands(Error **errp) return list; } +static void *split_off_generic_list(void *list, + bool (*splitp)(void *elt), + void **part) +{ + GenericList *keep = NULL, **keep_tailp = &keep; + GenericList *split = NULL, **split_tailp = &split; + GenericList *tail; + + for (tail = list; tail; tail = tail->next) { + if (splitp(tail)) { + *split_tailp = tail; + split_tailp = &tail->next; + } else { + *keep_tailp = tail; + keep_tailp = &tail->next; + } + } + + *keep_tailp = *split_tailp = NULL; + *part = split; + return keep; +} + +static bool is_in(const char *s, strList *list) +{ + strList *tail; + + for (tail = list; tail; tail = tail->next) { + if (!strcmp(tail->value, s)) { + return true; + } + } + return false; +} + +static bool is_entity_deprecated(void *link) +{ + return is_in("deprecated", ((SchemaInfoList *)link)->value->features); +} + +static bool is_member_deprecated(void *link) +{ + return is_in("deprecated", + ((SchemaInfoObjectMemberList *)link)->value->features); +} + +static SchemaInfoList *zap_deprecated(SchemaInfoList *schema) +{ + void *to_zap; + SchemaInfoList *tail; + SchemaInfo *ent; + + schema = split_off_generic_list(schema, is_entity_deprecated, &to_zap); + qapi_free_SchemaInfoList(to_zap); + + for (tail = schema; tail; tail = tail->next) { + ent = tail->value; + if (ent->meta_type == SCHEMA_META_TYPE_OBJECT) { + ent->u.object.members + = split_off_generic_list(ent->u.object.members, + is_member_deprecated, &to_zap); + qapi_free_SchemaInfoObjectMemberList(to_zap); + } + } + + return schema; +} + SchemaInfoList *qmp_query_qmp_schema(Error **errp) { QObject *obj = qobject_from_qlit(&qmp_schema_qlit); @@ -147,5 +215,8 @@ SchemaInfoList *qmp_query_qmp_schema(Error **errp) qobject_unref(obj); visit_free(v); + if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) { + return zap_deprecated(schema); + } return schema; }