drop qapi nested structs

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVSPKIAAoJEDhwtADrkYZTtRcP/is2MqiBt7luwL6gtCPzL4xs
 ig3Y618dEfJYz3qp8B8fDhY9keth8Uip/rVSJN8ke12ZBfkuY/pzK/dFnyAh2sb5
 QE5EWcX1yTyUAXbG7arNSQT7ruBQBlMKCQDJJIHvr5Dg4pP1AdlHScCSBrbSYSML
 DHOaO50n/UUXDtDOph9Ghjs+RCuxL/rPyHs3l7hJBOoSXdoMnpej+6SZbOuqqWcV
 J/v9xEYBYITlOItjTYzjnjHeA487AQx5WuJh9I+OPNeu5lMi/jt4YWUDuZfmSy8J
 6E+t9aPFenlr3RnDsP6RERQmPgwPemqYVCAtI9KAqJOxI1zYoZQtJEp1Dnr6AS/I
 snz/2FOFM1dSWTokKx1e0fRRVbKc3Vv6PDK7tMFQk/etnJ2UWxzP3G7kJ8zC2FSI
 NXFaXH7zvsKUis9lBbWlWytiv2YfRlfyUQxL6zLEyhqeF/n3UhoxFJD8KE2C49DZ
 oLZZpesb1N6b5ddQ24pYK+n5BU/9XH3zaSfvSnELcLTMfukrl91/8LL3bgRETuwr
 hoepvp/r2eL1JhNFYYtWLhU8fF2POYZEwjxAOHXCnawCJFi3Vcq2luuSuZvC160+
 lEtSAf+QjrkTMH6XZp1ClWUnglxDC0NNaXaeDB+KY5cU50UTiYeLy+ejsnjQonH1
 dS8UuhwwSFAB8RVvI+SV
 =xvD0
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qmp-2015-05-05' into staging

drop qapi nested structs

# gpg: Signature made Tue May  5 17:40:40 2015 BST using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"

* remotes/armbru/tags/pull-qmp-2015-05-05: (40 commits)
  qapi: Check for member name conflicts with a base class
  qapi: Support (subset of) \u escapes in strings
  qapi: Tweak doc references to QMP when QGA is also meant
  qapi: Drop dead visitor code related to nested structs
  qapi: Drop support for inline nested types
  qapi: Drop inline nested structs in query-pci
  qapi: Drop inline nested struct in query-version
  qapi: Drop tests for inline nested structs
  qapi: Merge UserDefTwo and UserDefNested in tests
  qapi: Forbid 'type' in schema
  qapi: Use 'struct' instead of 'type' in schema
  qapi: Document 'struct' metatype
  qapi: Prefer 'struct' over 'type' in generator
  qapi: More rigorous checking for type safety bypass
  qapi: Whitelist commands that don't return dictionary
  qapi: Require valid names
  qapi: More rigourous checking of types
  qapi: Add some type check tests
  qapi: Unify type bypass and add tests
  qapi: Allow true, false and null in schema json
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-05-05 18:22:12 +01:00
commit 233353ec93
325 changed files with 2105 additions and 923 deletions

View File

