QAPI patches patches for 2021-03-16
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmBUvgwSHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTo6sP/icaemYrSu5XNjr3caoXTn0rAEYARhcD OLENnlDw2ipnXtB59d7J0AulVk7DR0Ejq0MmoNw2yDYdquhopu0XAxF0TnL51GS1 gd+HygnLVlq/rkDLQn+GIvqzE8+Gx32zHhkQBft7GEHFt4YC5PeOWzG/yYxrt0Za VgjfT8WALx+pM8rYxAULbESZuw7eY7g8aNeJmcDmz7zWViVIZ0jEi3Mubdiq1gdc GM+qv/0BWPcQSba05RJlqY57s0JaoHcZy6Z5ReE11nyYxXssvNTKAg7Bvv/75H7c 2Q4Ls2snqsNPpCzRKRtDbhiwLxQxycQ7Jb+BJ2wGMjOjgBl8B+3h70B/ub/OqEPz VY+T2ekhTPWRidTDjurAXEcT07M8fMI8feiN6WP+4YMtFZoF/L931JMolJtTZKv5 D3Dy3QYpK+TjO6tnA93Jz8L5Am0aEngmHCTu6zWQuXauJxaYALf4tWbmKXZaQX2e ajqfvAT4xb8WI26I+LNcf37TCSl63xVCec6meS0QNBIM1PTl6ovFQhcSrXrOSrkU 6HhCsIg7sZ/2MyW4zuINBdyoTAK+pXVSyutQ/OdMYPueDA64NCB5Mrptw/jejwtu 5JwdevxrHGjnfLVlHFkTtYmH33hCiDtj5RswoONFcXxLanltJtFOtJXYUrkBIAZL j4rbal8z0RzR =DJOJ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-03-16-v4' into staging QAPI patches patches for 2021-03-16 # gpg: Signature made Fri 19 Mar 2021 15:06:52 GMT # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2021-03-16-v4: qapi: New -compat deprecated-input=crash qapi: Implement deprecated-input=reject for QMP command arguments qapi: Implement deprecated-input=reject for QMP commands test-util-sockets: Add stub for monitor_set_cur() qapi: Implement deprecated-output=hide for QMP introspection monitor: Drop query-qmp-schema 'gen': false hack qapi: Implement deprecated-output=hide for QMP event data qapi: Implement deprecated-output=hide for QMP events qapi: Implement deprecated-output=hide for QMP command results qemu-options: New -compat to set policy for deprecated interfaces qemuutil: remove qemu_set_fd_handler duplicate symbol Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2e1293cbaa
38
include/qapi/compat-policy.h
Normal file
38
include/qapi/compat-policy.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Policy for handling "funny" management interfaces
|
||||
*
|
||||
* Copyright (C) 2020 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef QAPI_COMPAT_POLICY_H
|
||||
#define QAPI_COMPAT_POLICY_H
|
||||
|
||||
#include "qapi/qapi-types-compat.h"
|
||||
|
||||
extern CompatPolicy compat_policy;
|
||||
|
||||
/*
|
||||
* Create a QObject input visitor for @obj for use with QMP
|
||||
*
|
||||
* This is like qobject_input_visitor_new(), except it obeys the
|
||||
* policy for handling deprecated management interfaces set with
|
||||
* -compat.
|
||||
*/
|
||||
Visitor *qobject_input_visitor_new_qmp(QObject *obj);
|
||||
|
||||
/*
|
||||
* Create a QObject output visitor for @obj for use with QMP
|
||||
*
|
||||
* This is like qobject_output_visitor_new(), except it obeys the
|
||||
* policy for handling deprecated management interfaces set with
|
||||
* -compat.
|
||||
*/
|
||||
Visitor *qobject_output_visitor_new_qmp(QObject **result);
|
||||
|
||||
#endif
|
@ -26,6 +26,7 @@ typedef enum QmpCommandOptions
|
||||
QCO_ALLOW_OOB = (1U << 1),
|
||||
QCO_ALLOW_PRECONFIG = (1U << 2),
|
||||
QCO_COROUTINE = (1U << 3),
|
||||
QCO_DEPRECATED = (1U << 4),
|
||||
} QmpCommandOptions;
|
||||
|
||||
typedef struct QmpCommand
|
||||
|
@ -15,6 +15,7 @@
|
||||
#ifndef QOBJECT_INPUT_VISITOR_H
|
||||
#define QOBJECT_INPUT_VISITOR_H
|
||||
|
||||
#include "qapi/qapi-types-compat.h"
|
||||
#include "qapi/visitor.h"
|
||||
|
||||
typedef struct QObjectInputVisitor QObjectInputVisitor;
|
||||
@ -58,6 +59,9 @@ typedef struct QObjectInputVisitor QObjectInputVisitor;
|
||||
*/
|
||||
Visitor *qobject_input_visitor_new(QObject *obj);
|
||||
|
||||
void qobject_input_visitor_set_policy(Visitor *v,
|
||||
CompatPolicyInput deprecated);
|
||||
|
||||
/*
|
||||
* Create a QObject input visitor for @obj for use with keyval_parse()
|
||||
*
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define QOBJECT_OUTPUT_VISITOR_H
|
||||
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi/qapi-types-compat.h"
|
||||
|
||||
typedef struct QObjectOutputVisitor QObjectOutputVisitor;
|
||||
|
||||
@ -53,4 +54,7 @@ typedef struct QObjectOutputVisitor QObjectOutputVisitor;
|
||||
*/
|
||||
Visitor *qobject_output_visitor_new(QObject **result);
|
||||
|
||||
void qobject_output_visitor_set_policy(Visitor *v,
|
||||
CompatPolicyOutput deprecated);
|
||||
|
||||
#endif
|
||||
|
@ -113,6 +113,12 @@ struct Visitor
|
||||
The core takes care of the return type in the public interface. */
|
||||
void (*optional)(Visitor *v, const char *name, bool *present);
|
||||
|
||||
/* Optional */
|
||||
bool (*deprecated_accept)(Visitor *v, const char *name, Error **errp);
|
||||
|
||||
/* Optional */
|
||||
bool (*deprecated)(Visitor *v, const char *name);
|
||||
|
||||
/* Must be set */
|
||||
VisitorType type;
|
||||
|
||||
|
@ -459,6 +459,24 @@ void visit_end_alternate(Visitor *v, void **obj);
|
||||
*/
|
||||
bool visit_optional(Visitor *v, const char *name, bool *present);
|
||||
|
||||
/*
|
||||
* Should we reject deprecated member @name?
|
||||
*
|
||||
* @name must not be NULL. This function is only useful between
|
||||
* visit_start_struct() and visit_end_struct(), since only objects
|
||||
* have deprecated members.
|
||||
*/
|
||||
bool visit_deprecated_accept(Visitor *v, const char *name, Error **errp);
|
||||
|
||||
/*
|
||||
* Should we visit deprecated member @name?
|
||||
*
|
||||
* @name must not be NULL. This function is only useful between
|
||||
* visit_start_struct() and visit_end_struct(), since only objects
|
||||
* have deprecated members.
|
||||
*/
|
||||
bool visit_deprecated(Visitor *v, const char *name);
|
||||
|
||||
/*
|
||||
* Visit an enum value.
|
||||
*
|
||||
|
@ -231,8 +231,6 @@ static void monitor_init_qmp_commands(void)
|
||||
|
||||
qmp_init_marshal(&qmp_commands);
|
||||
|
||||
qmp_register_command(&qmp_commands, "query-qmp-schema",
|
||||
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
|
||||
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
|
||||
QCO_NO_OPTIONS);
|
||||
|
||||
|
@ -183,7 +183,4 @@ void help_cmd(Monitor *mon, const char *name);
|
||||
void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
|
||||
int hmp_compare_cmd(const char *name, const char *list);
|
||||
|
||||
void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
|
||||
Error **errp);
|
||||
|
||||
#endif
|
||||
|
@ -26,10 +26,14 @@
|
||||
|
||||
#include "monitor-internal.h"
|
||||
#include "qemu-version.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-control.h"
|
||||
#include "qapi/qapi-commands-introspect.h"
|
||||
#include "qapi/qapi-emit-events.h"
|
||||
#include "qapi/qapi-introspect.h"
|
||||
#include "qapi/qapi-visit-introspect.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
|
||||
/*
|
||||
* Accept QMP capabilities in @list for @mon.
|
||||
@ -130,17 +134,89 @@ CommandInfoList *qmp_query_commands(Error **errp)
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Minor hack: generated marshalling suppressed for this command
|
||||
* ('gen': false in the schema) so we can parse the JSON string
|
||||
* directly into QObject instead of first parsing it with
|
||||
* visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it
|
||||
* to QObject with generated output marshallers, every time. Instead,
|
||||
* we do it in test-qobject-input-visitor.c, just to make sure
|
||||
* qapi-gen.py's output actually conforms to the schema.
|
||||
*/
|
||||
void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
|
||||
Error **errp)
|
||||
static void *split_off_generic_list(void *list,
|
||||
bool (*splitp)(void *elt),
|
||||
void **part)
|
||||
{
|
||||
*ret_data = qobject_from_qlit(&qmp_schema_qlit);
|
||||
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);
|
||||
Visitor *v = qobject_input_visitor_new(obj);
|
||||
SchemaInfoList *schema = NULL;
|
||||
|
||||
/* test_visitor_in_qmp_introspect() ensures this can't fail */
|
||||
visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
|
||||
g_assert(schema);
|
||||
|
||||
qobject_unref(obj);
|
||||
visit_free(v);
|
||||
|
||||
if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) {
|
||||
return zap_deprecated(schema);
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
52
qapi/compat.json
Normal file
52
qapi/compat.json
Normal file
@ -0,0 +1,52 @@
|
||||
# -*- Mode: Python -*-
|
||||
|
||||
##
|
||||
# = Compatibility policy
|
||||
##
|
||||
|
||||
##
|
||||
# @CompatPolicyInput:
|
||||
#
|
||||
# Policy for handling "funny" input.
|
||||
#
|
||||
# @accept: Accept silently
|
||||
# @reject: Reject with an error
|
||||
# @crash: abort() the process
|
||||
#
|
||||
# Since: 6.0
|
||||
##
|
||||
{ 'enum': 'CompatPolicyInput',
|
||||
'data': [ 'accept', 'reject', 'crash' ] }
|
||||
|
||||
##
|
||||
# @CompatPolicyOutput:
|
||||
#
|
||||
# Policy for handling "funny" output.
|
||||
#
|
||||
# @accept: Pass on unchanged
|
||||
# @hide: Filter out
|
||||
#
|
||||
# Since: 6.0
|
||||
##
|
||||
{ 'enum': 'CompatPolicyOutput',
|
||||
'data': [ 'accept', 'hide' ] }
|
||||
|
||||
##
|
||||
# @CompatPolicy:
|
||||
#
|
||||
# Policy for handling deprecated management interfaces.
|
||||
#
|
||||
# This is intended for testing users of the management interfaces.
|
||||
#
|
||||
# Limitation: covers only syntactic aspects of QMP, i.e. stuff tagged
|
||||
# with feature 'deprecated'. We may want to extend it to cover
|
||||
# semantic aspects, CLI, and experimental features.
|
||||
#
|
||||
# @deprecated-input: how to handle deprecated input (default 'accept')
|
||||
# @deprecated-output: how to handle deprecated output (default 'accept')
|
||||
#
|
||||
# Since: 6.0
|
||||
##
|
||||
{ 'struct': 'CompatPolicy',
|
||||
'data': { '*deprecated-input': 'CompatPolicyInput',
|
||||
'*deprecated-output': 'CompatPolicyOutput' } }
|
@ -49,7 +49,7 @@
|
||||
##
|
||||
{ 'command': 'query-qmp-schema',
|
||||
'returns': [ 'SchemaInfo' ],
|
||||
'gen': false } # just to simplify qmp_query_json()
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @SchemaMetaType:
|
||||
|
@ -25,6 +25,7 @@ qapi_all_modules = [
|
||||
'block-export',
|
||||
'char',
|
||||
'common',
|
||||
'compat',
|
||||
'control',
|
||||
'crypto',
|
||||
'dump',
|
||||
|
@ -79,6 +79,7 @@
|
||||
{ 'include': 'migration.json' }
|
||||
{ 'include': 'transaction.json' }
|
||||
{ 'include': 'trace.json' }
|
||||
{ 'include': 'compat.json' }
|
||||
{ 'include': 'control.json' }
|
||||
{ 'include': 'introspect.json' }
|
||||
{ 'include': 'qom.json' }
|
||||
|
@ -135,6 +135,24 @@ bool visit_optional(Visitor *v, const char *name, bool *present)
|
||||
return *present;
|
||||
}
|
||||
|
||||
bool visit_deprecated_accept(Visitor *v, const char *name, Error **errp)
|
||||
{
|
||||
trace_visit_deprecated_accept(v, name);
|
||||
if (v->deprecated_accept) {
|
||||
return v->deprecated_accept(v, name, errp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit_deprecated(Visitor *v, const char *name)
|
||||
{
|
||||
trace_visit_deprecated(v, name);
|
||||
if (v->deprecated) {
|
||||
return v->deprecated(v, name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit_is_input(Visitor *v)
|
||||
{
|
||||
return v->type == VISITOR_INPUT;
|
||||
|
@ -14,15 +14,36 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "block/aio.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/dispatch.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
CompatPolicy compat_policy;
|
||||
|
||||
Visitor *qobject_input_visitor_new_qmp(QObject *obj)
|
||||
{
|
||||
Visitor *v = qobject_input_visitor_new(obj);
|
||||
|
||||
qobject_input_visitor_set_policy(v, compat_policy.deprecated_input);
|
||||
return v;
|
||||
}
|
||||
|
||||
Visitor *qobject_output_visitor_new_qmp(QObject **result)
|
||||
{
|
||||
Visitor *v = qobject_output_visitor_new(result);
|
||||
|
||||
qobject_output_visitor_set_policy(v, compat_policy.deprecated_output);
|
||||
return v;
|
||||
}
|
||||
|
||||
static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
|
||||
Error **errp)
|
||||
{
|
||||
@ -155,6 +176,20 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
|
||||
"The command %s has not been found", command);
|
||||
goto out;
|
||||
}
|
||||
if (cmd->options & QCO_DEPRECATED) {
|
||||
switch (compat_policy.deprecated_input) {
|
||||
case COMPAT_POLICY_INPUT_ACCEPT:
|
||||
break;
|
||||
case COMPAT_POLICY_INPUT_REJECT:
|
||||
error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
|
||||
"Deprecated command %s disabled by policy",
|
||||
command);
|
||||
goto out;
|
||||
case COMPAT_POLICY_INPUT_CRASH:
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (!cmd->enabled) {
|
||||
error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
|
||||
"Command %s has been disabled%s%s",
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <math.h>
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/visitor-impl.h"
|
||||
@ -43,6 +44,7 @@ typedef struct StackObject {
|
||||
|
||||
struct QObjectInputVisitor {
|
||||
Visitor visitor;
|
||||
CompatPolicyInput deprecated_policy;
|
||||
|
||||
/* Root of visit at visitor creation. */
|
||||
QObject *root;
|
||||
@ -662,6 +664,24 @@ static void qobject_input_optional(Visitor *v, const char *name, bool *present)
|
||||
*present = true;
|
||||
}
|
||||
|
||||
static bool qobject_input_deprecated_accept(Visitor *v, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
QObjectInputVisitor *qiv = to_qiv(v);
|
||||
|
||||
switch (qiv->deprecated_policy) {
|
||||
case COMPAT_POLICY_INPUT_ACCEPT:
|
||||
return true;
|
||||
case COMPAT_POLICY_INPUT_REJECT:
|
||||
error_setg(errp, "Deprecated parameter '%s' disabled by policy",
|
||||
name);
|
||||
return false;
|
||||
case COMPAT_POLICY_INPUT_CRASH:
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void qobject_input_free(Visitor *v)
|
||||
{
|
||||
QObjectInputVisitor *qiv = to_qiv(v);
|
||||
@ -696,6 +716,7 @@ static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
|
||||
v->visitor.end_list = qobject_input_end_list;
|
||||
v->visitor.start_alternate = qobject_input_start_alternate;
|
||||
v->visitor.optional = qobject_input_optional;
|
||||
v->visitor.deprecated_accept = qobject_input_deprecated_accept;
|
||||
v->visitor.free = qobject_input_free;
|
||||
|
||||
v->root = qobject_ref(obj);
|
||||
@ -718,6 +739,14 @@ Visitor *qobject_input_visitor_new(QObject *obj)
|
||||
return &v->visitor;
|
||||
}
|
||||
|
||||
void qobject_input_visitor_set_policy(Visitor *v,
|
||||
CompatPolicyInput deprecated)
|
||||
{
|
||||
QObjectInputVisitor *qiv = to_qiv(v);
|
||||
|
||||
qiv->deprecated_policy = deprecated;
|
||||
}
|
||||
|
||||
Visitor *qobject_input_visitor_new_keyval(QObject *obj)
|
||||
{
|
||||
QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qapi/visitor-impl.h"
|
||||
#include "qemu/queue.h"
|
||||
@ -31,6 +32,8 @@ typedef struct QStackEntry {
|
||||
|
||||
struct QObjectOutputVisitor {
|
||||
Visitor visitor;
|
||||
CompatPolicyOutput deprecated_policy;
|
||||
|
||||
QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */
|
||||
QObject *root; /* Root of the output visit */
|
||||
QObject **result; /* User's storage location for result */
|
||||
@ -207,6 +210,13 @@ static bool qobject_output_type_null(Visitor *v, const char *name,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool qobject_output_deprecated(Visitor *v, const char *name)
|
||||
{
|
||||
QObjectOutputVisitor *qov = to_qov(v);
|
||||
|
||||
return qov->deprecated_policy != COMPAT_POLICY_OUTPUT_HIDE;
|
||||
}
|
||||
|
||||
/* Finish building, and return the root object.
|
||||
* The root object is never null. The caller becomes the object's
|
||||
* owner, and should use qobject_unref() when done with it. */
|
||||
@ -256,6 +266,7 @@ Visitor *qobject_output_visitor_new(QObject **result)
|
||||
v->visitor.type_number = qobject_output_type_number;
|
||||
v->visitor.type_any = qobject_output_type_any;
|
||||
v->visitor.type_null = qobject_output_type_null;
|
||||
v->visitor.deprecated = qobject_output_deprecated;
|
||||
v->visitor.complete = qobject_output_complete;
|
||||
v->visitor.free = qobject_output_free;
|
||||
|
||||
@ -264,3 +275,11 @@ Visitor *qobject_output_visitor_new(QObject **result)
|
||||
|
||||
return &v->visitor;
|
||||
}
|
||||
|
||||
void qobject_output_visitor_set_policy(Visitor *v,
|
||||
CompatPolicyOutput deprecated)
|
||||
{
|
||||
QObjectOutputVisitor *qov = to_qov(v);
|
||||
|
||||
qov->deprecated_policy = deprecated;
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ visit_start_alternate(void *v, const char *name, void *obj, size_t size) "v=%p n
|
||||
visit_end_alternate(void *v, void *obj) "v=%p obj=%p"
|
||||
|
||||
visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p"
|
||||
visit_deprecated_accept(void *v, const char *name) "v=%p name=%s"
|
||||
visit_deprecated(void *v, const char *name) "v=%p name=%s"
|
||||
|
||||
visit_type_enum(void *v, const char *name, int *obj) "v=%p name=%s obj=%p"
|
||||
visit_type_int(void *v, const char *name, int64_t *obj) "v=%p name=%s obj=%p"
|
||||
|
@ -3507,6 +3507,28 @@ DEFHEADING()
|
||||
|
||||
DEFHEADING(Debug/Expert options:)
|
||||
|
||||
DEF("compat", HAS_ARG, QEMU_OPTION_compat,
|
||||
"-compat [deprecated-input=accept|reject|crash][,deprecated-output=accept|hide]\n"
|
||||
" Policy for handling deprecated management interfaces\n",
|
||||
QEMU_ARCH_ALL)
|
||||
SRST
|
||||
``-compat [deprecated-input=@var{input-policy}][,deprecated-output=@var{output-policy}]``
|
||||
Set policy for handling deprecated management interfaces (experimental):
|
||||
|
||||
``deprecated-input=accept`` (default)
|
||||
Accept deprecated commands and arguments
|
||||
``deprecated-input=reject``
|
||||
Reject deprecated commands and arguments
|
||||
``deprecated-input=crash``
|
||||
Crash on deprecated commands and arguments
|
||||
``deprecated-output=accept`` (default)
|
||||
Emit deprecated command results and events
|
||||
``deprecated-output=hide``
|
||||
Suppress deprecated command results and events
|
||||
|
||||
Limitation: covers only syntactic aspects of QMP.
|
||||
ERST
|
||||
|
||||
DEF("fw_cfg", HAS_ARG, QEMU_OPTION_fwcfg,
|
||||
"-fw_cfg [name=]<name>,file=<file>\n"
|
||||
" add named fw_cfg entry with contents from file\n"
|
||||
|
@ -96,7 +96,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in,
|
||||
{
|
||||
Visitor *v;
|
||||
|
||||
v = qobject_output_visitor_new(ret_out);
|
||||
v = qobject_output_visitor_new_qmp(ret_out);
|
||||
if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) {
|
||||
visit_complete(v, ret_out);
|
||||
}
|
||||
@ -154,7 +154,7 @@ def gen_marshal(name: str,
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
v = qobject_input_visitor_new(QOBJECT(args));
|
||||
v = qobject_input_visitor_new_qmp(QOBJECT(args));
|
||||
if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
|
||||
goto out;
|
||||
}
|
||||
@ -210,12 +210,16 @@ out:
|
||||
|
||||
|
||||
def gen_register_command(name: str,
|
||||
features: List[QAPISchemaFeature],
|
||||
success_response: bool,
|
||||
allow_oob: bool,
|
||||
allow_preconfig: bool,
|
||||
coroutine: bool) -> str:
|
||||
options = []
|
||||
|
||||
if 'deprecated' in [f.name for f in features]:
|
||||
options += ['QCO_DEPRECATED']
|
||||
|
||||
if not success_response:
|
||||
options += ['QCO_NO_SUCCESS_RESP']
|
||||
if allow_oob:
|
||||
@ -251,10 +255,9 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
|
||||
visit = self._module_basename('qapi-visit', name)
|
||||
self._genc.add(mcgen('''
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/dealloc-visitor.h"
|
||||
#include "qapi/error.h"
|
||||
#include "%(visit)s.h"
|
||||
@ -326,9 +329,9 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
|
||||
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
|
||||
with self._temp_module('./init'):
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genc.add(gen_register_command(name, success_response,
|
||||
allow_oob, allow_preconfig,
|
||||
coroutine))
|
||||
self._genc.add(gen_register_command(
|
||||
name, features, success_response, allow_oob,
|
||||
allow_preconfig, coroutine))
|
||||
|
||||
|
||||
def gen_commands(schema: QAPISchema,
|
||||
|
@ -79,6 +79,7 @@ def gen_param_var(typ: QAPISchemaObjectType) -> str:
|
||||
|
||||
def gen_event_send(name: str,
|
||||
arg_type: Optional[QAPISchemaObjectType],
|
||||
features: List[QAPISchemaFeature],
|
||||
boxed: bool,
|
||||
event_enum_name: str,
|
||||
event_emit: str) -> str:
|
||||
@ -107,6 +108,14 @@ def gen_event_send(name: str,
|
||||
if not boxed:
|
||||
ret += gen_param_var(arg_type)
|
||||
|
||||
if 'deprecated' in [f.name for f in features]:
|
||||
ret += mcgen('''
|
||||
|
||||
if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) {
|
||||
return;
|
||||
}
|
||||
''')
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
qmp = qmp_event_build_dict("%(name)s");
|
||||
@ -117,7 +126,7 @@ def gen_event_send(name: str,
|
||||
if have_args:
|
||||
assert arg_type is not None
|
||||
ret += mcgen('''
|
||||
v = qobject_output_visitor_new(&obj);
|
||||
v = qobject_output_visitor_new_qmp(&obj);
|
||||
''')
|
||||
if not arg_type.is_implicit():
|
||||
ret += mcgen('''
|
||||
@ -136,7 +145,11 @@ def gen_event_send(name: str,
|
||||
ret += mcgen('''
|
||||
|
||||
visit_complete(v, &obj);
|
||||
qdict_put_obj(qmp, "data", obj);
|
||||
if (qdict_size(qobject_to(QDict, obj))) {
|
||||
qdict_put_obj(qmp, "data", obj);
|
||||
} else {
|
||||
qobject_unref(obj);
|
||||
}
|
||||
''')
|
||||
|
||||
ret += mcgen('''
|
||||
@ -176,9 +189,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
|
||||
#include "%(prefix)sqapi-emit-events.h"
|
||||
#include "%(events)s.h"
|
||||
#include "%(visit)s.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qapi/qmp-event.h"
|
||||
|
||||
''',
|
||||
@ -220,7 +233,7 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict);
|
||||
boxed: bool) -> None:
|
||||
with ifcontext(ifcond, self._genh, self._genc):
|
||||
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
|
||||
self._genc.add(gen_event_send(name, arg_type, boxed,
|
||||
self._genc.add(gen_event_send(name, arg_type, features, boxed,
|
||||
self._event_enum_name,
|
||||
self._event_emit_name))
|
||||
# Note: we generate the enum member regardless of @ifcond, to
|
||||
|
@ -77,6 +77,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
|
||||
c_type=base.c_name())
|
||||
|
||||
for memb in members:
|
||||
deprecated = 'deprecated' in [f.name for f in memb.features]
|
||||
ret += gen_if(memb.ifcond)
|
||||
if memb.optional:
|
||||
ret += mcgen('''
|
||||
@ -84,6 +85,15 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
|
||||
''',
|
||||
name=memb.name, c_name=c_name(memb.name))
|
||||
indent.increase()
|
||||
if deprecated:
|
||||
ret += mcgen('''
|
||||
if (!visit_deprecated_accept(v, "%(name)s", errp)) {
|
||||
return false;
|
||||
}
|
||||
if (visit_deprecated(v, "%(name)s")) {
|
||||
''',
|
||||
name=memb.name)
|
||||
indent.increase()
|
||||
ret += mcgen('''
|
||||
if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
|
||||
return false;
|
||||
@ -91,6 +101,11 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
|
||||
''',
|
||||
c_type=memb.type.c_name(), name=memb.name,
|
||||
c_name=c_name(memb.name))
|
||||
if deprecated:
|
||||
indent.decrease()
|
||||
ret += mcgen('''
|
||||
}
|
||||
''')
|
||||
if memb.optional:
|
||||
indent.decrease()
|
||||
ret += mcgen('''
|
||||
|
17
softmmu/vl.c
17
softmmu/vl.c
@ -29,6 +29,7 @@
|
||||
#include "exec/cpu-common.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
@ -114,6 +115,7 @@
|
||||
#include "sysemu/replay.h"
|
||||
#include "qapi/qapi-events-run-state.h"
|
||||
#include "qapi/qapi-visit-block-core.h"
|
||||
#include "qapi/qapi-visit-compat.h"
|
||||
#include "qapi/qapi-visit-ui.h"
|
||||
#include "qapi/qapi-commands-block-core.h"
|
||||
#include "qapi/qapi-commands-migration.h"
|
||||
@ -3452,6 +3454,21 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||
enable_mlock = qemu_opt_get_bool(opts, "mem-lock", false);
|
||||
enable_cpu_pm = qemu_opt_get_bool(opts, "cpu-pm", false);
|
||||
break;
|
||||
case QEMU_OPTION_compat:
|
||||
{
|
||||
CompatPolicy *opts;
|
||||
Visitor *v;
|
||||
|
||||
v = qobject_input_visitor_new_str(optarg, NULL,
|
||||
&error_fatal);
|
||||
|
||||
visit_type_CompatPolicy(v, NULL, &opts, &error_fatal);
|
||||
QAPI_CLONE_MEMBERS(CompatPolicy, &compat_policy, opts);
|
||||
|
||||
qapi_free_CompatPolicy(opts);
|
||||
visit_free(v);
|
||||
break;
|
||||
}
|
||||
case QEMU_OPTION_msg:
|
||||
opts = qemu_opts_parse_noisily(qemu_find_opts("msg"), optarg,
|
||||
false);
|
||||
|
@ -137,8 +137,6 @@ extern QemuOptsList qemu_chardev_opts;
|
||||
static void init_qmp_commands(void)
|
||||
{
|
||||
qmp_init_marshal(&qmp_commands);
|
||||
qmp_register_command(&qmp_commands, "query-qmp-schema",
|
||||
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
|
||||
|
||||
QTAILQ_INIT(&qmp_cap_negotiation_commands);
|
||||
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
|
||||
|
@ -34,7 +34,6 @@ stub_ss.add(files('ram-block.c'))
|
||||
stub_ss.add(files('ramfb.c'))
|
||||
stub_ss.add(files('replay.c'))
|
||||
stub_ss.add(files('runstate-check.c'))
|
||||
stub_ss.add(files('set-fd-handler.c'))
|
||||
stub_ss.add(files('sysbus.c'))
|
||||
stub_ss.add(files('target-get-monitor-def.c'))
|
||||
stub_ss.add(files('target-monitor-defs.c'))
|
||||
|
@ -1,10 +0,0 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
void qemu_set_fd_handler(int fd,
|
||||
IOHandler *fd_read,
|
||||
IOHandler *fd_write,
|
||||
void *opaque)
|
||||
{
|
||||
abort();
|
||||
}
|
@ -299,14 +299,15 @@
|
||||
'features': [ 'feature1' ] }
|
||||
|
||||
{ 'command': 'test-features0',
|
||||
'data': { 'fs0': 'FeatureStruct0',
|
||||
'fs1': 'FeatureStruct1',
|
||||
'fs2': 'FeatureStruct2',
|
||||
'fs3': 'FeatureStruct3',
|
||||
'fs4': 'FeatureStruct4',
|
||||
'cfs1': 'CondFeatureStruct1',
|
||||
'cfs2': 'CondFeatureStruct2',
|
||||
'cfs3': 'CondFeatureStruct3' },
|
||||
'data': { '*fs0': 'FeatureStruct0',
|
||||
'*fs1': 'FeatureStruct1',
|
||||
'*fs2': 'FeatureStruct2',
|
||||
'*fs3': 'FeatureStruct3',
|
||||
'*fs4': 'FeatureStruct4',
|
||||
'*cfs1': 'CondFeatureStruct1',
|
||||
'*cfs2': 'CondFeatureStruct2',
|
||||
'*cfs3': 'CondFeatureStruct3' },
|
||||
'returns': 'FeatureStruct1',
|
||||
'features': [] }
|
||||
|
||||
{ 'command': 'test-command-features1',
|
||||
@ -323,5 +324,8 @@
|
||||
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
|
||||
'defined(TEST_IF_COND_2)'] } ] }
|
||||
|
||||
{ 'event': 'TEST-EVENT-FEATURES0',
|
||||
'data': 'FeatureStruct1' }
|
||||
|
||||
{ 'event': 'TEST-EVENT-FEATURES1',
|
||||
'features': [ 'deprecated' ] }
|
||||
|
@ -409,15 +409,15 @@ alternate FeatureAlternate1
|
||||
case eins: FeatureStruct1
|
||||
feature feature1
|
||||
object q_obj_test-features0-arg
|
||||
member fs0: FeatureStruct0 optional=False
|
||||
member fs1: FeatureStruct1 optional=False
|
||||
member fs2: FeatureStruct2 optional=False
|
||||
member fs3: FeatureStruct3 optional=False
|
||||
member fs4: FeatureStruct4 optional=False
|
||||
member cfs1: CondFeatureStruct1 optional=False
|
||||
member cfs2: CondFeatureStruct2 optional=False
|
||||
member cfs3: CondFeatureStruct3 optional=False
|
||||
command test-features0 q_obj_test-features0-arg -> None
|
||||
member fs0: FeatureStruct0 optional=True
|
||||
member fs1: FeatureStruct1 optional=True
|
||||
member fs2: FeatureStruct2 optional=True
|
||||
member fs3: FeatureStruct3 optional=True
|
||||
member fs4: FeatureStruct4 optional=True
|
||||
member cfs1: CondFeatureStruct1 optional=True
|
||||
member cfs2: CondFeatureStruct2 optional=True
|
||||
member cfs3: CondFeatureStruct3 optional=True
|
||||
command test-features0 q_obj_test-features0-arg -> FeatureStruct1
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
command test-command-features1 None -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
@ -440,6 +440,8 @@ command test-command-cond-features3 None -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
feature feature1
|
||||
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
|
||||
event TEST-EVENT-FEATURES0 FeatureStruct1
|
||||
boxed=False
|
||||
event TEST-EVENT-FEATURES1 None
|
||||
boxed=False
|
||||
feature deprecated
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qnum.h"
|
||||
@ -49,12 +50,17 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
|
||||
{
|
||||
}
|
||||
|
||||
void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
|
||||
FeatureStruct2 *fs2, FeatureStruct3 *fs3,
|
||||
FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1,
|
||||
CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3,
|
||||
Error **errp)
|
||||
FeatureStruct1 *qmp_test_features0(bool has_fs0, FeatureStruct0 *fs0,
|
||||
bool has_fs1, FeatureStruct1 *fs1,
|
||||
bool has_fs2, FeatureStruct2 *fs2,
|
||||
bool has_fs3, FeatureStruct3 *fs3,
|
||||
bool has_fs4, FeatureStruct4 *fs4,
|
||||
bool has_cfs1, CondFeatureStruct1 *cfs1,
|
||||
bool has_cfs2, CondFeatureStruct2 *cfs2,
|
||||
bool has_cfs3, CondFeatureStruct3 *cfs3,
|
||||
Error **errp)
|
||||
{
|
||||
return g_new0(FeatureStruct1, 1);
|
||||
}
|
||||
|
||||
void qmp_test_command_features1(Error **errp)
|
||||
@ -275,6 +281,75 @@ static void test_dispatch_cmd_io(void)
|
||||
qobject_unref(ret3);
|
||||
}
|
||||
|
||||
static void test_dispatch_cmd_deprecated(void)
|
||||
{
|
||||
const char *cmd = "{ 'execute': 'test-command-features1' }";
|
||||
QDict *ret;
|
||||
|
||||
memset(&compat_policy, 0, sizeof(compat_policy));
|
||||
|
||||
/* accept */
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
|
||||
assert(ret && qdict_size(ret) == 0);
|
||||
qobject_unref(ret);
|
||||
|
||||
compat_policy.has_deprecated_input = true;
|
||||
compat_policy.deprecated_input = COMPAT_POLICY_INPUT_ACCEPT;
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
|
||||
assert(ret && qdict_size(ret) == 0);
|
||||
qobject_unref(ret);
|
||||
|
||||
compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT;
|
||||
do_qmp_dispatch_error(false, ERROR_CLASS_COMMAND_NOT_FOUND, cmd);
|
||||
}
|
||||
|
||||
static void test_dispatch_cmd_arg_deprecated(void)
|
||||
{
|
||||
const char *cmd = "{ 'execute': 'test-features0',"
|
||||
" 'arguments': { 'fs1': { 'foo': 42 } } }";
|
||||
QDict *ret;
|
||||
|
||||
memset(&compat_policy, 0, sizeof(compat_policy));
|
||||
|
||||
/* accept */
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
|
||||
assert(ret && qdict_size(ret) == 1);
|
||||
qobject_unref(ret);
|
||||
|
||||
compat_policy.has_deprecated_input = true;
|
||||
compat_policy.deprecated_input = COMPAT_POLICY_INPUT_ACCEPT;
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
|
||||
assert(ret && qdict_size(ret) == 1);
|
||||
qobject_unref(ret);
|
||||
|
||||
compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT;
|
||||
do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR, cmd);
|
||||
}
|
||||
|
||||
static void test_dispatch_cmd_ret_deprecated(void)
|
||||
{
|
||||
const char *cmd = "{ 'execute': 'test-features0' }";
|
||||
QDict *ret;
|
||||
|
||||
memset(&compat_policy, 0, sizeof(compat_policy));
|
||||
|
||||
/* default accept */
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
|
||||
assert(ret && qdict_size(ret) == 1);
|
||||
qobject_unref(ret);
|
||||
|
||||
compat_policy.has_deprecated_output = true;
|
||||
compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_ACCEPT;
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
|
||||
assert(ret && qdict_size(ret) == 1);
|
||||
qobject_unref(ret);
|
||||
|
||||
compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
|
||||
assert(ret && qdict_size(ret) == 0);
|
||||
qobject_unref(ret);
|
||||
}
|
||||
|
||||
/* test generated dealloc functions for generated types */
|
||||
static void test_dealloc_types(void)
|
||||
{
|
||||
@ -349,6 +424,12 @@ int main(int argc, char **argv)
|
||||
g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
|
||||
g_test_add_func("/qmp/dispatch_cmd_success_response",
|
||||
test_dispatch_cmd_success_response);
|
||||
g_test_add_func("/qmp/dispatch_cmd_deprecated",
|
||||
test_dispatch_cmd_deprecated);
|
||||
g_test_add_func("/qmp/dispatch_cmd_arg_deprecated",
|
||||
test_dispatch_cmd_arg_deprecated);
|
||||
g_test_add_func("/qmp/dispatch_cmd_ret_deprecated",
|
||||
test_dispatch_cmd_ret_deprecated);
|
||||
g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
|
||||
g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/compat-policy.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
@ -140,6 +141,44 @@ static void test_event_d(TestEventData *data,
|
||||
qobject_unref(data->expect);
|
||||
}
|
||||
|
||||
static void test_event_deprecated(TestEventData *data, const void *unused)
|
||||
{
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES1' }");
|
||||
|
||||
memset(&compat_policy, 0, sizeof(compat_policy));
|
||||
|
||||
qapi_event_send_test_event_features1();
|
||||
g_assert(data->emitted);
|
||||
|
||||
compat_policy.has_deprecated_output = true;
|
||||
compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
|
||||
data->emitted = false;
|
||||
qapi_event_send_test_event_features1();
|
||||
g_assert(!data->emitted);
|
||||
|
||||
qobject_unref(data->expect);
|
||||
}
|
||||
|
||||
static void test_event_deprecated_data(TestEventData *data, const void *unused)
|
||||
{
|
||||
memset(&compat_policy, 0, sizeof(compat_policy));
|
||||
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0',"
|
||||
" 'data': { 'foo': 42 } }");
|
||||
qapi_event_send_test_event_features0(42);
|
||||
g_assert(data->emitted);
|
||||
|
||||
qobject_unref(data->expect);
|
||||
|
||||
compat_policy.has_deprecated_output = true;
|
||||
compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0' }");
|
||||
qapi_event_send_test_event_features0(42);
|
||||
g_assert(data->emitted);
|
||||
|
||||
qobject_unref(data->expect);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
@ -148,6 +187,8 @@ int main(int argc, char **argv)
|
||||
event_test_add("/event/event_b", test_event_b);
|
||||
event_test_add("/event/event_c", test_event_c);
|
||||
event_test_add("/event/event_d", test_event_d);
|
||||
event_test_add("/event/deprecated", test_event_deprecated);
|
||||
event_test_add("/event/deprecated_data", test_event_deprecated_data);
|
||||
g_test_run();
|
||||
|
||||
return 0;
|
||||
|
@ -73,6 +73,7 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
|
||||
* otherwise we get duplicate syms at link time.
|
||||
*/
|
||||
Monitor *monitor_cur(void) { return cur_mon; }
|
||||
Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); }
|
||||
int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); }
|
||||
|
||||
#ifndef _WIN32
|
||||
|
Loading…
Reference in New Issue
Block a user