@ -1,61 +1,193 @@
= How to use the QAPI code generator =
Copyright IBM Corp. 2011
Copyright (C) 2012-2015 Red Hat, Inc.
This work is licensed under the terms of the GNU GPL, version 2 or
later. See the COPYING file in the top-level directory.
== Introduction ==
QAPI is a native C API within QEMU which provides management-level
functionality to internal/external users. For external
users/processes, this interface is made available by a JSON-based
QEMU Monitor protocol that is provided by the QMP server.
functionality to internal and external users. For external
users/processes, this interface is made available by a JSON-based wire
format for the QEMU Monitor Protocol (QMP) for controlling qemu, as
well as the QEMU Guest Agent (QGA) for communicating with the guest.
The remainder of this document uses "Client JSON Protocol" when
referring to the wire contents of a QMP or QGA connection.
To map QMP-defined interfaces to the native C QAPI implementations,
a JSON-based schema is used to define types and function
signatures, and a set of scripts is used to generate types/signatures,
and marshaling/dispatch code. The QEMU Guest Agent also uses these
scripts, paired with a separate schema, to generate
marshaling/dispatch code for the guest agent server running in the
guest.
This document will describe how the schemas, scripts, and resulting
code are used.
To map Client JSON Protocol interfaces to the native C QAPI
implementations, a JSON-based schema is used to define types and
function signatures, and a set of scripts is used to generate types,
signatures, and marshaling/dispatch code. This document will describe
how the schemas, scripts, and resulting code are used.
== QMP/Guest agent schema ==
This file defines the types, commands, and events used by QMP. It should
fully describe the interface used by QMP.
A QAPI schema file is designed to be loosely based on JSON
(http://www.ietf.org/rfc/rfc7159.txt) with changes for quoting style
and the use of comments; a QAPI schema file is then parsed by a python
code generation program. A valid QAPI schema consists of a series of
top-level expressions, with no commas between them. Where
dictionaries (JSON objects) are used, they are parsed as python
OrderedDicts so that ordering is preserved (for predictable layout of
generated C structs and parameter lists). Ordering doesn't matter
between top-level expressions or the keys within an expression, but
does matter within dictionary values for 'data' and 'returns' members
of a single expression. QAPI schema input is written using 'single
quotes' instead of JSON's "double quotes" (in contrast, Client JSON
Protocol uses no comments, and while input accepts 'single quotes' as
an extension, output is strict JSON using only "double quotes"). As
in JSON, trailing commas are not permitted in arrays or dictionaries.
Input must be ASCII (although QMP supports full Unicode strings, the
QAPI parser does not). At present, there is no place where a QAPI
schema requires the use of JSON numbers or null.
This file is designed to be loosely based on JSON although it's technically
executable Python. While dictionaries are used, they are parsed as
OrderedDicts so that ordering is preserved.
Comments are allowed; anything between an unquoted # and the following
newline is ignored. Although there is not yet a documentation
generator, a form of stylized comments has developed for consistently
documenting details about an expression and when it was added to the
schema. The documentation is delimited between two lines of ##, then
the first line names the expression, an optional overview is provided,
then individual documentation about each member of 'data' is provided,
and finally, a 'Since: x.y.z' tag lists the release that introduced
the expression. Optional fields are tagged with the phrase
'#optional', often with their default value; and extensions added
after the expression was first released are also given a '(since
x.y.z)' comment. For example:
There are two basic syntaxes used, type definitions and command definitions.
##
# @BlockStats:
#
# Statistics of a virtual block device or a block backing device.
#
# @device: #optional If the stats are for a virtual block device, the name
# corresponding to the virtual block device.
#
# @stats: A @BlockDeviceStats for the device.
#
# @parent: #optional This describes the file block device if it has one.
#
# @backing: #optional This describes the backing block device if it has one.
# (Since 2.0)
#
# Since: 0.14.0
##
{ 'struct': 'BlockStats',
'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
'*parent': 'BlockStats',
'*backing': 'BlockStats'} }
The first syntax defines a type and is represented by a dictionary. There are
three kinds of user-defined types that are supported: complex types,
enumeration types and union types.
The schema sets up a series of types, as well as commands and events
that will use those types. Forward references are allowed: the parser
scans in two passes, where the first pass learns all type names, and
the second validates the schema and generates the code. This allows
the definition of complex structs that can have mutually recursive
types, and allows for indefinite nesting of Client JSON Protocol that
satisfies the schema. A type name should not be defined more than
once. It is permissible for the schema to contain additional types
not used by any commands or events in the Client JSON Protocol, for
the side effect of generated C code used internally.
Generally speaking, types definitions should always use CamelCase for the type
names. Command names should be all lower case with words separated by a hyphen.
There are seven top-level expressions recognized by the parser:
'include', 'command', 'struct', 'enum', 'union', 'alternate', and
'event'. There are several groups of types: simple types (a number of
built-in types, such as 'int' and 'str'; as well as enumerations),
complex types (structs and two flavors of unions), and alternate types
(a choice between other types). The 'command' and 'event' expressions
can refer to existing types by name, or list an anonymous type as a
dictionary. Listing a type name inside an array refers to a
single-dimension array of that type; multi-dimension arrays are not
directly supported (although an array of a complex struct that
contains an array member is possible).
Types, commands, and events share a common namespace. Therefore,
generally speaking, type definitions should always use CamelCase for
user-defined type names, while built-in types are lowercase. Type
definitions should not end in 'Kind', as this namespace is used for
creating implicit C enums for visiting union types. Command names,
and field names within a type, should be all lower case with words
separated by a hyphen. However, some existing older commands and
complex types use underscore; when extending such expressions,
consistency is preferred over blindly avoiding underscore. Event
names should be ALL_CAPS with words separated by underscore. The
special string '**' appears for some commands that manually perform
their own type checking rather than relying on the type-safe code
produced by the qapi code generators.
Any name (command, event, type, field, or enum value) beginning with
"x-" is marked experimental, and may be withdrawn or changed
incompatibly in a future release. Downstream vendors may add
extensions; such extensions should begin with a prefix matching
"__RFQDN_" (for the reverse-fully-qualified-domain-name of the
vendor), even if the rest of the name uses dash (example:
__com.redhat_drive-mirror). Other than downstream extensions (with
leading underscore and the use of dots), all names should begin with a
letter, and contain only ASCII letters, digits, dash, and underscore.
It is okay to reuse names that match C keywords; the generator will
rename a field named "default" in the QAPI to "q_default" in the
generated C code.
In the rest of this document, usage lines are given for each
expression type, with literal strings written in lower case and
placeholders written in capitals. If a literal string includes a
prefix of '*', that key/value pair can be omitted from the expression.
For example, a usage statement that includes '*base':STRUCT-NAME
means that an expression has an optional key 'base', which if present
must have a value that forms a struct name.
=== Built-in Types ===
The following types are built-in to the parser:
'str' - arbitrary UTF-8 string
'int' - 64-bit signed integer (although the C code may place further
restrictions on acceptable range)
'number' - floating point number
'bool' - JSON value of true or false
'int8', 'int16', 'int32', 'int64' - like 'int', but enforce maximum
bit size
'uint8', 'uint16', 'uint32', 'uint64' - unsigned counterparts
'size' - like 'uint64', but allows scaled suffix from command line
visitor
=== Includes ===
Usage: { 'include': STRING }
The QAPI schema definitions can be modularized using the 'include' directive:
{ 'include': 'path/to/file.json'}
{ 'include': 'path/to/file.json' }
The directive is evaluated recursively, and include paths are relative to the
file using the directive. Multiple includes of the same file are safe.
file using the directive. Multiple includes of the same file are
safe. No other keys should appear in the expression, and the include
value should be a string.
As a matter of style, it is a good idea to have all files be
self-contained, but at the moment, nothing prevents an included file
from making a forward reference to a type that is only introduced by
an outer file. The parser may be made stricter in the future to
prevent incomplete include files.
=== Complex types ===
=== Struct types ===
A complex type is a dictionary containing a single key whose value is a
dictionary. This corresponds to a struct in C or an Object in JSON. An
example of a complex type is:
Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME }
{ 'type': 'MyType',
A struct is a dictionary containing a single 'data' key whose
value is a dictionary. This corresponds to a struct in C or an Object
in JSON. Each value of the 'data' dictionary must be the name of a
type, or a one-element array containing a type name. An example of a
struct is:
{ 'struct': 'MyType',
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
The use of '*' as a prefix to the name means the member is optional.
The use of '*' as a prefix to the name means the member is optional in
the corresponding JSON protocol usage.
The default initialization value of an optional argument should not be changed
between versions of QEMU unless the new default maintains backward
@ -84,13 +216,13 @@ A structure that is used in both input and output of various commands
must consider the backwards compatibility constraints of both directions
of use.
A complex type definition can specify another complex type as its base.
A struct definition can specify another struct as its base.
In this case, the fields of the base type are included as top-level fields
of the new complex type's dictionary in the QMP wire format. An example
definition is:
of the new struct's dictionary in the Client JSON Protocol wire
format. An example definition is:
{ 'type': 'BlockdevOptionsGenericFormat', 'data': { 'file': 'str' } }
{ 'type': 'BlockdevOptionsGenericCOWFormat',
{ 'struct': 'BlockdevOptionsGenericFormat', 'data': { 'file': 'str' } }
{ 'struct': 'BlockdevOptionsGenericCOWFormat',
'base': 'BlockdevOptionsGenericFormat',
'data': { '*backing': 'str' } }
@ -100,97 +232,158 @@ both fields like this:
{ "file": "/some/place/my-image",
"backing": "/some/place/my-backing-file" }
=== Enumeration types ===
An enumeration type is a dictionary containing a single key whose value is a
list of strings. An example enumeration is:
Usage: { 'enum': STRING, 'data': ARRAY-OF-STRING }
An enumeration type is a dictionary containing a single 'data' key
whose value is a list of strings. An example enumeration is:
{ 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] }
Nothing prevents an empty enumeration, although it is probably not
useful. The list of strings should be lower case; if an enum name
represents multiple words, use '-' between words. The string 'max' is
not allowed as an enum value, and values should not be repeated.
The enumeration values are passed as strings over the Client JSON
Protocol, but are encoded as C enum integral values in generated code.
While the C code starts numbering at 0, it is better to use explicit
comparisons to enum values than implicit comparisons to 0; the C code
will also include a generated enum member ending in _MAX for tracking
the size of the enum, useful when using common functions for
converting between strings and enum values. Since the wire format
always passes by name, it is acceptable to reorder or add new
enumeration members in any location without breaking clients of Client
JSON Protocol; however, removing enum values would break
compatibility. For any struct that has a field that will only contain
a finite set of string values, using an enum type for that field is
better than open-coding the field to be type 'str'.
=== Union types ===
Union types are used to let the user choose between several different data
types. A union type is defined using a dictionary as explained in the
following paragraphs.
Usage: { 'union': STRING, 'data': DICT }
or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,
'discriminator': ENUM-MEMBER-OF-BASE }
Union types are used to let the user choose between several different
variants for an object. There are two flavors: simple (no
discriminator or base), flat (both discriminator and base). A union
type is defined using a data dictionary as explained in the following
paragraphs.
A simple union type defines a mapping from discriminator values to data types
like in this example:
A simple union type defines a mapping from automatic discriminator
values to data types like in this example:
{ 'type': 'FileOptions', 'data': { 'filename': 'str' } }
{ 'type': 'Qcow2Options',
{ 'struct': 'FileOptions', 'data': { 'filename': 'str' } }
{ 'struct': 'Qcow2Options',
'data': { 'backing-file': 'str', 'lazy-refcounts': 'bool' } }
{ 'union': 'BlockdevOptions',
'data': { 'file': 'FileOptions',
'qcow2': 'Qcow2Options' } }
In the QMP wire format, a simple union is represented by a dictionary that
contains the 'type' field as a discriminator, and a 'data' field that is of the
specified data type corresponding to the discriminator value:
In the Client JSON Protocol, a simple union is represented by a
dictionary that contains the 'type' field as a discriminator, and a
'data' field that is of the specified data type corresponding to the
discriminator value, as in these examples:
{ "type": "file", "data" : { "filename": "/some/place/my-image" } }
{ "type": "qcow2", "data" : { "backing-file": "/some/place/my-image",
"lazy-refcounts": true } }
A union definition can specify a complex type as its base. In this case, the
fields of the complex type are included as top-level fields of the union
dictionary in the QMP wire format. An example definition is:
{ 'type': 'BlockdevCommonOptions', 'data': { 'readonly': 'bool' } }
{ 'union': 'BlockdevOptions',
'base': 'BlockdevCommonOptions',
'data': { 'raw': 'RawOptions',
'qcow2': 'Qcow2Options' } }
And it looks like this on the wire:
{ "type": "qcow2",
"readonly": false,
"data" : { "backing-file": "/some/place/my-image",
"lazy-refcounts": true } }
The generated C code uses a struct containing a union. Additionally,
an implicit C enum 'NameKind' is created, corresponding to the union
'Name', for accessing the various branches of the union. No branch of
the union can be named 'max', as this would collide with the implicit
enum. The value for each branch can be of any type.
Flat union types avoid the nesting on the wire. They are used whenever a
specific field of the base type is declared as the discriminator ('type' is
then no longer generated). The discriminator must be of enumeration type.
The above example can then be modified as follows:
A flat union definition specifies a struct as its base, and
avoids nesting on the wire. All branches of the union must be
complex types, and the top-level fields of the union dictionary on
the wire will be combination of fields from both the base type and the
appropriate branch type (when merging two dictionaries, there must be
no keys in common). The 'discriminator' field must be the name of an
enum-typed member of the base struct.
The following example enhances the above simple union example by
adding a common field 'readonly', renaming the discriminator to
something more applicable, and reducing the number of {} required on
the wire:
{ 'enum': 'BlockdevDriver', 'data': [ 'raw', 'qcow2' ] }
{ 'type': 'BlockdevCommonOptions',
{ 'struct': 'BlockdevCommonOptions',
'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
{ 'union': 'BlockdevOptions',
'base': 'BlockdevCommonOptions',
'discriminator': 'driver',
'data': { 'raw': 'RawOptions',
'data': { 'file': 'FileOptions',
'qcow2': 'Qcow2Options' } }
Resulting in this JSON object:
Resulting in these JSON objects:
{ "driver": "qcow2",
"readonly": false,
"backing-file": "/some/place/my-image",
"lazy-refcounts": true }
{ "driver": "file", "readonly": true,
"filename": "/some/place/my-image" }
{ "driver": "qcow2", "readonly": false,
"backing-file": "/some/place/my-image", "lazy-refcounts": true }
Notice that in a flat union, the discriminator name is controlled by
the user, but because it must map to a base member with enum type, the
code generator can ensure that branches exist for all values of the
enum (although the order of the keys need not match the declaration of
the enum). In the resulting generated C data types, a flat union is
represented as a struct with the base member fields included directly,
and then a union of structures for each branch of the struct.
A simple union can always be re-written as a flat union where the base
class has a single member named 'type', and where each branch of the
union has a struct with a single member named 'data'. That is,
{ 'union': 'Simple', 'data': { 'one': 'str', 'two': 'int' } }
is identical on the wire to:
{ 'enum': 'Enum', 'data': ['one', 'two'] }
{ 'struct': 'Base', 'data': { 'type': 'Enum' } }
{ 'struct': 'Branch1', 'data': { 'data': 'str' } }
{ 'struct': 'Branch2', 'data': { 'data': 'int' } }
{ 'union': 'Flat': 'base': 'Base', 'discriminator': 'type',
'data': { 'one': 'Branch1', 'two': 'Branch2' } }
A special type of unions are anonymous unions. They don't form a dictionary in
the wire format but allow the direct use of different types in their place. As
they aren't structured, they don't have any explicit discriminator but use
the (QObject) data type of their value as an implicit discriminator. This means
that they are restricted to using only one discriminator value per QObject
type. For example, you cannot have two different complex types in an anonymous
union, or two different integer types.
=== Alternate types ===
Anonymous unions are declared using an empty dictionary as their discriminator.
The discriminator values never appear on the wire, they are only used in the
generated C code. Anonymous unions cannot have a base type.
Usage: { 'alternate': STRING, 'data': DICT }
{ 'union': 'BlockRef',
'discriminator': {},
An alternate type is one that allows a choice between two or more JSON
data types (string, integer, number, or object, but currently not
array) on the wire. The definition is similar to a simple union type,
where each branch of the union names a QAPI type. For example:
{ 'alternate': 'BlockRef',
'data': { 'definition': 'BlockdevOptions',
'reference': 'str' } }
This example allows using both of the following example objects:
Just like for a simple union, an implicit C enum 'NameKind' is created
to enumerate the branches for the alternate 'Name'.
Unlike a union, the discriminator string is never passed on the wire
for the Client JSON Protocol. Instead, the value's JSON type serves
as an implicit discriminator, which in turn means that an alternate
can only express a choice between types represented differently in
JSON. If a branch is typed as the 'bool' built-in, the alternate
accepts true and false; if it is typed as any of the various numeric
built-ins, it accepts a JSON number; if it is typed as a 'str'
built-in or named enum type, it accepts a JSON string; and if it is
typed as a complex type (struct or union), it accepts a JSON object.
Two different complex types, for instance, aren't permitted, because
both are represented as a JSON object.
The example alternate declaration above allows using both of the
following example objects:
{ "file": "my_existing_block_device_id" }
{ "file": { "driver": "file",
@ -200,23 +393,95 @@ This example allows using both of the following example objects:
=== Commands ===
Commands are defined by using a list containing three members. The first
member is the command name, the second member is a dictionary containing
arguments, and the third member is the return type.
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME-OR-DICT,
'*gen': false, '*success-response': false }
An example command is:
Commands are defined by using a dictionary containing several members,
where three members are most common. The 'command' member is a
mandatory string, and determines the "execute" value passed in a
Client JSON Protocol command exchange.
The 'data' argument maps to the "arguments" dictionary passed in as
part of a Client JSON Protocol command. The 'data' member is optional
and defaults to {} (an empty dictionary). If present, it must be the
string name of a complex type, a one-element array containing the name
of a complex type, or a dictionary that declares an anonymous type
with the same semantics as a 'struct' expression, with one exception
noted below when 'gen' is used.
The 'returns' member describes what will appear in the "return" field
of a Client JSON Protocol reply on successful completion of a command.
The member is optional from the command declaration; if absent, the
"return" field will be an empty dictionary. If 'returns' is present,
it must be the string name of a complex or built-in type, a
one-element array containing the name of a complex or built-in type,
or a dictionary that declares an anonymous type with the same
semantics as a 'struct' expression, with one exception noted below
when 'gen' is used. Although it is permitted to have the 'returns'
member name a built-in type or an array of built-in types, any command
that does this cannot be extended to return additional information in
the future; thus, new commands should strongly consider returning a
dictionary-based type or an array of dictionaries, even if the
dictionary only contains one field at the present.
All commands in Client JSON Protocol use a dictionary to report
failure, with no way to specify that in QAPI. Where the error return
is different than the usual GenericError class in order to help the
client react differently to certain error conditions, it is worth
documenting this in the comments before the command declaration.
Some example commands:
{ 'command': 'my-first-command',
'data': { 'arg1': 'str', '*arg2': 'str' } }
{ 'struct': 'MyType', 'data': { '*value': 'str' } }
{ 'command': 'my-second-command',
'returns': [ 'MyType' ] }
which would validate this Client JSON Protocol transaction:
=> { "execute": "my-first-command",
"arguments": { "arg1": "hello" } }
<= { "return": { } }
=> { "execute": "my-second-command" }
<= { "return": [ { "value": "one" }, { } ] }
In rare cases, QAPI cannot express a type-safe representation of a
corresponding Client JSON Protocol command. In these cases, if the
command expression includes the key 'gen' with boolean value false,
then the 'data' or 'returns' member that intends to bypass generated
type-safety and do its own manual validation should use an inline
dictionary definition, with a value of '**' rather than a valid type
name for the keys that the generated code will not validate. Please
try to avoid adding new commands that rely on this, and instead use
type-safe unions. For an example of bypass usage:
{ 'command': 'netdev_add',
'data': {'type': 'str', 'id': 'str', '*props': '**'},
'gen': false }
Normally, the QAPI schema is used to describe synchronous exchanges,
where a response is expected. But in some cases, the action of a
command is expected to change state in a way that a successful
response is not possible (although the command will still return a
normal dictionary error on failure). When a successful reply is not
possible, the command expression should include the optional key
'success-response' with boolean value false. So far, only QGA makes
use of this field.
{ 'command': 'my-command',
'data': { 'arg1': 'str', '*arg2': 'str' },
'returns': 'str' }
=== Events ===
Events are defined with the keyword 'event'. When 'data' is also specified,
additional info will be included in the event. Finally there will be C API
generated in qapi-event.h; when called by QEMU code, a message with timestamp
will be emitted on the wire. If timestamp is -1, it means failure to retrieve
host time.
Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT }
Events are defined with the keyword 'event'. It is not allowed to
name an event 'MAX', since the generator also produces a C enumeration
of all event names with a generated _MAX value at the end. When
'data' is also specified, additional info will be included in the
event, with similar semantics to a 'struct' expression. Finally there
will be C API generated in qapi-event.h; when called by QEMU code, a
message with timestamp will be emitted on the wire.
An example event is:
@ -234,9 +499,9 @@ Resulting in this JSON object:
Schemas are fed into 3 scripts to generate all the code/files that, paired
with the core QAPI libraries, comprise everything required to take JSON
commands read in by a QMP/guest agent server, unmarshal the arguments into
commands read in by a Client JSON Protocol server, unmarshal the arguments into
the underlying C types, call into the corresponding C function, and map the
response back to a QMP/guest agent response to be returned to the user.
response back to a Client JSON Protocol response to be returned to the user.
As an example, we'll use the following schema, which describes a single
complex user-defined type (which will produce a C struct, along with a list
@ -245,7 +510,7 @@ case we want to accept/return a list of this type with a command), and a
command which takes that type as a parameter and returns the same type:
$ cat example-schema.json
{ 'type': 'UserDefOne',
{ 'struct': 'UserDefOne',
'data': { 'integer': 'int', 'string': 'str' } }
{ 'command': 'my-command',
@ -311,7 +576,7 @@ Example:
#ifndef EXAMPLE_QAPI_TYPES_H
#define EXAMPLE_QAPI_TYPES_H
[Builtin types omitted...]
[Built-in types omitted...]
typedef struct UserDefOne UserDefOne;
@ -324,7 +589,7 @@ Example:
struct UserDefOneList *next;
} UserDefOneList;
[Functions on builtin types omitted...]
[Functions on built-in types omitted...]
struct UserDefOne
{
@ -423,7 +688,7 @@ Example:
#ifndef EXAMPLE_QAPI_VISIT_H
#define EXAMPLE_QAPI_VISIT_H
[Visitors for builtin types omitted...]
[Visitors for built-in types omitted...]
void visit_type_UserDefOne(Visitor *m, UserDefOne **obj, const char *name, Error **errp);
void visit_type_UserDefOneList(Visitor *m, UserDefOneList **obj, const char *name, Error **errp);

View File

@ -1,10 +1,21 @@
QEMU Machine Protocol Specification
0. About This Document
======================
Copyright (C) 2009-2015 Red Hat, Inc.
This work is licensed under the terms of the GNU GPL, version 2 or
later. See the COPYING file in the top-level directory.
1. Introduction
===============
This document specifies the QEMU Machine Protocol (QMP), a JSON-based protocol
which is available for applications to operate QEMU at the machine-level.
This document specifies the QEMU Machine Protocol (QMP), a JSON-based
protocol which is available for applications to operate QEMU at the
machine-level. It is also in use by the QEMU Guest Agent (QGA), which
is available for host applications to interact with the guest
operating system.
2. Protocol Specification
=========================
@ -18,14 +29,27 @@ following format:
json-DATA-STRUCTURE-NAME
Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined by
the JSON standard:
Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined
by the JSON standard:
http://www.ietf.org/rfc/rfc4627.txt
http://www.ietf.org/rfc/rfc7159.txt
For convenience, json-object members and json-array elements mentioned in
this document will be in a certain order. However, in real protocol usage
they can be in ANY order, thus no particular order should be assumed.
The protocol is always encoded in UTF-8 except for synchronization
bytes (documented below); although thanks to json-string escape
sequences, the server will reply using only the strict ASCII subset.
For convenience, json-object members mentioned in this document will
be in a certain order. However, in real protocol usage they can be in
ANY order, thus no particular order should be assumed. On the other
hand, use of json-array elements presumes that preserving order is
important unless specifically documented otherwise. Repeating a key
within a json-object gives unpredictable results.
Also for convenience, the server will accept an extension of
'single-quoted' strings in place of the usual "double-quoted"
json-string, and both input forms of strings understand an additional
escape sequence of "\'" for a single quote. The server will only use
double quoting on output.
2.1 General Definitions
-----------------------
@ -52,7 +76,16 @@ The greeting message format is:
- The "version" member contains the Server's version information (the format
is the same of the query-version command)
- The "capabilities" member specify the availability of features beyond the
baseline specification
baseline specification; the order of elements in this array has no
particular significance, so a client must search the entire array
when looking for a particular capability
2.2.1 Capabilities
------------------
As of the date this document was last revised, no server or client
capability strings have been defined.
2.3 Issuing Commands
--------------------
@ -65,10 +98,14 @@ The format for command execution is:
- The "execute" member identifies the command to be executed by the Server
- The "arguments" member is used to pass any arguments required for the
execution of the command, it is optional when no arguments are required
execution of the command, it is optional when no arguments are
required. Each command documents what contents will be considered
valid when handling the json-argument
- The "id" member is a transaction identification associated with the
command execution, it is optional and will be part of the response if
provided
provided. The "id" member can be any json-value, although most
clients merely use a json-number incremented for each successive
command
2.4 Commands Responses
----------------------
@ -81,13 +118,15 @@ of a command execution: success or error.
The format of a success response is:
{ "return": json-object, "id": json-value }
{ "return": json-value, "id": json-value }
Where,
- The "return" member contains the command returned data, which is defined
in a per-command basis or an empty json-object if the command does not
return data
- The "return" member contains the data returned by the command, which
is defined on a per-command basis (usually a json-object or
json-array of json-objects, but sometimes a json-number, json-string,
or json-array of json-strings); it is an empty json-object if the
command does not return data
- The "id" member contains the transaction identification associated
with the command execution if issued by the Client
@ -114,7 +153,8 @@ if provided by the client.
-----------------------
As a result of state changes, the Server may send messages unilaterally
to the Client at any time. They are called "asynchronous events".
to the Client at any time, when not in the middle of any other
response. They are called "asynchronous events".
The format of asynchronous events is:
@ -126,13 +166,27 @@ The format of asynchronous events is:
- The "event" member contains the event's name
- The "data" member contains event specific data, which is defined in a
per-event basis, it is optional
- The "timestamp" member contains the exact time of when the event occurred
in the Server. It is a fixed json-object with time in seconds and
microseconds
- The "timestamp" member contains the exact time of when the event
occurred in the Server. It is a fixed json-object with time in
seconds and microseconds relative to the Unix Epoch (1 Jan 1970); if
there is a failure to retrieve host time, both members of the
timestamp will be set to -1.
For a listing of supported asynchronous events, please, refer to the
qmp-events.txt file.
2.5 QGA Synchronization
-----------------------
When using QGA, an additional synchronization feature is built into
the protocol. If the Client sends a raw 0xFF sentinel byte (not valid
JSON), then the Server will reset its state and discard all pending
data prior to the sentinel. Conversely, if the Client makes use of
the 'guest-sync-delimited' command, the Server will send a raw 0xFF
sentinel byte prior to its response, to aid the Client in discarding
any data prior to the sentinel.
3. QMP Examples
===============
@ -145,32 +199,37 @@ This section provides some examples of real QMP usage, in all of them
S: { "QMP": { "version": { "qemu": { "micro": 50, "minor": 6, "major": 1 },
"package": ""}, "capabilities": []}}
3.2 Simple 'stop' execution
3.2 Client QMP negotiation
--------------------------
C: { "execute": "qmp_capabilities" }
S: { "return": {}}
3.3 Simple 'stop' execution
---------------------------
C: { "execute": "stop" }
S: { "return": {} }
3.3 KVM information
3.4 KVM information
-------------------
C: { "execute": "query-kvm", "id": "example" }
S: { "return": { "enabled": true, "present": true }, "id": "example"}
3.4 Parsing error
3.5 Parsing error
------------------
C: { "execute": }
S: { "error": { "class": "GenericError", "desc": "Invalid JSON syntax" } }
3.5 Powerdown event
3.6 Powerdown event
-------------------
S: { "timestamp": { "seconds": 1258551470, "microseconds": 802384 },
"event": "POWERDOWN" }
4. Capabilities Negotiation
----------------------------
===========================
When a Client successfully establishes a connection, the Server is in
Capabilities Negotiation mode.
@ -189,7 +248,7 @@ effect, all commands (except qmp_capabilities) are allowed and asynchronous
messages are delivered.
5 Compatibility Considerations
------------------------------
==============================
All protocol changes or new features which modify the protocol format in an
incompatible way are disabled by default and will be advertised by the
@ -213,12 +272,16 @@ However, Clients must not assume any particular:
- Amount of errors generated by a command, that is, new errors can be added
to any existing command in newer versions of the Server
Any command or field name beginning with "x-" is deemed experimental,
and may be withdrawn or changed in an incompatible manner in a future
release.
Of course, the Server does guarantee to send valid JSON. But apart from
this, a Client should be "conservative in what they send, and liberal in
what they accept".
6. Downstream extension of QMP
------------------------------
==============================
We recommend that downstream consumers of QEMU do *not* modify QMP.
Management tools should be able to support both upstream and downstream

28
hmp.c
View File

@ -60,7 +60,7 @@ void hmp_info_version(Monitor *mon, const QDict *qdict)
info = qmp_query_version(NULL);
monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
info->qemu.major, info->qemu.minor, info->qemu.micro,
info->qemu->major, info->qemu->minor, info->qemu->micro,
info->package);
qapi_free_VersionInfo(info);
@ -648,14 +648,14 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
dev->slot, dev->function);
monitor_printf(mon, " ");
if (dev->class_info.has_desc) {
monitor_printf(mon, "%s", dev->class_info.desc);
if (dev->class_info->has_desc) {
monitor_printf(mon, "%s", dev->class_info->desc);
} else {
monitor_printf(mon, "Class %04" PRId64, dev->class_info.q_class);
monitor_printf(mon, "Class %04" PRId64, dev->class_info->q_class);
}
monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
dev->id.vendor, dev->id.device);
dev->id->vendor, dev->id->device);
if (dev->has_irq) {
monitor_printf(mon, " IRQ %" PRId64 ".\n", dev->irq);
@ -663,25 +663,25 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
if (dev->has_pci_bridge) {
monitor_printf(mon, " BUS %" PRId64 ".\n",
dev->pci_bridge->bus.number);
dev->pci_bridge->bus->number);
monitor_printf(mon, " secondary bus %" PRId64 ".\n",
dev->pci_bridge->bus.secondary);
dev->pci_bridge->bus->secondary);
monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
dev->pci_bridge->bus.subordinate);
dev->pci_bridge->bus->subordinate);
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
dev->pci_bridge->bus.io_range->base,
dev->pci_bridge->bus.io_range->limit);
dev->pci_bridge->bus->io_range->base,
dev->pci_bridge->bus->io_range->limit);
monitor_printf(mon,
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
dev->pci_bridge->bus.memory_range->base,
dev->pci_bridge->bus.memory_range->limit);
dev->pci_bridge->bus->memory_range->base,
dev->pci_bridge->bus->memory_range->limit);
monitor_printf(mon, " prefetchable memory range "
"[0x%08"PRIx64", 0x%08"PRIx64"]\n",
dev->pci_bridge->bus.prefetchable_range->base,
dev->pci_bridge->bus.prefetchable_range->limit);
dev->pci_bridge->bus->prefetchable_range->base,
dev->pci_bridge->bus->prefetchable_range->limit);
}
for (region = dev->regions; region; region = region->next) {

View File

@ -1456,24 +1456,26 @@ static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
int bus_num)
{
PciBridgeInfo *info;
PciMemoryRange *range;
info = g_malloc0(sizeof(*info));
info = g_new0(PciBridgeInfo, 1);
info->bus.number = dev->config[PCI_PRIMARY_BUS];
info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
info->bus = g_new0(PciBusInfo, 1);
info->bus->number = dev->config[PCI_PRIMARY_BUS];
info->bus->secondary = dev->config[PCI_SECONDARY_BUS];
info->bus->subordinate = dev->config[PCI_SUBORDINATE_BUS];
info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
range = info->bus->io_range = g_new0(PciMemoryRange, 1);
range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
range = info->bus->memory_range = g_new0(PciMemoryRange, 1);
range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
range = info->bus->prefetchable_range = g_new0(PciMemoryRange, 1);
range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
if (dev->config[PCI_SECONDARY_BUS] != 0) {
PCIBus *child_bus = pci_find_bus_nr(bus, dev->config[PCI_SECONDARY_BUS]);
@ -1494,21 +1496,23 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
uint8_t type;
int class;
info = g_malloc0(sizeof(*info));
info = g_new0(PciDeviceInfo, 1);
info->bus = bus_num;
info->slot = PCI_SLOT(dev->devfn);
info->function = PCI_FUNC(dev->devfn);
info->class_info = g_new0(PciDeviceClass, 1);
class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
info->class_info.q_class = class;
info->class_info->q_class = class;
desc = get_class_desc(class);
if (desc->desc) {
info->class_info.has_desc = true;
info->class_info.desc = g_strdup(desc->desc);
info->class_info->has_desc = true;
info->class_info->desc = g_strdup(desc->desc);
}
info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
info->id = g_new0(PciDeviceId, 1);
info->id->vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
info->id->device = pci_get_word(dev->config + PCI_DEVICE_ID);
info->regions = qmp_query_pci_regions(dev);
info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");

View File

@ -71,7 +71,7 @@
#
# Since 0.14.0
##
{ 'type': 'NameInfo', 'data': {'*name': 'str'} }
{ 'struct': 'NameInfo', 'data': {'*name': 'str'} }
##
# @query-name:
@ -95,7 +95,7 @@
#
# Since: 0.14.0
##
{ 'type': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
{ 'struct': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
##
# @query-kvm:
@ -170,7 +170,7 @@
#
# Notes: @singlestep is enabled through the GDB stub
##
{ 'type': 'StatusInfo',
{ 'struct': 'StatusInfo',
'data': {'running': 'bool', 'singlestep': 'bool', 'status': 'RunState'} }
##
@ -195,7 +195,7 @@
#
# Notes: If no UUID was specified for the guest, a null UUID is returned.
##
{ 'type': 'UuidInfo', 'data': {'UUID': 'str'} }
{ 'struct': 'UuidInfo', 'data': {'UUID': 'str'} }
##
# @query-uuid:
@ -226,7 +226,7 @@
#
# Since: 0.14.0
##
{ 'type': 'ChardevInfo', 'data': {'label': 'str',
{ 'struct': 'ChardevInfo', 'data': {'label': 'str',
'filename': 'str',
'frontend-open': 'bool'} }
@ -250,7 +250,7 @@
#
# Since: 2.0
##
{ 'type': 'ChardevBackendInfo', 'data': {'name': 'str'} }
{ 'struct': 'ChardevBackendInfo', 'data': {'name': 'str'} }
##
# @query-chardev-backends:
@ -339,7 +339,7 @@
#
# Since: 1.2.0
##
{ 'type': 'EventInfo', 'data': {'name': 'str'} }
{ 'struct': 'EventInfo', 'data': {'name': 'str'} }
##
# @query-events:
@ -380,7 +380,7 @@
#
# Since: 0.14.0
##
{ 'type': 'MigrationStats',
{ 'struct': 'MigrationStats',
'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
'duplicate': 'int', 'skipped': 'int', 'normal': 'int',
'normal-bytes': 'int', 'dirty-pages-rate' : 'int',
@ -405,7 +405,7 @@
#
# Since: 1.2
##
{ 'type': 'XBZRLECacheStats',
{ 'struct': 'XBZRLECacheStats',
'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int',
'cache-miss': 'int', 'cache-miss-rate': 'number',
'overflow': 'int' } }
@ -476,7 +476,7 @@
#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
{ 'struct': 'MigrationInfo',
'data': {'*status': 'MigrationStatus', '*ram': 'MigrationStats',
'*disk': 'MigrationStats',
'*xbzrle-cache': 'XBZRLECacheStats',
@ -534,7 +534,7 @@
#
# Since: 1.2
##
{ 'type': 'MigrationCapabilityStatus',
{ 'struct': 'MigrationCapabilityStatus',
'data': { 'capability' : 'MigrationCapability', 'state' : 'bool' } }
##
@ -575,7 +575,7 @@
#
# Since: 0.14.0
##
{ 'type': 'MouseInfo',
{ 'struct': 'MouseInfo',
'data': {'name': 'str', 'index': 'int', 'current': 'bool',
'absolute': 'bool'} }
@ -621,7 +621,7 @@
# Notes: @halted is a transient state that changes frequently. By the time the
# data is sent to the client, the guest may no longer be halted.
##
{ 'type': 'CpuInfo',
{ 'struct': 'CpuInfo',
'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', '*pc': 'int',
'*nip': 'int', '*npc': 'int', '*PC': 'int', 'thread_id': 'int'} }
@ -647,7 +647,7 @@
#
# Since: 2.0
##
{ 'type': 'IOThreadInfo',
{ 'struct': 'IOThreadInfo',
'data': {'id': 'str', 'thread-id': 'int'} }
##
@ -700,7 +700,7 @@
#
# Since: 2.1
##
{ 'type': 'VncBasicInfo',
{ 'struct': 'VncBasicInfo',
'data': { 'host': 'str',
'service': 'str',
'family': 'NetworkAddressFamily',
@ -715,7 +715,7 @@
#
# Since: 2.1
##
{ 'type': 'VncServerInfo',
{ 'struct': 'VncServerInfo',
'base': 'VncBasicInfo',
'data': { '*auth': 'str' } }
@ -732,7 +732,7 @@
#
# Since: 0.14.0
##
{ 'type': 'VncClientInfo',
{ 'struct': 'VncClientInfo',
'base': 'VncBasicInfo',
'data': { '*x509_dname': 'str', '*sasl_username': 'str' } }
@ -772,7 +772,7 @@
#
# Since: 0.14.0
##
{ 'type': 'VncInfo',
{ 'struct': 'VncInfo',
'data': {'enabled': 'bool', '*host': 'str',
'*family': 'NetworkAddressFamily',
'*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
@ -826,7 +826,7 @@
#
# Since: 2.3
##
{ 'type': 'VncInfo2',
{ 'struct': 'VncInfo2',
'data': { 'id' : 'str',
'server' : ['VncBasicInfo'],
'clients' : ['VncClientInfo'],
@ -869,7 +869,7 @@
#
# Since: 2.1
##
{ 'type': 'SpiceBasicInfo',
{ 'struct': 'SpiceBasicInfo',
'data': { 'host': 'str',
'port': 'str',
'family': 'NetworkAddressFamily' } }
@ -883,7 +883,7 @@
#
# Since: 2.1
##
{ 'type': 'SpiceServerInfo',
{ 'struct': 'SpiceServerInfo',
'base': 'SpiceBasicInfo',
'data': { '*auth': 'str' } }
@ -907,7 +907,7 @@
#
# Since: 0.14.0
##
{ 'type': 'SpiceChannel',
{ 'struct': 'SpiceChannel',
'base': 'SpiceBasicInfo',
'data': {'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
'tls': 'bool'} }
@ -965,7 +965,7 @@
#
# Since: 0.14.0
##
{ 'type': 'SpiceInfo',
{ 'struct': 'SpiceInfo',
'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
@ -991,7 +991,7 @@
# Since: 0.14.0
#
##
{ 'type': 'BalloonInfo', 'data': {'actual': 'int' } }
{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
##
# @query-balloon:
@ -1018,7 +1018,7 @@
#
# Since: 0.14.0
##
{ 'type': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
{ 'struct': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
##
# @PciMemoryRegion
@ -1036,41 +1036,80 @@
#
# Since: 0.14.0
##
{ 'type': 'PciMemoryRegion',
{ 'struct': 'PciMemoryRegion',
'data': {'bar': 'int', 'type': 'str', 'address': 'int', 'size': 'int',
'*prefetch': 'bool', '*mem_type_64': 'bool' } }
##
# @PciBusInfo:
#
# Information about a bus of a PCI Bridge device
#
# @number: primary bus interface number. This should be the number of the
# bus the device resides on.
#
# @secondary: secondary bus interface number. This is the number of the
# main bus for the bridge
#
# @subordinate: This is the highest number bus that resides below the
# bridge.
#
# @io_range: The PIO range for all devices on this bridge
#
# @memory_range: The MMIO range for all devices on this bridge
#
# @prefetchable_range: The range of prefetchable MMIO for all devices on
# this bridge
#
# Since: 2.4
##
{ 'struct': 'PciBusInfo',
'data': {'number': 'int', 'secondary': 'int', 'subordinate': 'int',
'io_range': 'PciMemoryRange',
'memory_range': 'PciMemoryRange',
'prefetchable_range': 'PciMemoryRange' } }
##
# @PciBridgeInfo:
#
# Information about a PCI Bridge device
#
# @bus.number: primary bus interface number. This should be the number of the
# bus the device resides on.
#
# @bus.secondary: secondary bus interface number. This is the number of the
# main bus for the bridge
#
# @bus.subordinate: This is the highest number bus that resides below the
# bridge.
#
# @bus.io_range: The PIO range for all devices on this bridge
#
# @bus.memory_range: The MMIO range for all devices on this bridge
#
# @bus.prefetchable_range: The range of prefetchable MMIO for all devices on
# this bridge
# @bus: information about the bus the device resides on
#
# @devices: a list of @PciDeviceInfo for each device on this bridge
#
# Since: 0.14.0
##
{ 'type': 'PciBridgeInfo',
'data': {'bus': { 'number': 'int', 'secondary': 'int', 'subordinate': 'int',
'io_range': 'PciMemoryRange',
'memory_range': 'PciMemoryRange',
'prefetchable_range': 'PciMemoryRange' },
'*devices': ['PciDeviceInfo']} }
{ 'struct': 'PciBridgeInfo',
'data': {'bus': 'PciBusInfo', '*devices': ['PciDeviceInfo']} }
##
# @PciDeviceClass:
#
# Information about the Class of a PCI device
#
# @desc: #optional a string description of the device's class
#
# @class: the class code of the device
#
# Since: 2.4
##
{ 'struct': 'PciDeviceClass',
'data': {'*desc': 'str', 'class': 'int'} }
##
# @PciDeviceId:
#
# Information about the Id of a PCI device
#
# @device: the PCI device id
#
# @vendor: the PCI vendor id
#
# Since: 2.4
##
{ 'struct': 'PciDeviceId',
'data': {'device': 'int', 'vendor': 'int'} }
##
# @PciDeviceInfo:
@ -1083,13 +1122,9 @@
#
# @function: the function of the slot used by the device
#
# @class_info.desc: #optional a string description of the device's class
# @class_info: the class of the device
#
# @class_info.class: the class code of the device
#
# @id.device: the PCI device id
#
# @id.vendor: the PCI vendor id
# @id: the PCI device id
#
# @irq: #optional if an IRQ is assigned to the device, the IRQ number
#
@ -1104,10 +1139,9 @@
#
# Since: 0.14.0
##
{ 'type': 'PciDeviceInfo',
{ 'struct': 'PciDeviceInfo',
'data': {'bus': 'int', 'slot': 'int', 'function': 'int',
'class_info': {'*desc': 'str', 'class': 'int'},
'id': {'device': 'int', 'vendor': 'int'},
'class_info': 'PciDeviceClass', 'id': 'PciDeviceId',
'*irq': 'int', 'qdev_id': 'str', '*pci_bridge': 'PciBridgeInfo',
'regions': ['PciMemoryRegion']} }
@ -1122,7 +1156,7 @@
#
# Since: 0.14.0
##
{ 'type': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
{ 'struct': 'PciInfo', 'data': {'bus': 'int', 'devices': ['PciDeviceInfo']} }
##
# @query-pci:
@ -1341,7 +1375,7 @@
#
# Since: 1.6
###
{ 'type': 'Abort',
{ 'struct': 'Abort',
'data': { } }
##
@ -1506,7 +1540,7 @@
#
# Since: 1.2
##
{ 'type': 'ObjectPropertyInfo',
{ 'struct': 'ObjectPropertyInfo',
'data': { 'name': 'str', 'type': 'str' } }
##
@ -1561,8 +1595,8 @@
##
{ 'command': 'qom-get',
'data': { 'path': 'str', 'property': 'str' },
'returns': 'visitor',
'gen': 'no' }
'returns': '**',
'gen': false }
##
# @qom-set:
@ -1579,8 +1613,8 @@
# Since: 1.2
##
{ 'command': 'qom-set',
'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
'gen': 'no' }
'data': { 'path': 'str', 'property': 'str', 'value': '**' },
'gen': false }
##
# @set_password:
@ -1691,7 +1725,7 @@
#
# Notes: This command is experimental and may change syntax in future releases.
##
{ 'type': 'ObjectTypeInfo',
{ 'struct': 'ObjectTypeInfo',
'data': { 'name': 'str' } }
##
@ -1723,7 +1757,7 @@
#
# Since: 1.2
##
{ 'type': 'DevicePropertyInfo',
{ 'struct': 'DevicePropertyInfo',
'data': { 'name': 'str', 'type': 'str', '*description': 'str' } }
##
@ -1903,7 +1937,7 @@
#
# Since: 2.0
##
{ 'type': 'DumpGuestMemoryCapability',
{ 'struct': 'DumpGuestMemoryCapability',
'data': {
'formats': ['DumpGuestMemoryFormat'] } }
@ -1943,7 +1977,7 @@
##
{ 'command': 'netdev_add',
'data': {'type': 'str', 'id': 'str', '*props': '**'},
'gen': 'no' }
'gen': false }
##
# @netdev_del:
@ -1976,8 +2010,8 @@
# Since: 2.0
##
{ 'command': 'object-add',
'data': {'qom-type': 'str', 'id': 'str', '*props': 'dict'},
'gen': 'no' }
'data': {'qom-type': 'str', 'id': 'str', '*props': '**'},
'gen': false }
##
# @object-del:
@ -2000,7 +2034,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevNoneOptions',
{ 'struct': 'NetdevNoneOptions',
'data': { } }
##
@ -2020,7 +2054,7 @@
#
# Since 1.2
##
{ 'type': 'NetLegacyNicOptions',
{ 'struct': 'NetLegacyNicOptions',
'data': {
'*netdev': 'str',
'*macaddr': 'str',
@ -2035,7 +2069,7 @@
#
# Since 1.2
##
{ 'type': 'String',
{ 'struct': 'String',
'data': {
'str': 'str' } }
@ -2078,7 +2112,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevUserOptions',
{ 'struct': 'NetdevUserOptions',
'data': {
'*hostname': 'str',
'*restrict': 'bool',
@ -2130,7 +2164,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevTapOptions',
{ 'struct': 'NetdevTapOptions',
'data': {
'*ifname': 'str',
'*fd': 'str',
@ -2166,7 +2200,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevSocketOptions',
{ 'struct': 'NetdevSocketOptions',
'data': {
'*fd': 'str',
'*listen': 'str',
@ -2214,7 +2248,7 @@
#
# Since 2.1
##
{ 'type': 'NetdevL2TPv3Options',
{ 'struct': 'NetdevL2TPv3Options',
'data': {
'src': 'str',
'dst': 'str',
@ -2246,7 +2280,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevVdeOptions',
{ 'struct': 'NetdevVdeOptions',
'data': {
'*sock': 'str',
'*port': 'uint16',
@ -2265,7 +2299,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevDumpOptions',
{ 'struct': 'NetdevDumpOptions',
'data': {
'*len': 'size',
'*file': 'str' } }
@ -2281,7 +2315,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevBridgeOptions',
{ 'struct': 'NetdevBridgeOptions',
'data': {
'*br': 'str',
'*helper': 'str' } }
@ -2295,7 +2329,7 @@
#
# Since 1.2
##
{ 'type': 'NetdevHubPortOptions',
{ 'struct': 'NetdevHubPortOptions',
'data': {
'hubid': 'int32' } }
@ -2315,7 +2349,7 @@
#
# Since 2.0
##
{ 'type': 'NetdevNetmapOptions',
{ 'struct': 'NetdevNetmapOptions',
'data': {
'ifname': 'str',
'*devname': 'str' } }
@ -2331,7 +2365,7 @@
#
# Since 2.1
##
{ 'type': 'NetdevVhostUserOptions',
{ 'struct': 'NetdevVhostUserOptions',
'data': {
'chardev': 'str',
'*vhostforce': 'bool' } }
@ -2376,7 +2410,7 @@
#
# Since 1.2
##
{ 'type': 'NetLegacy',
{ 'struct': 'NetLegacy',
'data': {
'*vlan': 'int32',
'*id': 'str',
@ -2394,7 +2428,7 @@
#
# Since 1.2
##
{ 'type': 'Netdev',
{ 'struct': 'Netdev',
'data': {
'id': 'str',
'opts': 'NetClientOptions' } }
@ -2418,7 +2452,7 @@
#
# Since 1.3
##
{ 'type': 'InetSocketAddress',
{ 'struct': 'InetSocketAddress',
'data': {
'host': 'str',
'port': 'str',
@ -2435,7 +2469,7 @@
#
# Since 1.3
##
{ 'type': 'UnixSocketAddress',
{ 'struct': 'UnixSocketAddress',
'data': {
'path': 'str' } }
@ -2500,7 +2534,7 @@
#
# Since: 1.2.0
##
{ 'type': 'MachineInfo',
{ 'struct': 'MachineInfo',
'data': { 'name': 'str', '*alias': 'str',
'*is-default': 'bool', 'cpu-max': 'int' } }
@ -2524,7 +2558,7 @@
#
# Since: 1.2.0
##
{ 'type': 'CpuDefinitionInfo',
{ 'struct': 'CpuDefinitionInfo',
'data': { 'name': 'str' } }
##
@ -2549,7 +2583,7 @@
#
# Since: 1.2.0
##
{ 'type': 'AddfdInfo', 'data': {'fdset-id': 'int', 'fd': 'int'} }
{ 'struct': 'AddfdInfo', 'data': {'fdset-id': 'int', 'fd': 'int'} }
##
# @add-fd:
@ -2605,7 +2639,7 @@
#
# Since: 1.2.0
##
{ 'type': 'FdsetFdInfo',
{ 'struct': 'FdsetFdInfo',
'data': {'fd': 'int', '*opaque': 'str'} }
##
@ -2619,7 +2653,7 @@
#
# Since: 1.2.0
##
{ 'type': 'FdsetInfo',
{ 'struct': 'FdsetInfo',
'data': {'fdset-id': 'int', 'fds': ['FdsetFdInfo']} }
##
@ -2645,7 +2679,7 @@
#
# Since: 1.2.0
##
{ 'type': 'TargetInfo',
{ 'struct': 'TargetInfo',
'data': { 'arch': 'str' } }
##
@ -2745,7 +2779,7 @@
#
# Since: 1.4
##
{ 'type': 'ChardevFile', 'data': { '*in' : 'str',
{ 'struct': 'ChardevFile', 'data': { '*in' : 'str',
'out' : 'str' } }
##
@ -2759,7 +2793,7 @@
#
# Since: 1.4
##
{ 'type': 'ChardevHostdev', 'data': { 'device' : 'str' } }
{ 'struct': 'ChardevHostdev', 'data': { 'device' : 'str' } }
##
# @ChardevSocket:
@ -2781,7 +2815,7 @@
#
# Since: 1.4
##
{ 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress',
{ 'struct': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress',
'*server' : 'bool',
'*wait' : 'bool',
'*nodelay' : 'bool',
@ -2798,7 +2832,7 @@
#
# Since: 1.5
##
{ 'type': 'ChardevUdp', 'data': { 'remote' : 'SocketAddress',
{ 'struct': 'ChardevUdp', 'data': { 'remote' : 'SocketAddress',
'*local' : 'SocketAddress' } }
##
@ -2810,7 +2844,7 @@
#
# Since: 1.5
##
{ 'type': 'ChardevMux', 'data': { 'chardev' : 'str' } }
{ 'struct': 'ChardevMux', 'data': { 'chardev' : 'str' } }
##
# @ChardevStdio:
@ -2823,7 +2857,7 @@
#
# Since: 1.5
##
{ 'type': 'ChardevStdio', 'data': { '*signal' : 'bool' } }
{ 'struct': 'ChardevStdio', 'data': { '*signal' : 'bool' } }
##
# @ChardevSpiceChannel:
@ -2834,7 +2868,7 @@
#
# Since: 1.5
##
{ 'type': 'ChardevSpiceChannel', 'data': { 'type' : 'str' } }
{ 'struct': 'ChardevSpiceChannel', 'data': { 'type' : 'str' } }
##
# @ChardevSpicePort:
@ -2845,7 +2879,7 @@
#
# Since: 1.5
##
{ 'type': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' } }
{ 'struct': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' } }
##
# @ChardevVC:
@ -2859,7 +2893,7 @@
#
# Since: 1.5
##
{ 'type': 'ChardevVC', 'data': { '*width' : 'int',
{ 'struct': 'ChardevVC', 'data': { '*width' : 'int',
'*height' : 'int',
'*cols' : 'int',
'*rows' : 'int' } }
@ -2873,7 +2907,7 @@
#
# Since: 1.5
##
{ 'type': 'ChardevRingbuf', 'data': { '*size' : 'int' } }
{ 'struct': 'ChardevRingbuf', 'data': { '*size' : 'int' } }
##
# @ChardevBackend:
@ -2882,7 +2916,7 @@
#
# Since: 1.4 (testdev since 2.2)
##
{ 'type': 'ChardevDummy', 'data': { } }
{ 'struct': 'ChardevDummy', 'data': { } }
{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
'serial' : 'ChardevHostdev',
@ -2915,7 +2949,7 @@
#
# Since: 1.4
##
{ 'type' : 'ChardevReturn', 'data': { '*pty' : 'str' } }
{ 'struct' : 'ChardevReturn', 'data': { '*pty' : 'str' } }
##
# @chardev-add:
@ -3002,7 +3036,7 @@
#
# Since: 1.5
##
{ 'type': 'TPMPassthroughOptions', 'data': { '*path' : 'str',
{ 'struct': 'TPMPassthroughOptions', 'data': { '*path' : 'str',
'*cancel-path' : 'str'} }
##
@ -3030,7 +3064,7 @@
#
# Since: 1.5
##
{ 'type': 'TPMInfo',
{ 'struct': 'TPMInfo',
'data': {'id': 'str',
'model': 'TpmModel',
'options': 'TpmTypeOptions' } }
@ -3092,7 +3126,7 @@
#
# Since 1.5
##
{ 'type': 'AcpiTableOptions',
{ 'struct': 'AcpiTableOptions',
'data': {
'*sig': 'str',
'*rev': 'uint8',
@ -3138,7 +3172,7 @@
#
# Since 1.5
##
{ 'type': 'CommandLineParameterInfo',
{ 'struct': 'CommandLineParameterInfo',
'data': { 'name': 'str',
'type': 'CommandLineParameterType',
'*help': 'str',
@ -3155,7 +3189,7 @@
#
# Since 1.5
##
{ 'type': 'CommandLineOptionInfo',
{ 'struct': 'CommandLineOptionInfo',
'data': { 'option': 'str', 'parameters': ['CommandLineParameterInfo'] } }
##
@ -3199,7 +3233,7 @@
#
# Since: 1.5
##
{ 'type': 'X86CPUFeatureWordInfo',
{ 'struct': 'X86CPUFeatureWordInfo',
'data': { 'cpuid-input-eax': 'int',
'*cpuid-input-ecx': 'int',
'cpuid-register': 'X86CPURegister32',
@ -3252,7 +3286,7 @@
# Since 1.6
##
{ 'type': 'RxFilterInfo',
{ 'struct': 'RxFilterInfo',
'data': {
'name': 'str',
'promiscuous': 'bool',
@ -3314,7 +3348,7 @@
#
# Since: 2.0
##
{ 'type' : 'InputKeyEvent',
{ 'struct' : 'InputKeyEvent',
'data' : { 'key' : 'KeyValue',
'down' : 'bool' } }
@ -3328,7 +3362,7 @@
#
# Since: 2.0
##
{ 'type' : 'InputBtnEvent',
{ 'struct' : 'InputBtnEvent',
'data' : { 'button' : 'InputButton',
'down' : 'bool' } }
@ -3343,7 +3377,7 @@
#
# Since: 2.0
##
{ 'type' : 'InputMoveEvent',
{ 'struct' : 'InputMoveEvent',
'data' : { 'axis' : 'InputAxis',
'value' : 'int' } }
@ -3426,7 +3460,7 @@
#
# Since: 2.1
##
{ 'type': 'NumaNodeOptions',
{ 'struct': 'NumaNodeOptions',
'data': {
'*nodeid': 'uint16',
'*cpus': ['uint16'],
@ -3473,7 +3507,7 @@
# Since: 2.1
##
{ 'type': 'Memdev',
{ 'struct': 'Memdev',
'data': {
'size': 'size',
'merge': 'bool',
@ -3516,7 +3550,7 @@
#
# Since: 2.1
##
{ 'type': 'PCDIMMDeviceInfo',
{ 'struct': 'PCDIMMDeviceInfo',
'data': { '*id': 'str',
'addr': 'int',
'size': 'int',
@ -3570,7 +3604,7 @@
#
# Since: 2.1
##
{ 'type': 'ACPIOSTInfo',
{ 'struct': 'ACPIOSTInfo',
'data' : { '*device': 'str',
'slot': 'str',
'slot-type': 'ACPISlotType',

View File

@ -26,7 +26,7 @@
#
##
{ 'type': 'SnapshotInfo',
{ 'struct': 'SnapshotInfo',
'data': { 'id': 'str', 'name': 'str', 'vm-state-size': 'int',
'date-sec': 'int', 'date-nsec': 'int',
'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } }
@ -45,7 +45,7 @@
#
# Since: 1.7
##
{ 'type': 'ImageInfoSpecificQCow2',
{ 'struct': 'ImageInfoSpecificQCow2',
'data': {
'compat': 'str',
'*lazy-refcounts': 'bool',
@ -66,7 +66,7 @@
#
# Since: 1.7
##
{ 'type': 'ImageInfoSpecificVmdk',
{ 'struct': 'ImageInfoSpecificVmdk',
'data': {
'create-type': 'str',
'cid': 'int',
@ -126,7 +126,7 @@
#
##
{ 'type': 'ImageInfo',
{ 'struct': 'ImageInfo',
'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool',
'*actual-size': 'int', 'virtual-size': 'int',
'*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool',
@ -178,7 +178,7 @@
#
##
{ 'type': 'ImageCheck',
{ 'struct': 'ImageCheck',
'data': {'filename': 'str', 'format': 'str', 'check-errors': 'int',
'*image-end-offset': 'int', '*corruptions': 'int', '*leaks': 'int',
'*corruptions-fixed': 'int', '*leaks-fixed': 'int',
@ -196,7 +196,7 @@
#
# Since: 2.3
##
{ 'type': 'BlockdevCacheInfo',
{ 'struct': 'BlockdevCacheInfo',
'data': { 'writeback': 'bool',
'direct': 'bool',
'no-flush': 'bool' } }
@ -267,7 +267,7 @@
# Since: 0.14.0
#
##
{ 'type': 'BlockDeviceInfo',
{ 'struct': 'BlockDeviceInfo',
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'backing_file_depth': 'int',
'encrypted': 'bool', 'encryption_key_missing': 'bool',
@ -321,7 +321,7 @@
#
# Since 1.7
##
{ 'type': 'BlockDeviceMapEntry',
{ 'struct': 'BlockDeviceMapEntry',
'data': { 'start': 'int', 'length': 'int', 'depth': 'int', 'zero': 'bool',
'data': 'bool', '*offset': 'int' } }
@ -340,7 +340,7 @@
#
# Since: 1.3
##
{ 'type': 'BlockDirtyInfo',
{ 'struct': 'BlockDirtyInfo',
'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32',
'frozen': 'bool'} }
@ -375,7 +375,7 @@
#
# Since: 0.14.0
##
{ 'type': 'BlockInfo',
{ 'struct': 'BlockInfo',
'data': {'device': 'str', 'type': 'str', 'removable': 'bool',
'locked': 'bool', '*inserted': 'BlockDeviceInfo',
'*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus',
@ -428,7 +428,7 @@
#
# Since: 0.14.0
##
{ 'type': 'BlockDeviceStats',
{ 'struct': 'BlockDeviceStats',
'data': {'rd_bytes': 'int', 'wr_bytes': 'int', 'rd_operations': 'int',
'wr_operations': 'int', 'flush_operations': 'int',
'flush_total_time_ns': 'int', 'wr_total_time_ns': 'int',
@ -454,7 +454,7 @@
#
# Since: 0.14.0
##
{ 'type': 'BlockStats',
{ 'struct': 'BlockStats',
'data': {'*device': 'str', '*node-name': 'str',
'stats': 'BlockDeviceStats',
'*parent': 'BlockStats',
@ -567,7 +567,7 @@
#
# Since: 1.1
##
{ 'type': 'BlockJobInfo',
{ 'struct': 'BlockJobInfo',
'data': {'type': 'str', 'device': 'str', 'len': 'int',
'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'int',
'io-status': 'BlockDeviceIoStatus', 'ready': 'bool'} }
@ -677,7 +677,7 @@
# @mode: #optional whether and how QEMU should create a new image, default is
# 'absolute-paths'.
##
{ 'type': 'BlockdevSnapshot',
{ 'struct': 'BlockdevSnapshot',
'data': { '*device': 'str', '*node-name': 'str',
'snapshot-file': 'str', '*snapshot-node-name': 'str',
'*format': 'str', '*mode': 'NewImageMode' } }
@ -721,7 +721,7 @@
#
# Since: 1.6
##
{ 'type': 'DriveBackup',
{ 'struct': 'DriveBackup',
'data': { 'device': 'str', 'target': 'str', '*format': 'str',
'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
'*speed': 'int', '*bitmap': 'str',
@ -756,7 +756,7 @@
#
# Since: 2.3
##
{ 'type': 'BlockdevBackup',
{ 'struct': 'BlockdevBackup',
'data': { 'device': 'str', 'target': 'str',
'sync': 'MirrorSyncMode',
'*speed': 'int',
@ -977,7 +977,7 @@
#
# Since 2.4
##
{ 'type': 'BlockDirtyBitmap',
{ 'struct': 'BlockDirtyBitmap',
'data': { 'node': 'str', 'name': 'str' } }
##
@ -992,7 +992,7 @@
#
# Since 2.4
##
{ 'type': 'BlockDirtyBitmapAdd',
{ 'struct': 'BlockDirtyBitmapAdd',
'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } }
##
@ -1313,7 +1313,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevCacheOptions',
{ 'struct': 'BlockdevCacheOptions',
'data': { '*writeback': 'bool',
'*direct': 'bool',
'*no-flush': 'bool' } }
@ -1360,7 +1360,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevOptionsBase',
{ 'struct': 'BlockdevOptionsBase',
'data': { 'driver': 'BlockdevDriver',
'*id': 'str',
'*node-name': 'str',
@ -1382,7 +1382,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevOptionsFile',
{ 'struct': 'BlockdevOptionsFile',
'data': { 'filename': 'str' } }
##
@ -1397,7 +1397,7 @@
#
# Since: 2.2
##
{ 'type': 'BlockdevOptionsNull',
{ 'struct': 'BlockdevOptionsNull',
'data': { '*size': 'int', '*latency-ns': 'uint64' } }
##
@ -1413,7 +1413,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevOptionsVVFAT',
{ 'struct': 'BlockdevOptionsVVFAT',
'data': { 'dir': 'str', '*fat-type': 'int', '*floppy': 'bool',
'*rw': 'bool' } }
@ -1427,7 +1427,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevOptionsGenericFormat',
{ 'struct': 'BlockdevOptionsGenericFormat',
'data': { 'file': 'BlockdevRef' } }
##
@ -1443,7 +1443,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevOptionsGenericCOWFormat',
{ 'struct': 'BlockdevOptionsGenericCOWFormat',
'base': 'BlockdevOptionsGenericFormat',
'data': { '*backing': 'BlockdevRef' } }
@ -1479,7 +1479,7 @@
#
# Since: 2.2
##
{ 'type': 'Qcow2OverlapCheckFlags',
{ 'struct': 'Qcow2OverlapCheckFlags',
'data': { '*template': 'Qcow2OverlapCheckMode',
'*main-header': 'bool',
'*active-l1': 'bool',
@ -1503,8 +1503,7 @@
#
# Since: 2.2
##
{ 'union': 'Qcow2OverlapChecks',
'discriminator': {},
{ 'alternate': 'Qcow2OverlapChecks',
'data': { 'flags': 'Qcow2OverlapCheckFlags',
'mode': 'Qcow2OverlapCheckMode' } }
@ -1541,7 +1540,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevOptionsQcow2',
{ 'struct': 'BlockdevOptionsQcow2',
'base': 'BlockdevOptionsGenericCOWFormat',
'data': { '*lazy-refcounts': 'bool',
'*pass-discard-request': 'bool',
@ -1576,7 +1575,7 @@
# use the default value, 'archipelago'.
# Since: 2.2
##
{ 'type': 'BlockdevOptionsArchipelago',
{ 'struct': 'BlockdevOptionsArchipelago',
'data': { 'volume': 'str',
'*mport': 'int',
'*vport': 'int',
@ -1628,7 +1627,7 @@
#
# Since: 2.0
##
{ 'type': 'BlkdebugInjectErrorOptions',
{ 'struct': 'BlkdebugInjectErrorOptions',
'data': { 'event': 'BlkdebugEvent',
'*state': 'int',
'*errno': 'int',
@ -1651,7 +1650,7 @@
#
# Since: 2.0
##
{ 'type': 'BlkdebugSetStateOptions',
{ 'struct': 'BlkdebugSetStateOptions',
'data': { 'event': 'BlkdebugEvent',
'*state': 'int',
'new_state': 'int' } }
@ -1673,7 +1672,7 @@
#
# Since: 2.0
##
{ 'type': 'BlockdevOptionsBlkdebug',
{ 'struct': 'BlockdevOptionsBlkdebug',
'data': { 'image': 'BlockdevRef',
'*config': 'str',
'*align': 'int',
@ -1691,7 +1690,7 @@
#
# Since: 2.0
##
{ 'type': 'BlockdevOptionsBlkverify',
{ 'struct': 'BlockdevOptionsBlkverify',
'data': { 'test': 'BlockdevRef',
'raw': 'BlockdevRef' } }
@ -1728,7 +1727,7 @@
#
# Since: 2.0
##
{ 'type': 'BlockdevOptionsQuorum',
{ 'struct': 'BlockdevOptionsQuorum',
'data': { '*blkverify': 'bool',
'children': [ 'BlockdevRef' ],
'vote-threshold': 'int',
@ -1795,8 +1794,7 @@
#
# Since: 1.7
##
{ 'union': 'BlockdevRef',
'discriminator': {},
{ 'alternate': 'BlockdevRef',
'data': { 'definition': 'BlockdevOptions',
'reference': 'str' } }

View File

@ -52,7 +52,7 @@
#
# Since: 1.7
##
{ 'type': 'BlockdevSnapshotInternal',
{ 'struct': 'BlockdevSnapshotInternal',
'data': { 'device': 'str', 'name': 'str' } }
##

View File

@ -28,16 +28,29 @@
'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted',
'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] }
##
# @VersionTriple
#
# A three-part version number.
#
# @qemu.major: The major version number.
#
# @qemu.minor: The minor version number.
#
# @qemu.micro: The micro version number.
#
# Since: 2.4
##
{ 'struct': 'VersionTriple',
'data': {'major': 'int', 'minor': 'int', 'micro': 'int'} }
##
# @VersionInfo:
#
# A description of QEMU's version.
#
# @qemu.major: The major version of QEMU
#
# @qemu.minor: The minor version of QEMU
#
# @qemu.micro: The micro version of QEMU. By current convention, a micro
# @qemu: The version of QEMU. By current convention, a micro
# version of 50 signifies a development branch. A micro version
# greater than or equal to 90 signifies a release candidate for
# the next minor version. A micro version of less than 50
@ -50,9 +63,8 @@
#
# Since: 0.14.0
##
{ 'type': 'VersionInfo',
'data': {'qemu': {'major': 'int', 'minor': 'int', 'micro': 'int'},
'package': 'str'} }
{ 'struct': 'VersionInfo',
'data': {'qemu': 'VersionTriple', 'package': 'str'} }
##
# @query-version:
@ -74,7 +86,7 @@
#
# Since: 0.14.0
##
{ 'type': 'CommandInfo', 'data': {'name': 'str'} }
{ 'struct': 'CommandInfo', 'data': {'name': 'str'} }
##
# @query-commands:

View File

@ -32,7 +32,7 @@
#
# Since 2.2
##
{ 'type': 'TraceEventInfo',
{ 'struct': 'TraceEventInfo',
'data': {'name': 'str', 'state': 'TraceEventState'} }
##

View File

@ -150,7 +150,7 @@
#
# Since 1.1.0
##
{ 'type': 'GuestAgentCommandInfo',
{ 'struct': 'GuestAgentCommandInfo',
'data': { 'name': 'str', 'enabled': 'bool', 'success-response': 'bool' } }
##
@ -164,7 +164,7 @@
#
# Since 0.15.0
##
{ 'type': 'GuestAgentInfo',
{ 'struct': 'GuestAgentInfo',
'data': { 'version': 'str',
'supported_commands': ['GuestAgentCommandInfo'] } }
##
@ -195,7 +195,7 @@
# Since: 0.15.0
##
{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' },
'success-response': 'no' }
'success-response': false }
##
# @guest-file-open:
@ -242,7 +242,7 @@
#
# Since: 0.15.0
##
{ 'type': 'GuestFileRead',
{ 'struct': 'GuestFileRead',
'data': { 'count': 'int', 'buf-b64': 'str', 'eof': 'bool' } }
##
@ -274,7 +274,7 @@
#
# Since: 0.15.0
##
{ 'type': 'GuestFileWrite',
{ 'struct': 'GuestFileWrite',
'data': { 'count': 'int', 'eof': 'bool' } }
##
@ -309,7 +309,7 @@
#
# Since: 0.15.0
##
{ 'type': 'GuestFileSeek',
{ 'struct': 'GuestFileSeek',
'data': { 'position': 'int', 'eof': 'bool' } }
##
@ -470,7 +470,7 @@
#
# Since: 1.1
##
{ 'command': 'guest-suspend-disk', 'success-response': 'no' }
{ 'command': 'guest-suspend-disk', 'success-response': false }
##
# @guest-suspend-ram
@ -502,7 +502,7 @@
#
# Since: 1.1
##
{ 'command': 'guest-suspend-ram', 'success-response': 'no' }
{ 'command': 'guest-suspend-ram', 'success-response': false }
##
# @guest-suspend-hybrid
@ -529,7 +529,7 @@
#
# Since: 1.1
##
{ 'command': 'guest-suspend-hybrid', 'success-response': 'no' }
{ 'command': 'guest-suspend-hybrid', 'success-response': false }
##
# @GuestIpAddressType:
@ -556,7 +556,7 @@
#
# Since: 1.1
##
{ 'type': 'GuestIpAddress',
{ 'struct': 'GuestIpAddress',
'data': {'ip-address': 'str',
'ip-address-type': 'GuestIpAddressType',
'prefix': 'int'} }
@ -572,7 +572,7 @@
#
# Since: 1.1
##
{ 'type': 'GuestNetworkInterface',
{ 'struct': 'GuestNetworkInterface',
'data': {'name': 'str',
'*hardware-address': 'str',
'*ip-addresses': ['GuestIpAddress'] } }
@ -604,7 +604,7 @@
#
# Since: 1.5
##
{ 'type': 'GuestLogicalProcessor',
{ 'struct': 'GuestLogicalProcessor',
'data': {'logical-id': 'int',
'online': 'bool',
'*can-offline': 'bool'} }
@ -694,7 +694,7 @@
#
# Since: 2.2
##
{ 'type': 'GuestPCIAddress',
{ 'struct': 'GuestPCIAddress',
'data': {'domain': 'int', 'bus': 'int',
'slot': 'int', 'function': 'int'} }
@ -709,7 +709,7 @@
#
# Since: 2.2
##
{ 'type': 'GuestDiskAddress',
{ 'struct': 'GuestDiskAddress',
'data': {'pci-controller': 'GuestPCIAddress',
'bus-type': 'GuestDiskBusType',
'bus': 'int', 'target': 'int', 'unit': 'int'} }
@ -725,7 +725,7 @@
#
# Since: 2.2
##
{ 'type': 'GuestFilesystemInfo',
{ 'struct': 'GuestFilesystemInfo',
'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
'disk': ['GuestDiskAddress']} }
@ -782,7 +782,7 @@
#
# Since: 2.3
##
{ 'type': 'GuestMemoryBlock',
{ 'struct': 'GuestMemoryBlock',
'data': {'phys-index': 'uint64',
'online': 'bool',
'*can-offline': 'bool'} }
@ -835,7 +835,7 @@
#
# Since: 2.3
##
{ 'type': 'GuestMemoryBlockResponse',
{ 'struct': 'GuestMemoryBlockResponse',
'data': { 'phys-index': 'uint64',
'response': 'GuestMemoryBlockResponseType',
'*error-code': 'int' }}
@ -876,7 +876,7 @@
#
# Since: 2.3
##
{ 'type': 'GuestMemoryBlockInfo',
{ 'struct': 'GuestMemoryBlockInfo',
'data': {'size': 'uint64'} }
##

9
qmp.c
View File

@ -45,15 +45,16 @@ NameInfo *qmp_query_name(Error **errp)
VersionInfo *qmp_query_version(Error **errp)
{
VersionInfo *info = g_malloc0(sizeof(*info));
VersionInfo *info = g_new0(VersionInfo, 1);
const char *version = QEMU_VERSION;
char *tmp;
info->qemu.major = strtol(version, &tmp, 10);
info->qemu = g_new0(VersionTriple, 1);
info->qemu->major = strtol(version, &tmp, 10);
tmp++;
info->qemu.minor = strtol(tmp, &tmp, 10);
info->qemu->minor = strtol(tmp, &tmp, 10);
tmp++;
info->qemu.micro = strtol(tmp, &tmp, 10);
info->qemu->micro = strtol(tmp, &tmp, 10);
info->package = g_strdup(QEMU_PKGVERSION);
return info;

View File

@ -2,7 +2,7 @@
# QAPI command marshaller generator
#
# Copyright IBM, Corp. 2011
# Copyright (C) 2014 Red Hat, Inc.
# Copyright (C) 2014-2015 Red Hat, Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
@ -28,7 +28,7 @@ def type_visitor(name):
def generate_command_decl(name, args, ret_type):
arglist=""
for argname, argtype, optional, structured in parse_args(args):
for argname, argtype, optional in parse_args(args):
argtype = c_type(argtype, is_param=True)
if optional:
arglist += "bool has_%s, " % c_var(argname)
@ -53,7 +53,7 @@ def gen_sync_call(name, args, ret_type, indent=0):
retval=""
if ret_type:
retval = "retval = "
for argname, argtype, optional, structured in parse_args(args):
for argname, argtype, optional in parse_args(args):
if optional:
arglist += "has_%s, " % c_var(argname)
arglist += "%s, " % (c_var(argname))
@ -96,7 +96,7 @@ Visitor *v;
def gen_visitor_input_vars_decl(args):
ret = ""
push_indent()
for argname, argtype, optional, structured in parse_args(args):
for argname, argtype, optional in parse_args(args):
if optional:
ret += mcgen('''
bool has_%(argname)s = false;
@ -139,7 +139,7 @@ v = qapi_dealloc_get_visitor(md);
v = qmp_input_get_visitor(mi);
''')
for argname, argtype, optional, structured in parse_args(args):
for argname, argtype, optional in parse_args(args):
if optional:
ret += mcgen('''
visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
@ -293,17 +293,12 @@ out:
return ret
def option_value_matches(opt, val, cmd):
if opt in cmd and cmd[opt] == val:
return True
return False
def gen_registry(commands):
registry=""
push_indent()
for cmd in commands:
options = 'QCO_NO_OPTIONS'
if option_value_matches('success-response', 'no', cmd):
if not cmd.get('success-response', True):
options = 'QCO_NO_SUCCESS_RESP'
registry += mcgen('''

View File

@ -21,7 +21,7 @@ def _generate_event_api_name(event_name, params):
l = len(api_name)
if params:
for argname, argentry, optional, structured in parse_args(params):
for argname, argentry, optional in parse_args(params):
if optional:
api_name += "bool has_%s,\n" % c_var(argname)
api_name += "".ljust(l)
@ -93,7 +93,7 @@ def generate_event_implement(api_name, event_name, params):
""",
event_name = event_name)
for argname, argentry, optional, structured in parse_args(params):
for argname, argentry, optional in parse_args(params):
if optional:
ret += mcgen("""
if (has_%(var)s) {

View File

@ -63,18 +63,13 @@ typedef struct %(name)sList
def generate_struct_fields(members):
ret = ''
for argname, argentry, optional, structured in parse_args(members):
for argname, argentry, optional in parse_args(members):
if optional:
ret += mcgen('''
bool has_%(c_name)s;
''',
c_name=c_var(argname))
if structured:
push_indent()
ret += generate_struct({ "field": argname, "data": argentry})
pop_indent()
else:
ret += mcgen('''
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
c_type=c_type(argentry), c_name=c_var(argname))
@ -83,7 +78,7 @@ def generate_struct_fields(members):
def generate_struct(expr):
structname = expr.get('type', "")
structname = expr.get('struct', "")
fieldname = expr.get('field', "")
members = expr['data']
base = expr.get('base')
@ -170,9 +165,9 @@ typedef enum %(name)s
return lookup_decl + enum_decl
def generate_anon_union_qtypes(expr):
def generate_alternate_qtypes(expr):
name = expr['union']
name = expr['alternate']
members = expr['data']
ret = mcgen('''
@ -181,17 +176,8 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
name=name)
for key in members:
qapi_type = members[key]
if builtin_type_qtypes.has_key(qapi_type):
qtype = builtin_type_qtypes[qapi_type]
elif find_struct(qapi_type):
qtype = "QTYPE_QDICT"
elif find_union(qapi_type):
qtype = "QTYPE_QDICT"
elif find_enum(qapi_type):
qtype = "QTYPE_QSTRING"
else:
assert False, "Invalid anonymous union member"
qtype = find_alternate_member_qtype(members[key])
assert qtype, "Invalid alternate member"
ret += mcgen('''
[ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s,
@ -206,9 +192,9 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
return ret
def generate_union(expr):
def generate_union(expr, meta):
name = expr['union']
name = expr[meta]
typeinfo = expr['data']
base = expr.get('base')
@ -242,10 +228,9 @@ struct %(name)s
''')
if base:
base_fields = find_struct(base)['data']
if discriminator:
base_fields = base_fields.copy()
del base_fields[discriminator]
assert discriminator
base_fields = find_struct(base)['data'].copy()
del base_fields[discriminator]
ret += generate_struct_fields(base_fields)
else:
assert not discriminator
@ -253,7 +238,7 @@ struct %(name)s
ret += mcgen('''
};
''')
if discriminator == {}:
if meta == 'alternate':
ret += mcgen('''
extern const int %(name)s_qtypes[];
''',
@ -398,14 +383,14 @@ exprs = parse_schema(input_file)
exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
for typename in builtin_types:
for typename in builtin_types.keys():
fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
for expr in exprs:
ret = "\n"
if expr.has_key('type'):
ret += generate_fwd_struct(expr['type'], expr['data'])
if expr.has_key('struct'):
ret += generate_fwd_struct(expr['struct'], expr['data'])
elif expr.has_key('enum'):
ret += generate_enum(expr['enum'], expr['data']) + "\n"
ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
@ -417,8 +402,12 @@ for expr in exprs:
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
expr['data'].keys()))
if expr.get('discriminator') == {}:
fdef.write(generate_anon_union_qtypes(expr))
elif expr.has_key('alternate'):
ret += generate_fwd_struct(expr['alternate'], expr['data']) + "\n"
ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
expr['data'].keys()))
fdef.write(generate_alternate_qtypes(expr))
else:
continue
fdecl.write(ret)
@ -426,7 +415,7 @@ for expr in exprs:
# to avoid header dependency hell, we always generate declarations
# for built-in types in our header files and simply guard them
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
for typename in builtin_types:
for typename in builtin_types.keys():
fdecl.write(generate_type_cleanup_decl(typename + "List"))
fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
@ -435,24 +424,30 @@ fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
# over these cases
if do_builtins:
fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for typename in builtin_types:
for typename in builtin_types.keys():
fdef.write(generate_type_cleanup(typename + "List"))
fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for expr in exprs:
ret = "\n"
if expr.has_key('type'):
if expr.has_key('struct'):
ret += generate_struct(expr) + "\n"
ret += generate_type_cleanup_decl(expr['type'] + "List")
fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
ret += generate_type_cleanup_decl(expr['type'])
fdef.write(generate_type_cleanup(expr['type']) + "\n")
ret += generate_type_cleanup_decl(expr['struct'] + "List")
fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
ret += generate_type_cleanup_decl(expr['struct'])
fdef.write(generate_type_cleanup(expr['struct']) + "\n")
elif expr.has_key('union'):
ret += generate_union(expr)
ret += generate_union(expr, 'union')
ret += generate_type_cleanup_decl(expr['union'] + "List")
fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
ret += generate_type_cleanup_decl(expr['union'])
fdef.write(generate_type_cleanup(expr['union']) + "\n")
elif expr.has_key('alternate'):
ret += generate_union(expr, 'alternate')
ret += generate_type_cleanup_decl(expr['alternate'] + "List")
fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
ret += generate_type_cleanup_decl(expr['alternate'])
fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
elif expr.has_key('enum'):
ret += generate_type_cleanup_decl(expr['enum'] + "List")
fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")

View File

@ -43,79 +43,45 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error *
''',
c_type=type_name(type))
def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
def generate_visit_struct_fields(name, members, base = None):
substructs = []
ret = ''
if not fn_prefix:
full_name = name
else:
full_name = "%s_%s" % (name, fn_prefix)
for argname, argentry, optional, structured in parse_args(members):
if structured:
if not fn_prefix:
nested_fn_prefix = argname
else:
nested_fn_prefix = "%s_%s" % (fn_prefix, argname)
nested_field_prefix = "%s%s." % (field_prefix, argname)
ret += generate_visit_struct_fields(name, nested_field_prefix,
nested_fn_prefix, argentry)
ret += mcgen('''
static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp)
{
''',
name=name, full_name=full_name, c_name=c_var(argname))
ret += generate_visit_struct_body(full_name, argname, argentry)
ret += mcgen('''
}
''')
if base:
ret += generate_visit_implicit_struct(base)
ret += mcgen('''
static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
{
Error *err = NULL;
''',
name=name, full_name=full_name)
name=name)
push_indent()
if base:
ret += mcgen('''
visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
if (err) {
goto out;
}
''',
c_prefix=c_var(field_prefix),
type=type_name(base), c_name=c_var('base'))
for argname, argentry, optional, structured in parse_args(members):
for argname, argentry, optional in parse_args(members):
if optional:
ret += mcgen('''
visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
if (!err && (*obj)->%(prefix)shas_%(c_name)s) {
visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
if (!err && (*obj)->has_%(c_name)s) {
''',
c_prefix=c_var(field_prefix), prefix=field_prefix,
c_name=c_var(argname), name=argname)
push_indent()
if structured:
ret += mcgen('''
visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err);
ret += mcgen('''
visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
''',
full_name=full_name, c_name=c_var(argname))
else:
ret += mcgen('''
visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
''',
c_prefix=c_var(field_prefix), prefix=field_prefix,
type=type_name(argentry), c_name=c_var(argname),
name=argname)
type=type_name(argentry), c_name=c_var(argname),
name=argname)
if optional:
pop_indent()
@ -141,29 +107,11 @@ out:
return ret
def generate_visit_struct_body(field_prefix, name, members):
def generate_visit_struct_body(name, members):
ret = mcgen('''
Error *err = NULL;
''')
if not field_prefix:
full_name = name
else:
full_name = "%s_%s" % (field_prefix, name)
if len(field_prefix):
ret += mcgen('''
visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
''',
name=name)
else:
ret += mcgen('''
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
''',
name=name)
ret += mcgen('''
if (!err) {
if (*obj) {
visit_type_%(name)s_fields(m, obj, errp);
@ -172,17 +120,17 @@ def generate_visit_struct_body(field_prefix, name, members):
}
error_propagate(errp, err);
''',
name=full_name)
name=name)
return ret
def generate_visit_struct(expr):
name = expr['type']
name = expr['struct']
members = expr['data']
base = expr.get('base')
ret = generate_visit_struct_fields(name, "", "", members, base)
ret = generate_visit_struct_fields(name, members, base)
ret += mcgen('''
@ -191,7 +139,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
''',
name=name)
ret += generate_visit_struct_body("", name, members)
ret += generate_visit_struct_body(name, members)
ret += mcgen('''
}
@ -237,7 +185,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er
''',
name=name)
def generate_visit_anon_union(name, members):
def generate_visit_alternate(name, members):
ret = mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
@ -256,15 +204,15 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
''',
name=name)
# For anon union, always use the default enum type automatically generated
# For alternate, always use the default enum type automatically generated
# as "'%sKind' % (name)"
disc_type = '%sKind' % (name)
for key in members:
assert (members[key] in builtin_types
assert (members[key] in builtin_types.keys()
or find_struct(members[key])
or find_union(members[key])
or find_enum(members[key])), "Invalid anonymous union member"
or find_enum(members[key])), "Invalid alternate member"
enum_full_value = generate_enum_full_value(disc_type, key)
ret += mcgen('''
@ -300,27 +248,22 @@ def generate_visit_union(expr):
base = expr.get('base')
discriminator = expr.get('discriminator')
if discriminator == {}:
assert not base
return generate_visit_anon_union(name, members)
enum_define = discriminator_find_enum_define(expr)
if enum_define:
# Use the enum type as discriminator
ret = ""
disc_type = enum_define['enum_name']
else:
# There will always be a discriminator in the C switch code, by default it
# is an enum type generated silently as "'%sKind' % (name)"
# There will always be a discriminator in the C switch code, by default
# it is an enum type generated silently as "'%sKind' % (name)"
ret = generate_visit_enum('%sKind' % name, members.keys())
disc_type = '%sKind' % (name)
if base:
base_fields = find_struct(base)['data']
if discriminator:
base_fields = base_fields.copy()
del base_fields[discriminator]
ret += generate_visit_struct_fields(name, "", "", base_fields)
assert discriminator
base_fields = find_struct(base)['data'].copy()
del base_fields[discriminator]
ret += generate_visit_struct_fields(name, base_fields)
if discriminator:
for key in members:
@ -538,7 +481,7 @@ exprs = parse_schema(input_file)
# to avoid header dependency hell, we always generate declarations
# for built-in types in our header files and simply guard them
fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
for typename in builtin_types:
for typename in builtin_types.keys():
fdecl.write(generate_declaration(typename, None, builtin_type=True))
fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
@ -546,16 +489,16 @@ fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# have the functions defined, so we use -b option to provide control
# over these cases
if do_builtins:
for typename in builtin_types:
for typename in builtin_types.keys():
fdef.write(generate_visit_list(typename, None))
for expr in exprs:
if expr.has_key('type'):
if expr.has_key('struct'):
ret = generate_visit_struct(expr)
ret += generate_visit_list(expr['type'], expr['data'])
ret += generate_visit_list(expr['struct'], expr['data'])
fdef.write(ret)
ret = generate_declaration(expr['type'], expr['data'])
ret = generate_declaration(expr['struct'], expr['data'])
fdecl.write(ret)
elif expr.has_key('union'):
ret = generate_visit_union(expr)
@ -569,6 +512,15 @@ for expr in exprs:
expr['data'].keys())
ret += generate_declaration(expr['union'], expr['data'])
fdecl.write(ret)
elif expr.has_key('alternate'):
ret = generate_visit_alternate(expr['alternate'], expr['data'])
ret += generate_visit_list(expr['alternate'], expr['data'])
fdef.write(ret)
ret = generate_decl_enum('%sKind' % expr['alternate'],
expr['data'].keys())
ret += generate_declaration(expr['alternate'], expr['data'])
fdecl.write(ret)
elif expr.has_key('enum'):
ret = generate_visit_list(expr['enum'], expr['data'])
ret += generate_visit_enum(expr['enum'], expr['data'])

View File

@ -2,7 +2,7 @@
# QAPI helper library
#
# Copyright IBM, Corp. 2011
# Copyright (c) 2013 Red Hat Inc.
# Copyright (c) 2013-2015 Red Hat Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
@ -16,13 +16,7 @@ from ordereddict import OrderedDict
import os
import sys
builtin_types = [
'str', 'int', 'number', 'bool',
'int8', 'int16', 'int32', 'int64',
'uint8', 'uint16', 'uint32', 'uint64'
]
builtin_type_qtypes = {
builtin_types = {
'str': 'QTYPE_QSTRING',
'int': 'QTYPE_QINT',
'number': 'QTYPE_QFLOAT',
@ -35,8 +29,39 @@ builtin_type_qtypes = {
'uint16': 'QTYPE_QINT',
'uint32': 'QTYPE_QINT',
'uint64': 'QTYPE_QINT',
'size': 'QTYPE_QINT',
}
# Whitelist of commands allowed to return a non-dictionary
returns_whitelist = [
# From QMP:
'human-monitor-command',
'query-migrate-cache-size',
'query-tpm-models',
'query-tpm-types',
'ringbuf-read',
# From QGA:
'guest-file-open',
'guest-fsfreeze-freeze',
'guest-fsfreeze-freeze-list',
'guest-fsfreeze-status',
'guest-fsfreeze-thaw',
'guest-get-time',
'guest-set-vcpus',
'guest-sync',
'guest-sync-delimited',
# From qapi-schema-test:
'user_def_cmd3',
]
enum_types = []
struct_types = []
union_types = []
events = []
all_names = {}
def error_path(parent):
res = ""
while parent:
@ -148,7 +173,41 @@ class QAPISchema:
raise QAPISchemaError(self,
'Missing terminating "\'"')
if esc:
string += ch
if ch == 'b':
string += '\b'
elif ch == 'f':
string += '\f'
elif ch == 'n':
string += '\n'
elif ch == 'r':
string += '\r'
elif ch == 't':
string += '\t'
elif ch == 'u':
value = 0
for x in range(0, 4):
ch = self.src[self.cursor]
self.cursor += 1
if ch not in "0123456789abcdefABCDEF":
raise QAPISchemaError(self,
'\\u escape needs 4 '
'hex digits')
value = (value << 4) + int(ch, 16)
# If Python 2 and 3 didn't disagree so much on
# how to handle Unicode, then we could allow
# Unicode string defaults. But most of QAPI is
# ASCII-only, so we aren't losing much for now.
if not value or value > 0x7f:
raise QAPISchemaError(self,
'For now, \\u escape '
'only supports non-zero '
'values up to \\u007f')
string += chr(value)
elif ch in "\\/'\"":
string += ch
else:
raise QAPISchemaError(self,
"Unknown escape \\%s" %ch)
esc = False
elif ch == "\\":
esc = True
@ -157,6 +216,20 @@ class QAPISchema:
return
else:
string += ch
elif self.tok in "tfn":
val = self.src[self.cursor - 1:]
if val.startswith("true"):
self.val = True
self.cursor += 3
return
elif val.startswith("false"):
self.val = False
self.cursor += 4
return
elif val.startswith("null"):
self.val = None
self.cursor += 3
return
elif self.tok == '\n':
if self.cursor == len(self.src):
self.tok = None
@ -196,8 +269,9 @@ class QAPISchema:
if self.tok == ']':
self.accept()
return expr
if not self.tok in [ '{', '[', "'" ]:
raise QAPISchemaError(self, 'Expected "{", "[", "]" or string')
if not self.tok in "{['tfn":
raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
'boolean or "null"')
while True:
expr.append(self.get_expr(True))
if self.tok == ']':
@ -216,7 +290,7 @@ class QAPISchema:
elif self.tok == '[':
self.accept()
expr = self.get_values()
elif self.tok == "'":
elif self.tok in "'tfn":
expr = self.val
self.accept()
else:
@ -229,6 +303,18 @@ def find_base_fields(base):
return None
return base_struct_define['data']
# Return the qtype of an alternate branch, or None on error.
def find_alternate_member_qtype(qapi_type):
if builtin_types.has_key(qapi_type):
return builtin_types[qapi_type]
elif find_struct(qapi_type):
return "QTYPE_QDICT"
elif find_enum(qapi_type):
return "QTYPE_QSTRING"
elif find_union(qapi_type):
return "QTYPE_QDICT"
return None
# Return the discriminator enum define if discriminator is specified as an
# enum type, otherwise return None.
def discriminator_find_enum_define(expr):
@ -248,56 +334,178 @@ def discriminator_find_enum_define(expr):
return find_enum(discriminator_type)
valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
def check_name(expr_info, source, name, allow_optional = False,
enum_member = False):
global valid_name
membername = name
if not isinstance(name, str):
raise QAPIExprError(expr_info,
"%s requires a string name" % source)
if name.startswith('*'):
membername = name[1:]
if not allow_optional:
raise QAPIExprError(expr_info,
"%s does not allow optional name '%s'"
% (source, name))
# Enum members can start with a digit, because the generated C
# code always prefixes it with the enum name
if enum_member:
membername = '_' + membername
if not valid_name.match(membername):
raise QAPIExprError(expr_info,
"%s uses invalid name '%s'" % (source, name))
def check_type(expr_info, source, value, allow_array = False,
allow_dict = False, allow_optional = False,
allow_star = False, allow_metas = []):
global all_names
orig_value = value
if value is None:
return
if allow_star and value == '**':
return
# Check if array type for value is okay
if isinstance(value, list):
if not allow_array:
raise QAPIExprError(expr_info,
"%s cannot be an array" % source)
if len(value) != 1 or not isinstance(value[0], str):
raise QAPIExprError(expr_info,
"%s: array type must contain single type name"
% source)
value = value[0]
orig_value = "array of %s" %value
# Check if type name for value is okay
if isinstance(value, str):
if value == '**':
raise QAPIExprError(expr_info,
"%s uses '**' but did not request 'gen':false"
% source)
if not value in all_names:
raise QAPIExprError(expr_info,
"%s uses unknown type '%s'"
% (source, orig_value))
if not all_names[value] in allow_metas:
raise QAPIExprError(expr_info,
"%s cannot use %s type '%s'"
% (source, all_names[value], orig_value))
return
# value is a dictionary, check that each member is okay
if not isinstance(value, OrderedDict):
raise QAPIExprError(expr_info,
"%s should be a dictionary" % source)
if not allow_dict:
raise QAPIExprError(expr_info,
"%s should be a type name" % source)
for (key, arg) in value.items():
check_name(expr_info, "Member of %s" % source, key,
allow_optional=allow_optional)
# Todo: allow dictionaries to represent default values of
# an optional argument.
check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
allow_array=True, allow_star=allow_star,
allow_metas=['built-in', 'union', 'alternate', 'struct',
'enum'])
def check_member_clash(expr_info, base_name, data, source = ""):
base = find_struct(base_name)
assert base
base_members = base['data']
for key in data.keys():
if key.startswith('*'):
key = key[1:]
if key in base_members or "*" + key in base_members:
raise QAPIExprError(expr_info,
"Member name '%s'%s clashes with base '%s'"
% (key, source, base_name))
if base.get('base'):
check_member_clash(expr_info, base['base'], data, source)
def check_command(expr, expr_info):
name = expr['command']
allow_star = expr.has_key('gen')
check_type(expr_info, "'data' for command '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
allow_metas=['union', 'struct'], allow_star=allow_star)
returns_meta = ['union', 'struct']
if name in returns_whitelist:
returns_meta += ['built-in', 'alternate', 'enum']
check_type(expr_info, "'returns' for command '%s'" % name,
expr.get('returns'), allow_array=True, allow_dict=True,
allow_optional=True, allow_metas=returns_meta,
allow_star=allow_star)
def check_event(expr, expr_info):
global events
name = expr['event']
params = expr.get('data')
if params:
for argname, argentry, optional, structured in parse_args(params):
if structured:
raise QAPIExprError(expr_info,
"Nested structure define in event is not "
"supported, event '%s', argname '%s'"
% (expr['event'], argname))
if name.upper() == 'MAX':
raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
events.append(name)
check_type(expr_info, "'data' for event '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
allow_metas=['union', 'struct'])
def check_union(expr, expr_info):
name = expr['union']
base = expr.get('base')
discriminator = expr.get('discriminator')
members = expr['data']
values = { 'MAX': '(automatic)' }
# If the object has a member 'base', its value must name a complex type.
if base:
base_fields = find_base_fields(base)
if not base_fields:
# If the object has a member 'base', its value must name a struct,
# and there must be a discriminator.
if base is not None:
if discriminator is None:
raise QAPIExprError(expr_info,
"Base '%s' is not a valid type"
% base)
"Union '%s' requires a discriminator to go "
"along with base" %name)
# If the union object has no member 'discriminator', it's an
# ordinary union.
if not discriminator:
enum_define = None
# Two types of unions, determined by discriminator.
# Else if the value of member 'discriminator' is {}, it's an
# anonymous union.
elif discriminator == {}:
# With no discriminator it is a simple union.
if discriminator is None:
enum_define = None
allow_metas=['built-in', 'union', 'alternate', 'struct', 'enum']
if base is not None:
raise QAPIExprError(expr_info,
"Simple union '%s' must not have a base"
% name)
# Else, it's a flat union.
else:
# The object must have a member 'base'.
if not base:
# The object must have a string member 'base'.
if not isinstance(base, str):
raise QAPIExprError(expr_info,
"Flat union '%s' must have a base field"
"Flat union '%s' must have a string base field"
% name)
# The value of member 'discriminator' must name a member of the
# base type.
base_fields = find_base_fields(base)
if not base_fields:
raise QAPIExprError(expr_info,
"Base '%s' is not a valid struct"
% base)
# The value of member 'discriminator' must name a non-optional
# member of the base struct.
check_name(expr_info, "Discriminator of flat union '%s'" % name,
discriminator)
discriminator_type = base_fields.get(discriminator)
if not discriminator_type:
raise QAPIExprError(expr_info,
"Discriminator '%s' is not a member of base "
"type '%s'"
"struct '%s'"
% (discriminator, base))
enum_define = find_enum(discriminator_type)
allow_metas=['struct']
# Do not allow string discriminator
if not enum_define:
raise QAPIExprError(expr_info,
@ -306,51 +514,196 @@ def check_union(expr, expr_info):
# Check every branch
for (key, value) in members.items():
# If this named member's value names an enum type, then all members
check_name(expr_info, "Member of union '%s'" % name, key)
# Each value must name a known type; furthermore, in flat unions,
# branches must be a struct with no overlapping member names
check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
value, allow_array=True, allow_metas=allow_metas)
if base:
branch_struct = find_struct(value)
assert branch_struct
check_member_clash(expr_info, base, branch_struct['data'],
" of branch '%s'" % key)
# If the discriminator names an enum type, then all members
# of 'data' must also be members of the enum type.
if enum_define and not key in enum_define['enum_values']:
if enum_define:
if not key in enum_define['enum_values']:
raise QAPIExprError(expr_info,
"Discriminator value '%s' is not found in "
"enum '%s'" %
(key, enum_define["enum_name"]))
# Otherwise, check for conflicts in the generated enum
else:
c_key = _generate_enum_string(key)
if c_key in values:
raise QAPIExprError(expr_info,
"Union '%s' member '%s' clashes with '%s'"
% (name, key, values[c_key]))
values[c_key] = key
def check_alternate(expr, expr_info):
name = expr['alternate']
members = expr['data']
values = { 'MAX': '(automatic)' }
types_seen = {}
# Check every branch
for (key, value) in members.items():
check_name(expr_info, "Member of alternate '%s'" % name, key)
# Check for conflicts in the generated enum
c_key = _generate_enum_string(key)
if c_key in values:
raise QAPIExprError(expr_info,
"Discriminator value '%s' is not found in "
"enum '%s'" %
(key, enum_define["enum_name"]))
# Todo: add checking for values. Key is checked as above, value can be
# also checked here, but we need more functions to handle array case.
"Alternate '%s' member '%s' clashes with '%s'"
% (name, key, values[c_key]))
values[c_key] = key
# Ensure alternates have no type conflicts.
check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
value,
allow_metas=['built-in', 'union', 'struct', 'enum'])
qtype = find_alternate_member_qtype(value)
assert qtype
if qtype in types_seen:
raise QAPIExprError(expr_info,
"Alternate '%s' member '%s' can't "
"be distinguished from member '%s'"
% (name, key, types_seen[qtype]))
types_seen[qtype] = key
def check_enum(expr, expr_info):
name = expr['enum']
members = expr.get('data')
values = { 'MAX': '(automatic)' }
if not isinstance(members, list):
raise QAPIExprError(expr_info,
"Enum '%s' requires an array for 'data'" % name)
for member in members:
check_name(expr_info, "Member of enum '%s'" %name, member,
enum_member=True)
key = _generate_enum_string(member)
if key in values:
raise QAPIExprError(expr_info,
"Enum '%s' member '%s' clashes with '%s'"
% (name, member, values[key]))
values[key] = member
def check_struct(expr, expr_info):
name = expr['struct']
members = expr['data']
check_type(expr_info, "'data' for struct '%s'" % name, members,
allow_dict=True, allow_optional=True)
check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
allow_metas=['struct'])
if expr.get('base'):
check_member_clash(expr_info, expr['base'], expr['data'])
def check_exprs(schema):
for expr_elem in schema.exprs:
expr = expr_elem['expr']
if expr.has_key('union'):
check_union(expr, expr_elem['info'])
if expr.has_key('event'):
check_event(expr, expr_elem['info'])
info = expr_elem['info']
if expr.has_key('enum'):
check_enum(expr, info)
elif expr.has_key('union'):
check_union(expr, info)
elif expr.has_key('alternate'):
check_alternate(expr, info)
elif expr.has_key('struct'):
check_struct(expr, info)
elif expr.has_key('command'):
check_command(expr, info)
elif expr.has_key('event'):
check_event(expr, info)
else:
assert False, 'unexpected meta type'
def check_keys(expr_elem, meta, required, optional=[]):
expr = expr_elem['expr']
info = expr_elem['info']
name = expr[meta]
if not isinstance(name, str):
raise QAPIExprError(info,
"'%s' key must have a string value" % meta)
required = required + [ meta ]
for (key, value) in expr.items():
if not key in required and not key in optional:
raise QAPIExprError(info,
"Unknown key '%s' in %s '%s'"
% (key, meta, name))
if (key == 'gen' or key == 'success-response') and value != False:
raise QAPIExprError(info,
"'%s' of %s '%s' should only use false value"
% (key, meta, name))
for key in required:
if not expr.has_key(key):
raise QAPIExprError(info,
"Key '%s' is missing from %s '%s'"
% (key, meta, name))
def parse_schema(input_file):
global all_names
exprs = []
# First pass: read entire file into memory
try:
schema = QAPISchema(open(input_file, "r"))
except (QAPISchemaError, QAPIExprError), e:
print >>sys.stderr, e
exit(1)
exprs = []
for expr_elem in schema.exprs:
expr = expr_elem['expr']
if expr.has_key('enum'):
add_enum(expr['enum'], expr['data'])
elif expr.has_key('union'):
add_union(expr)
elif expr.has_key('type'):
add_struct(expr)
exprs.append(expr)
# Try again for hidden UnionKind enum
for expr_elem in schema.exprs:
expr = expr_elem['expr']
if expr.has_key('union'):
if not discriminator_find_enum_define(expr):
add_enum('%sKind' % expr['union'])
try:
# Next pass: learn the types and check for valid expression keys. At
# this point, top-level 'include' has already been flattened.
for builtin in builtin_types.keys():
all_names[builtin] = 'built-in'
for expr_elem in schema.exprs:
expr = expr_elem['expr']
info = expr_elem['info']
if expr.has_key('enum'):
check_keys(expr_elem, 'enum', ['data'])
add_enum(expr['enum'], info, expr['data'])
elif expr.has_key('union'):
check_keys(expr_elem, 'union', ['data'],
['base', 'discriminator'])
add_union(expr, info)
elif expr.has_key('alternate'):
check_keys(expr_elem, 'alternate', ['data'])
add_name(expr['alternate'], info, 'alternate')
elif expr.has_key('struct'):
check_keys(expr_elem, 'struct', ['data'], ['base'])
add_struct(expr, info)
elif expr.has_key('command'):
check_keys(expr_elem, 'command', [],
['data', 'returns', 'gen', 'success-response'])
add_name(expr['command'], info, 'command')
elif expr.has_key('event'):
check_keys(expr_elem, 'event', [], ['data'])
add_name(expr['event'], info, 'event')
else:
raise QAPIExprError(expr_elem['info'],
"Expression is missing metatype")
exprs.append(expr)
# Try again for hidden UnionKind enum
for expr_elem in schema.exprs:
expr = expr_elem['expr']
if expr.has_key('union'):
if not discriminator_find_enum_define(expr):
add_enum('%sKind' % expr['union'], expr_elem['info'],
implicit=True)
elif expr.has_key('alternate'):
add_enum('%sKind' % expr['alternate'], expr_elem['info'],
implicit=True)
# Final pass - validate that exprs make sense
check_exprs(schema)
except QAPIExprError, e:
print >>sys.stderr, e
@ -359,7 +712,7 @@ def parse_schema(input_file):
return exprs
def parse_args(typeinfo):
if isinstance(typeinfo, basestring):
if isinstance(typeinfo, str):
struct = find_struct(typeinfo)
assert struct != None
typeinfo = struct['data']
@ -368,13 +721,12 @@ def parse_args(typeinfo):
argname = member
argentry = typeinfo[member]
optional = False
structured = False
if member.startswith('*'):
argname = member[1:]
optional = True
if isinstance(argentry, OrderedDict):
structured = True
yield (argname, argentry, optional, structured)
# Todo: allow argentry to be OrderedDict, for providing the
# value of an optional argument.
yield (argname, argentry, optional)
def de_camel_case(name):
new_name = ''
@ -442,23 +794,36 @@ def type_name(name):
return c_list_type(name[0])
return name
enum_types = []
struct_types = []
union_types = []
def add_name(name, info, meta, implicit = False):
global all_names
check_name(info, "'%s'" % meta, name)
if name in all_names:
raise QAPIExprError(info,
"%s '%s' is already defined"
% (all_names[name], name))
if not implicit and name[-4:] == 'Kind':
raise QAPIExprError(info,
"%s '%s' should not end in 'Kind'"
% (meta, name))
all_names[name] = meta
def add_struct(definition):
def add_struct(definition, info):
global struct_types
name = definition['struct']
add_name(name, info, 'struct')
struct_types.append(definition)
def find_struct(name):
global struct_types
for struct in struct_types:
if struct['type'] == name:
if struct['struct'] == name:
return struct
return None
def add_union(definition):
def add_union(definition, info):
global union_types
name = definition['union']
add_name(name, info, 'union')
union_types.append(definition)
def find_union(name):
@ -468,8 +833,9 @@ def find_union(name):
return union
return None
def add_enum(name, enum_values = None):
def add_enum(name, info, enum_values = None, implicit = False):
global enum_types
add_name(name, info, 'enum', implicit)
enum_types.append({"enum_name": name, "enum_values": enum_values})
def find_enum(name):
@ -511,7 +877,7 @@ def c_type(name, is_param=False):
return name
elif name == None or len(name) == 0:
return 'void'
elif name == name.upper():
elif name in events:
return '%sEvent *%s' % (camel_case(name), eatspace)
else:
return '%s *%s' % (name, eatspace)

View File

@ -207,20 +207,44 @@ $(foreach target,$(SYSEMU_TARGET_LIST), \
$(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF))))
check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
comments.json empty.json funny-char.json indented-expr.json \
missing-colon.json missing-comma-list.json \
missing-comma-object.json non-objects.json \
comments.json empty.json enum-empty.json enum-missing-data.json \
enum-wrong-data.json enum-int-member.json enum-dict-member.json \
enum-clash-member.json enum-max-member.json enum-union-clash.json \
enum-bad-name.json funny-char.json indented-expr.json \
missing-type.json bad-ident.json ident-with-escape.json \
escape-outside-string.json unknown-escape.json \
escape-too-short.json escape-too-big.json unicode-str.json \
double-type.json bad-base.json bad-type-bool.json bad-type-int.json \
bad-type-dict.json double-data.json unknown-expr-key.json \
redefined-type.json redefined-command.json redefined-builtin.json \
redefined-event.json command-int.json bad-data.json event-max.json \
type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \
data-array-empty.json data-array-unknown.json data-int.json \
data-unknown.json data-member-unknown.json data-member-array.json \
data-member-array-bad.json returns-array-bad.json returns-int.json \
returns-unknown.json returns-alternate.json returns-whitelist.json \
missing-colon.json missing-comma-list.json missing-comma-object.json \
nested-struct-data.json nested-struct-returns.json non-objects.json \
qapi-schema-test.json quoted-structural-chars.json \
trailing-comma-list.json trailing-comma-object.json \
unclosed-list.json unclosed-object.json unclosed-string.json \
duplicate-key.json union-invalid-base.json flat-union-no-base.json \
flat-union-invalid-discriminator.json \
duplicate-key.json union-invalid-base.json union-bad-branch.json \
union-optional-branch.json union-unknown.json union-max.json \
flat-union-optional-discriminator.json flat-union-no-base.json \
flat-union-invalid-discriminator.json flat-union-inline.json \
flat-union-invalid-branch-key.json flat-union-reverse-define.json \
flat-union-string-discriminator.json \
flat-union-string-discriminator.json union-base-no-discriminator.json \
flat-union-bad-discriminator.json flat-union-bad-base.json \
flat-union-base-star.json flat-union-int-branch.json \
flat-union-base-union.json flat-union-branch-clash.json \
alternate-nested.json alternate-unknown.json alternate-clash.json \
alternate-good.json alternate-base.json alternate-array.json \
alternate-conflict-string.json alternate-conflict-dict.json \
include-simple.json include-relpath.json include-format-err.json \
include-non-file.json include-no-file.json include-before-err.json \
include-nested-err.json include-self-cycle.json include-cycle.json \
include-repetition.json event-nest-struct.json)
include-repetition.json event-nest-struct.json event-case.json \
struct-base-clash.json struct-base-clash-deep.json )
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \
tests/test-qmp-commands.h tests/test-qapi-event.h

View File

@ -0,0 +1 @@
tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt' cannot be an array

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,7 @@
# we do not allow array branches in alternates
# TODO: should we support this?
{ 'struct': 'One',
'data': { 'name': 'str' } }
{ 'alternate': 'Alt',
'data': { 'one': 'One',
'two': [ 'int' ] } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
# we reject alternate with base type
{ 'struct': 'Base',
'data': { 'string': 'str' } }
{ 'alternate': 'Alt',
'base': 'Base',
'data': { 'number': 'int' } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/alternate-clash.json:2: Alternate 'Alt1' member 'ONE' clashes with 'one'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
# we detect C enum collisions in an alternate
{ 'alternate': 'Alt1',
'data': { 'one': 'str', 'ONE': 'int' } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member 'two' can't be distinguished from member 'one'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,8 @@
# we reject alternates with multiple object branches
{ 'struct': 'One',
'data': { 'name': 'str' } }
{ 'struct': 'Two',
'data': { 'value': 'int' } }
{ 'alternate': 'Alt',
'data': { 'one': 'One',
'two': 'Two' } }

View File

@ -0,0 +1 @@
tests/qapi-schema/alternate-conflict-string.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
# we reject alternates with multiple string-like branches
{ 'enum': 'Enum',
'data': [ 'hello', 'world' ] }
{ 'alternate': 'Alt',
'data': { 'one': 'str',
'two': 'Enum' } }

View File

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,9 @@
# Working example of alternate
{ 'struct': 'Data',
'data': { '*number': 'int', '*name': 'str' } }
{ 'enum': 'Enum',
'data': [ 'hello', 'world' ] }
{ 'alternate': 'Alt',
'data': { 'value': 'int',
'string': 'Enum',
'struct': 'Data' } }

View File

@ -0,0 +1,6 @@
[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))]),
OrderedDict([('enum', 'Enum'), ('data', ['hello', 'world'])]),
OrderedDict([('alternate', 'Alt'), ('data', OrderedDict([('value', 'int'), ('string', 'Enum'), ('struct', 'Data')]))])]
[{'enum_name': 'Enum', 'enum_values': ['hello', 'world']},
{'enum_name': 'AltKind', 'enum_values': None}]
[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))])]

View File

@ -0,0 +1 @@
tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
# we reject a nested alternate branch
{ 'alternate': 'Alt1',
'data': { 'name': 'str', 'value': 'int' } }
{ 'alternate': 'Alt2',
'data': { 'nested': 'Alt1' } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
# we reject an alternate with unknown type in branch
{ 'alternate': 'Alt',
'data': { 'unknown': 'MissingType' } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use union type 'Union'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
# we reject a base that is not a struct
{ 'union': 'Union', 'data': { 'a': 'int', 'b': 'str' } }
{ 'struct': 'MyType', 'base': 'Union', 'data': { 'c': 'int' } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an array

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we ensure 'data' is a dictionary for all but enums
{ 'command': 'oops', 'data': [ ] }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name '*oops'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject creating a type name with bad name
{ 'struct': '*oops', 'data': { 'i': 'int' } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/bad-type-bool.json:2: 'struct' key must have a string value

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject an expression with a metatype that is not a string
{ 'struct': true, 'data': { } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string value

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject an expression with a metatype that is not a string
{ 'command': { } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/bad-type-int.json:3:13: Stray "1"

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
# we reject an expression with a metatype that is not a string
# FIXME: once the parser understands integer inputs, improve the error message
{ 'struct': 1, 'data': { } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/command-int.json:2: built-in 'int' is already defined

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,3 @@
# we reject collisions between commands and types
{ 'command': 'int', 'data': { 'character': 'str' },
'returns': { 'value': 'int' } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/data-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject an array for data if it does not contain a known type
{ 'command': 'oops', 'data': { 'empty': [ ] } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/data-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'array of NoSuchType'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject an array for data if it does not contain a known type
{ 'command': 'oops', 'data': { 'array': [ 'NoSuchType' ] } }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/data-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject commands where data is not an array or complex type
{ 'command': 'oops', 'data': 'int' }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/data-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject data if it does not contain a valid array type
{ 'command': 'oops', 'data': { 'member': [ { 'nested': 'str' } ] } }

View File

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,4 @@
# valid array members
{ 'enum': 'abc', 'data': [ 'a', 'b', 'c' ] }
{ 'struct': 'def', 'data': { 'array': [ 'abc' ] } }
{ 'command': 'okay', 'data': { 'member1': [ 'int' ], 'member2': [ 'def' ] } }

View File

@ -0,0 +1,5 @@
[OrderedDict([('enum', 'abc'), ('data', ['a', 'b', 'c'])]),
OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))]),
OrderedDict([('command', 'okay'), ('data', OrderedDict([('member1', ['int']), ('member2', ['def'])]))])]
[{'enum_name': 'abc', 'enum_values': ['a', 'b', 'c']}]
[OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))])]

View File

@ -0,0 +1 @@
tests/qapi-schema/data-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject data if it does not contain a known type
{ 'command': 'oops', 'data': { 'member': 'NoSuchType' } }

Some files were not shown because too many files have changed in this diff Show More