QAPI patches patches for 2024-03-04
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmXlaSISHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTdZ8P/iMgqLoAFkCCjwfkUc/rqZUezK52Ynr7 LYwOPI/xcYD7EnVogdRgFgjWFNoivQLP5yKsU/eRTk29pwdDzTscFm/0ztTQX/Gb ypWV+GBcu5J8mKbp1KF5w68aDD8Bat4WRfEgDQ1DV7v6CoMiUzTiF3CGXkYzqK5Y kYNq97vdEkBFvFdOl/7scs/XXN2jG27egDhMp68RTxnPHlXZiAO9/2Bul3uVe3x0 fzQ2ViYv0qLnjE/PwENDqqE3Thv3Sxp5iEeQQ6GWi07EVh07UtHpOM3RYyrTU0Sb VrTApSrg0oxlkOuR0CBd9Fi+timtbokBL0DWyUpXNTfIEZfLtA9H+8riUg3EOcDp r7a4SI/27VdPxX6Kc6zA3bi+/j1o7CLTW2LGEwuZs52nmixoo1HTWPIFdyh13g/V QjNbun0fViHb0FVLiyDlXF/7Y+EWUWIyqwwGqbvve1DyUHQmo3CUQAKGOpkeKSBe 4eGciVDgpBoKhtw9Kv6LCDj2cwZKC8DxBMibf7GHkOnAsX2mnyuHcey7HvYNCoF+ yYz7oIEXdlL2eWqg7CfBZK7lniCDln50RI4Ll1v+J4r1v1kRZGMLesTYXCdNc4ku yb4kpU4t22/RODffLE7K+fc3Onwze3fcfxlZMN66F+wFtk4KdPR2aQBE66bB8J99 vuSKlTbT4cGL =s9AR -----END PGP SIGNATURE----- Merge tag 'pull-qapi-2024-03-04' of https://repo.or.cz/qemu/armbru into staging QAPI patches patches for 2024-03-04 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmXlaSISHGFybWJydUBy # ZWRoYXQuY29tAAoJEDhwtADrkYZTdZ8P/iMgqLoAFkCCjwfkUc/rqZUezK52Ynr7 # LYwOPI/xcYD7EnVogdRgFgjWFNoivQLP5yKsU/eRTk29pwdDzTscFm/0ztTQX/Gb # ypWV+GBcu5J8mKbp1KF5w68aDD8Bat4WRfEgDQ1DV7v6CoMiUzTiF3CGXkYzqK5Y # kYNq97vdEkBFvFdOl/7scs/XXN2jG27egDhMp68RTxnPHlXZiAO9/2Bul3uVe3x0 # fzQ2ViYv0qLnjE/PwENDqqE3Thv3Sxp5iEeQQ6GWi07EVh07UtHpOM3RYyrTU0Sb # VrTApSrg0oxlkOuR0CBd9Fi+timtbokBL0DWyUpXNTfIEZfLtA9H+8riUg3EOcDp # r7a4SI/27VdPxX6Kc6zA3bi+/j1o7CLTW2LGEwuZs52nmixoo1HTWPIFdyh13g/V # QjNbun0fViHb0FVLiyDlXF/7Y+EWUWIyqwwGqbvve1DyUHQmo3CUQAKGOpkeKSBe # 4eGciVDgpBoKhtw9Kv6LCDj2cwZKC8DxBMibf7GHkOnAsX2mnyuHcey7HvYNCoF+ # yYz7oIEXdlL2eWqg7CfBZK7lniCDln50RI4Ll1v+J4r1v1kRZGMLesTYXCdNc4ku # yb4kpU4t22/RODffLE7K+fc3Onwze3fcfxlZMN66F+wFtk4KdPR2aQBE66bB8J99 # vuSKlTbT4cGL # =s9AR # -----END PGP SIGNATURE----- # gpg: Signature made Mon 04 Mar 2024 06:24:34 GMT # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * tag 'pull-qapi-2024-03-04' of https://repo.or.cz/qemu/armbru: migration: simplify exec migration functions qapi: New strv_from_str_list() qapi: New QAPI_LIST_LENGTH() docs/devel/writing-monitor-commands: Minor improvements docs/devel/writing-monitor-commands: Repair a decade of rot qapi: Reject "Returns" section when command doesn't return anything qga/qapi-schema: Fix guest-set-memory-blocks documentation qga/qapi-schema: Tweak documentation of fsfreeze commands qga/qapi-schema: Clean up "Returns" sections qga/qapi-schema: Delete useless "Returns" sections qga/qapi-schema: Move error documentation to new "Errors" sections qapi/yank: Tweak @yank's error description for consistency qapi: Clean up "Returns" sections qapi: Delete useless "Returns" sections qapi: Move error documentation to new "Errors" sections qapi: New documentation section tag "Errors" qapi: Slightly clearer error message for invalid "Returns" section qapi: Memorize since & returns sections Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7d4e29ef80
@ -996,7 +996,8 @@ line "Features:", like this::
|
||||
|
||||
A tagged section begins with a paragraph that starts with one of the
|
||||
following words: "Note:"/"Notes:", "Since:", "Example:"/"Examples:",
|
||||
"Returns:", "TODO:". It ends with the start of a new section.
|
||||
"Returns:", "Errors:", "TODO:". It ends with the start of a new
|
||||
section.
|
||||
|
||||
The second and subsequent lines of tagged sections must be indented
|
||||
like this::
|
||||
@ -1007,6 +1008,9 @@ like this::
|
||||
# Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
# cillum dolore eu fugiat nulla pariatur.
|
||||
|
||||
"Returns" and "Errors" sections are only valid for commands. They
|
||||
document the success and the error response, respectively.
|
||||
|
||||
A "Since: x.y.z" tagged section lists the release that introduced the
|
||||
definition.
|
||||
|
||||
|
@ -66,12 +66,13 @@ Then, in a different terminal::
|
||||
"version": {
|
||||
"qemu": {
|
||||
"micro": 50,
|
||||
"minor": 15,
|
||||
"major": 0
|
||||
"minor": 2,
|
||||
"major": 8
|
||||
},
|
||||
"package": ""
|
||||
"package": ...
|
||||
},
|
||||
"capabilities": [
|
||||
"oob"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -107,10 +108,14 @@ The first step is defining the command in the appropriate QAPI schema
|
||||
module. We pick module qapi/misc.json, and add the following line at
|
||||
the bottom::
|
||||
|
||||
##
|
||||
# @hello-world:
|
||||
#
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'command': 'hello-world' }
|
||||
|
||||
The "command" keyword defines a new QMP command. It's an JSON object. All
|
||||
schema entries are JSON objects. The line above will instruct the QAPI to
|
||||
The "command" keyword defines a new QMP command. It instructs QAPI to
|
||||
generate any prototypes and the necessary code to marshal and unmarshal
|
||||
protocol data.
|
||||
|
||||
@ -132,57 +137,70 @@ There are a few things to be noticed:
|
||||
3. It takes an "Error \*\*" argument. This is required. Later we will see how to
|
||||
return errors and take additional arguments. The Error argument should not
|
||||
be touched if the command doesn't return errors
|
||||
4. We won't add the function's prototype. That's automatically done by the QAPI
|
||||
4. We won't add the function's prototype. That's automatically done by QAPI
|
||||
5. Printing to the terminal is discouraged for QMP commands, we do it here
|
||||
because it's the easiest way to demonstrate a QMP command
|
||||
|
||||
You're done. Now build qemu, run it as suggested in the "Testing" section,
|
||||
You're done. Now build QEMU, run it as suggested in the "Testing" section,
|
||||
and then type the following QMP command::
|
||||
|
||||
{ "execute": "hello-world" }
|
||||
|
||||
Then check the terminal running qemu and look for the "Hello, world" string. If
|
||||
Then check the terminal running QEMU and look for the "Hello, world" string. If
|
||||
you don't see it then something went wrong.
|
||||
|
||||
|
||||
Arguments
|
||||
~~~~~~~~~
|
||||
|
||||
Let's add an argument called "message" to our "hello-world" command. The new
|
||||
argument will contain the string to be printed to stdout. It's an optional
|
||||
argument, if it's not present we print our default "Hello, World" string.
|
||||
Let's add arguments to our "hello-world" command.
|
||||
|
||||
The first change we have to do is to modify the command specification in the
|
||||
schema file to the following::
|
||||
|
||||
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
||||
##
|
||||
# @hello-world:
|
||||
#
|
||||
# @message: message to be printed (default: "Hello, world!")
|
||||
#
|
||||
# @times: how many times to print the message (default: 1)
|
||||
#
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'command': 'hello-world',
|
||||
'data': { '*message': 'str', '*times': 'int' } }
|
||||
|
||||
Notice the new 'data' member in the schema. It's an JSON object whose each
|
||||
element is an argument to the command in question. Also notice the asterisk,
|
||||
it's used to mark the argument optional (that means that you shouldn't use it
|
||||
for mandatory arguments). Finally, 'str' is the argument's type, which
|
||||
stands for "string". The QAPI also supports integers, booleans, enumerations
|
||||
and user defined types.
|
||||
Notice the new 'data' member in the schema. It specifies an argument
|
||||
'message' of QAPI type 'str', and an argument 'times' of QAPI type
|
||||
'int'. Also notice the asterisk, it's used to mark the argument
|
||||
optional.
|
||||
|
||||
Now, let's update our C implementation in monitor/qmp-cmds.c::
|
||||
|
||||
void qmp_hello_world(const char *message, Error **errp)
|
||||
void qmp_hello_world(const char *message, bool has_times, int64_t times,
|
||||
Error **errp)
|
||||
{
|
||||
if (message) {
|
||||
if (!message) {
|
||||
message = "Hello, world";
|
||||
}
|
||||
if (!has_times) {
|
||||
times = 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < times; i++) {
|
||||
printf("%s\n", message);
|
||||
} else {
|
||||
printf("Hello, world\n");
|
||||
}
|
||||
}
|
||||
|
||||
There are two important details to be noticed:
|
||||
|
||||
1. All optional arguments are accompanied by a 'has\_' boolean, which is set
|
||||
if the optional argument is present or false otherwise
|
||||
1. Optional arguments other than pointers are accompanied by a 'has\_'
|
||||
boolean, which is set if the optional argument is present or false
|
||||
otherwise
|
||||
2. The C implementation signature must follow the schema's argument ordering,
|
||||
which is defined by the "data" member
|
||||
|
||||
Time to test our new version of the "hello-world" command. Build qemu, run it as
|
||||
Time to test our new version of the "hello-world" command. Build QEMU, run it as
|
||||
described in the "Testing" section and then send two commands::
|
||||
|
||||
{ "execute": "hello-world" }
|
||||
@ -191,13 +209,13 @@ described in the "Testing" section and then send two commands::
|
||||
}
|
||||
}
|
||||
|
||||
{ "execute": "hello-world", "arguments": { "message": "We love qemu" } }
|
||||
{ "execute": "hello-world", "arguments": { "message": "We love QEMU" } }
|
||||
{
|
||||
"return": {
|
||||
}
|
||||
}
|
||||
|
||||
You should see "Hello, world" and "We love qemu" in the terminal running qemu,
|
||||
You should see "Hello, world" and "We love QEMU" in the terminal running QEMU,
|
||||
if you don't see these strings, then something went wrong.
|
||||
|
||||
|
||||
@ -227,7 +245,7 @@ The first argument to the error_setg() function is the Error pointer
|
||||
to pointer, which is passed to all QMP functions. The next argument is a human
|
||||
description of the error, this is a free-form printf-like string.
|
||||
|
||||
Let's test the example above. Build qemu, run it as defined in the "Testing"
|
||||
Let's test the example above. Build QEMU, run it as defined in the "Testing"
|
||||
section, and then issue the following command::
|
||||
|
||||
{ "execute": "hello-world", "arguments": { "message": "all you need is love" } }
|
||||
@ -254,44 +272,14 @@ If the failure you want to report falls into one of the two cases above,
|
||||
use error_set() with a second argument of an ErrorClass value.
|
||||
|
||||
|
||||
Command Documentation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There's only one step missing to make "hello-world"'s implementation complete,
|
||||
and that's its documentation in the schema file.
|
||||
|
||||
There are many examples of such documentation in the schema file already, but
|
||||
here goes "hello-world"'s new entry for qapi/misc.json::
|
||||
|
||||
##
|
||||
# @hello-world:
|
||||
#
|
||||
# Print a client provided string to the standard output stream.
|
||||
#
|
||||
# @message: string to be printed
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Notes: if @message is not provided, the "Hello, world" string will
|
||||
# be printed instead
|
||||
#
|
||||
# Since: <next qemu stable release, eg. 1.0>
|
||||
##
|
||||
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
||||
|
||||
Please, note that the "Returns" clause is optional if a command doesn't return
|
||||
any data nor any errors.
|
||||
|
||||
|
||||
Implementing the HMP command
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now that the QMP command is in place, we can also make it available in the human
|
||||
monitor (HMP).
|
||||
|
||||
With the introduction of the QAPI, HMP commands make QMP calls. Most of the
|
||||
time HMP commands are simple wrappers. All HMP commands implementation exist in
|
||||
the monitor/hmp-cmds.c file.
|
||||
With the introduction of QAPI, HMP commands make QMP calls. Most of the
|
||||
time HMP commands are simple wrappers.
|
||||
|
||||
Here's the implementation of the "hello-world" HMP command::
|
||||
|
||||
@ -306,18 +294,20 @@ Here's the implementation of the "hello-world" HMP command::
|
||||
}
|
||||
}
|
||||
|
||||
Also, you have to add the function's prototype to the hmp.h file.
|
||||
Add it to monitor/hmp-cmds.c. Also, add its prototype to
|
||||
include/monitor/hmp.h.
|
||||
|
||||
There are three important points to be noticed:
|
||||
There are four important points to be noticed:
|
||||
|
||||
1. The "mon" and "qdict" arguments are mandatory for all HMP functions. The
|
||||
former is the monitor object. The latter is how the monitor passes
|
||||
arguments entered by the user to the command implementation
|
||||
2. hmp_hello_world() performs error checking. In this example we just call
|
||||
2. We chose not to support the "times" argument in HMP
|
||||
3. hmp_hello_world() performs error checking. In this example we just call
|
||||
hmp_handle_error() which prints a message to the user, but we could do
|
||||
more, like taking different actions depending on the error
|
||||
qmp_hello_world() returns
|
||||
3. The "err" variable must be initialized to NULL before performing the
|
||||
4. The "err" variable must be initialized to NULL before performing the
|
||||
QMP call
|
||||
|
||||
There's one last step to actually make the command available to monitor users,
|
||||
@ -340,17 +330,17 @@ To test this you have to open a user monitor and issue the "hello-world"
|
||||
command. It might be instructive to check the command's documentation with
|
||||
HMP's "help" command.
|
||||
|
||||
Please, check the "-monitor" command-line option to know how to open a user
|
||||
Please check the "-monitor" command-line option to know how to open a user
|
||||
monitor.
|
||||
|
||||
|
||||
Writing more complex commands
|
||||
-----------------------------
|
||||
|
||||
A QMP command is capable of returning any data the QAPI supports like integers,
|
||||
A QMP command is capable of returning any data QAPI supports like integers,
|
||||
strings, booleans, enumerations and user defined types.
|
||||
|
||||
In this section we will focus on user defined types. Please, check the QAPI
|
||||
In this section we will focus on user defined types. Please check the QAPI
|
||||
documentation for information about the other types.
|
||||
|
||||
|
||||
@ -372,7 +362,7 @@ data, it is not expected that machines will need to parse the result.
|
||||
The overhead of defining a fine grained QAPI type for the data may not
|
||||
be justified by the potential benefit. In such cases, it is permitted
|
||||
to have a command return a simple string that contains formatted data,
|
||||
however, it is mandatory for the command to use the 'x-' name prefix.
|
||||
however, it is mandatory for the command to be marked unstable.
|
||||
This indicates that the command is not guaranteed to be long term
|
||||
stable / liable to change in future and is not following QAPI design
|
||||
best practices. An example where this approach is taken is the QMP
|
||||
@ -386,302 +376,207 @@ an illustration.
|
||||
User Defined Types
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
FIXME This example needs to be redone after commit 6d32717
|
||||
For this example we will write the query-option-roms command, which
|
||||
returns information about ROMs loaded into the option ROM space. For
|
||||
more information about it, please check the "-option-rom" command-line
|
||||
option.
|
||||
|
||||
For this example we will write the query-alarm-clock command, which returns
|
||||
information about QEMU's timer alarm. For more information about it, please
|
||||
check the "-clock" command-line option.
|
||||
|
||||
We want to return two pieces of information. The first one is the alarm clock's
|
||||
name. The second one is when the next alarm will fire. The former information is
|
||||
returned as a string, the latter is an integer in nanoseconds (which is not
|
||||
very useful in practice, as the timer has probably already fired when the
|
||||
information reaches the client).
|
||||
|
||||
The best way to return that data is to create a new QAPI type, as shown below::
|
||||
For each option ROM, we want to return two pieces of information: the
|
||||
ROM image's file name, and its bootindex, if any. We need to create a
|
||||
new QAPI type for that, as shown below::
|
||||
|
||||
##
|
||||
# @QemuAlarmClock
|
||||
# @OptionRomInfo:
|
||||
#
|
||||
# QEMU alarm clock information.
|
||||
# @filename: option ROM image file name
|
||||
#
|
||||
# @clock-name: The alarm clock method's name.
|
||||
# @bootindex: option ROM's bootindex
|
||||
#
|
||||
# @next-deadline: The time (in nanoseconds) the next alarm will fire.
|
||||
#
|
||||
# Since: 1.0
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'type': 'QemuAlarmClock',
|
||||
'data': { 'clock-name': 'str', '*next-deadline': 'int' } }
|
||||
{ 'struct': 'OptionRomInfo',
|
||||
'data': { 'filename': 'str', '*bootindex': 'int' } }
|
||||
|
||||
The "type" keyword defines a new QAPI type. Its "data" member contains the
|
||||
type's members. In this example our members are the "clock-name" and the
|
||||
"next-deadline" one, which is optional.
|
||||
The "struct" keyword defines a new QAPI type. Its "data" member
|
||||
contains the type's members. In this example our members are
|
||||
"filename" and "bootindex". The latter is optional.
|
||||
|
||||
Now let's define the query-alarm-clock command::
|
||||
Now let's define the query-option-roms command::
|
||||
|
||||
##
|
||||
# @query-alarm-clock
|
||||
# @query-option-roms:
|
||||
#
|
||||
# Return information about QEMU's alarm clock.
|
||||
# Query information on ROMs loaded into the option ROM space.
|
||||
#
|
||||
# Returns a @QemuAlarmClock instance describing the alarm clock method
|
||||
# being currently used by QEMU (this is usually set by the '-clock'
|
||||
# command-line option).
|
||||
# Returns: OptionRomInfo
|
||||
#
|
||||
# Since: 1.0
|
||||
# Since: 9.0
|
||||
##
|
||||
{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' }
|
||||
{ 'command': 'query-option-roms',
|
||||
'returns': ['OptionRomInfo'] }
|
||||
|
||||
Notice the "returns" keyword. As its name suggests, it's used to define the
|
||||
data returned by a command.
|
||||
|
||||
It's time to implement the qmp_query_alarm_clock() function, you can put it
|
||||
in the qemu-timer.c file::
|
||||
Notice the syntax ['OptionRomInfo']". This should be read as "returns
|
||||
a list of OptionRomInfo".
|
||||
|
||||
QemuAlarmClock *qmp_query_alarm_clock(Error **errp)
|
||||
It's time to implement the qmp_query_option_roms() function. Add to
|
||||
monitor/qmp-cmds.c::
|
||||
|
||||
OptionRomInfoList *qmp_query_option_roms(Error **errp)
|
||||
{
|
||||
QemuAlarmClock *clock;
|
||||
int64_t deadline;
|
||||
OptionRomInfoList *info_list = NULL;
|
||||
OptionRomInfoList **tailp = &info_list;
|
||||
OptionRomInfo *info;
|
||||
|
||||
clock = g_malloc0(sizeof(*clock));
|
||||
|
||||
deadline = qemu_next_alarm_deadline();
|
||||
if (deadline > 0) {
|
||||
clock->has_next_deadline = true;
|
||||
clock->next_deadline = deadline;
|
||||
for (int i = 0; i < nb_option_roms; i++) {
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->filename = g_strdup(option_rom[i].name);
|
||||
info->has_bootindex = option_rom[i].bootindex >= 0;
|
||||
if (info->has_bootindex) {
|
||||
info->bootindex = option_rom[i].bootindex;
|
||||
}
|
||||
QAPI_LIST_APPEND(tailp, info);
|
||||
}
|
||||
clock->clock_name = g_strdup(alarm_timer->name);
|
||||
|
||||
return clock;
|
||||
return info_list;
|
||||
}
|
||||
|
||||
There are a number of things to be noticed:
|
||||
|
||||
1. The QemuAlarmClock type is automatically generated by the QAPI framework,
|
||||
its members correspond to the type's specification in the schema file
|
||||
2. As specified in the schema file, the function returns a QemuAlarmClock
|
||||
instance and takes no arguments (besides the "errp" one, which is mandatory
|
||||
for all QMP functions)
|
||||
3. The "clock" variable (which will point to our QAPI type instance) is
|
||||
allocated by the regular g_malloc0() function. Note that we chose to
|
||||
initialize the memory to zero. This is recommended for all QAPI types, as
|
||||
it helps avoiding bad surprises (specially with booleans)
|
||||
4. Remember that "next_deadline" is optional? Non-pointer optional
|
||||
members have a 'has_TYPE_NAME' member that should be properly set
|
||||
1. Type OptionRomInfo is automatically generated by the QAPI framework,
|
||||
its members correspond to the type's specification in the schema
|
||||
file
|
||||
2. Type OptionRomInfoList is also generated. It's a singly linked
|
||||
list.
|
||||
3. As specified in the schema file, the function returns a
|
||||
OptionRomInfoList, and takes no arguments (besides the "errp" one,
|
||||
which is mandatory for all QMP functions)
|
||||
4. The returned object is dynamically allocated
|
||||
5. All strings are dynamically allocated. This is so because QAPI also
|
||||
generates a function to free its types and it cannot distinguish
|
||||
between dynamically or statically allocated strings
|
||||
6. Remember that "bootindex" is optional? As a non-pointer optional
|
||||
member, it comes with a 'has_bootindex' member that needs to be set
|
||||
by the implementation, as shown above
|
||||
5. Even static strings, such as "alarm_timer->name", should be dynamically
|
||||
allocated by the implementation. This is so because the QAPI also generates
|
||||
a function to free its types and it cannot distinguish between dynamically
|
||||
or statically allocated strings
|
||||
6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c
|
||||
|
||||
Time to test the new command. Build qemu, run it as described in the "Testing"
|
||||
Time to test the new command. Build QEMU, run it as described in the "Testing"
|
||||
section and try this::
|
||||
|
||||
{ "execute": "query-alarm-clock" }
|
||||
{ "execute": "query-option-rom" }
|
||||
{
|
||||
"return": {
|
||||
"next-deadline": 2368219,
|
||||
"clock-name": "dynticks"
|
||||
}
|
||||
"return": [
|
||||
{
|
||||
"filename": "kvmvapic.bin"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
The HMP command
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Here's the HMP counterpart of the query-alarm-clock command::
|
||||
Here's the HMP counterpart of the query-option-roms command::
|
||||
|
||||
void hmp_info_alarm_clock(Monitor *mon)
|
||||
void hmp_info_option_roms(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
QemuAlarmClock *clock;
|
||||
Error *err = NULL;
|
||||
OptionRomInfoList *info_list, *tail;
|
||||
OptionRomInfo *info;
|
||||
|
||||
clock = qmp_query_alarm_clock(&err);
|
||||
info_list = qmp_query_option_roms(&err);
|
||||
if (hmp_handle_error(mon, err)) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_name);
|
||||
if (clock->has_next_deadline) {
|
||||
monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseconds\n",
|
||||
clock->next_deadline);
|
||||
}
|
||||
|
||||
qapi_free_QemuAlarmClock(clock);
|
||||
}
|
||||
|
||||
It's important to notice that hmp_info_alarm_clock() calls
|
||||
qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock().
|
||||
For user defined types, the QAPI will generate a qapi_free_QAPI_TYPE_NAME()
|
||||
function and that's what you have to use to free the types you define and
|
||||
qapi_free_QAPI_TYPE_NAMEList() for list types (explained in the next section).
|
||||
If the QMP call returns a string, then you should g_free() to free it.
|
||||
|
||||
Also note that hmp_info_alarm_clock() performs error handling. That's not
|
||||
strictly required if you're sure the QMP function doesn't return errors, but
|
||||
it's good practice to always check for errors.
|
||||
|
||||
Another important detail is that HMP's "info" commands don't go into the
|
||||
hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined
|
||||
in the monitor/misc.c file. The entry for the "info alarmclock" follows::
|
||||
|
||||
{
|
||||
.name = "alarmclock",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show information about the alarm clock",
|
||||
.cmd = hmp_info_alarm_clock,
|
||||
},
|
||||
|
||||
To test this, run qemu and type "info alarmclock" in the user monitor.
|
||||
|
||||
|
||||
Returning Lists
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
For this example, we're going to return all available methods for the timer
|
||||
alarm, which is pretty much what the command-line option "-clock ?" does,
|
||||
except that we're also going to inform which method is in use.
|
||||
|
||||
This first step is to define a new type::
|
||||
|
||||
##
|
||||
# @TimerAlarmMethod
|
||||
#
|
||||
# Timer alarm method information.
|
||||
#
|
||||
# @method-name: The method's name.
|
||||
#
|
||||
# @current: true if this alarm method is currently in use, false otherwise
|
||||
#
|
||||
# Since: 1.0
|
||||
##
|
||||
{ 'type': 'TimerAlarmMethod',
|
||||
'data': { 'method-name': 'str', 'current': 'bool' } }
|
||||
|
||||
The command will be called "query-alarm-methods", here is its schema
|
||||
specification::
|
||||
|
||||
##
|
||||
# @query-alarm-methods
|
||||
#
|
||||
# Returns information about available alarm methods.
|
||||
#
|
||||
# Returns: a list of @TimerAlarmMethod for each method
|
||||
#
|
||||
# Since: 1.0
|
||||
##
|
||||
{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] }
|
||||
|
||||
Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this
|
||||
should be read as "returns a list of TimerAlarmMethod instances".
|
||||
|
||||
The C implementation follows::
|
||||
|
||||
TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
|
||||
{
|
||||
TimerAlarmMethodList *method_list = NULL;
|
||||
const struct qemu_alarm_timer *p;
|
||||
bool current = true;
|
||||
|
||||
for (p = alarm_timers; p->name; p++) {
|
||||
TimerAlarmMethod *value = g_malloc0(*value);
|
||||
value->method_name = g_strdup(p->name);
|
||||
value->current = current;
|
||||
QAPI_LIST_PREPEND(method_list, value);
|
||||
current = false;
|
||||
}
|
||||
|
||||
return method_list;
|
||||
}
|
||||
|
||||
The most important difference from the previous examples is the
|
||||
TimerAlarmMethodList type, which is automatically generated by the QAPI from
|
||||
the TimerAlarmMethod type.
|
||||
|
||||
Each list node is represented by a TimerAlarmMethodList instance. We have to
|
||||
allocate it, and that's done inside the for loop: the "info" pointer points to
|
||||
an allocated node. We also have to allocate the node's contents, which is
|
||||
stored in its "value" member. In our example, the "value" member is a pointer
|
||||
to an TimerAlarmMethod instance.
|
||||
|
||||
Notice that the "current" variable is used as "true" only in the first
|
||||
iteration of the loop. That's because the alarm timer method in use is the
|
||||
first element of the alarm_timers array. Also notice that QAPI lists are handled
|
||||
by hand and we return the head of the list.
|
||||
|
||||
Now Build qemu, run it as explained in the "Testing" section and try our new
|
||||
command::
|
||||
|
||||
{ "execute": "query-alarm-methods" }
|
||||
{
|
||||
"return": [
|
||||
{
|
||||
"current": false,
|
||||
"method-name": "unix"
|
||||
},
|
||||
{
|
||||
"current": true,
|
||||
"method-name": "dynticks"
|
||||
for (tail = info_list; tail; tail = tail->next) {
|
||||
info = tail->value;
|
||||
monitor_printf(mon, "%s", info->filename);
|
||||
if (info->has_bootindex) {
|
||||
monitor_printf(mon, " %" PRId64, info->bootindex);
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
The HMP counterpart is a bit more complex than previous examples because it
|
||||
has to traverse the list, it's shown below for reference::
|
||||
|
||||
void hmp_info_alarm_methods(Monitor *mon)
|
||||
{
|
||||
TimerAlarmMethodList *method_list, *method;
|
||||
Error *err = NULL;
|
||||
|
||||
method_list = qmp_query_alarm_methods(&err);
|
||||
if (hmp_handle_error(mon, err)) {
|
||||
return;
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
for (method = method_list; method; method = method->next) {
|
||||
monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ',
|
||||
method->value->method_name);
|
||||
}
|
||||
|
||||
qapi_free_TimerAlarmMethodList(method_list);
|
||||
qapi_free_OptionRomInfoList(info_list);
|
||||
}
|
||||
|
||||
It's important to notice that hmp_info_option_roms() calls
|
||||
qapi_free_OptionRomInfoList() to free the data returned by
|
||||
qmp_query_option_roms(). For user defined types, QAPI will generate a
|
||||
qapi_free_QAPI_TYPE_NAME() function, and that's what you have to use to
|
||||
free the types you define and qapi_free_QAPI_TYPE_NAMEList() for list
|
||||
types (explained in the next section). If the QMP function returns a
|
||||
string, then you should g_free() to free it.
|
||||
|
||||
Also note that hmp_info_option_roms() performs error handling. That's
|
||||
not strictly required when you're sure the QMP function doesn't return
|
||||
errors; you could instead pass it &error_abort then.
|
||||
|
||||
Another important detail is that HMP's "info" commands go into
|
||||
hmp-commands-info.hx, not hmp-commands.hx. The entry for the "info
|
||||
option-roms" follows::
|
||||
|
||||
{
|
||||
.name = "option-roms",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show roms",
|
||||
.cmd = hmp_info_option_roms,
|
||||
},
|
||||
SRST
|
||||
``info option-roms``
|
||||
Show the option ROMs.
|
||||
ERST
|
||||
|
||||
To test this, run QEMU and type "info option-roms" in the user monitor.
|
||||
|
||||
|
||||
Writing a debugging aid returning unstructured text
|
||||
---------------------------------------------------
|
||||
|
||||
As discussed in section `Modelling data in QAPI`_, it is required that
|
||||
commands expecting machine usage be using fine-grained QAPI data types.
|
||||
The exception to this rule applies when the command is solely intended
|
||||
as a debugging aid and allows for returning unstructured text. This is
|
||||
commonly needed for query commands that report aspects of QEMU's
|
||||
internal state that are useful to human operators.
|
||||
as a debugging aid and allows for returning unstructured text, such as
|
||||
a query command that report aspects of QEMU's internal state that are
|
||||
useful only to human operators.
|
||||
|
||||
In this example we will consider a simplified variant of the HMP
|
||||
command ``info roms``. Following the earlier rules, this command will
|
||||
need to live under the ``x-`` name prefix, so its QMP implementation
|
||||
will be called ``x-query-roms``. It will have no parameters and will
|
||||
return a single text string::
|
||||
|
||||
{ 'struct': 'HumanReadableText',
|
||||
'data': { 'human-readable-text': 'str' } }
|
||||
In this example we will consider the existing QMP command
|
||||
``x-query-roms`` in qapi/machine.json. It has no parameters and
|
||||
returns a ``HumanReadableText``::
|
||||
|
||||
##
|
||||
# @x-query-roms:
|
||||
#
|
||||
# Query information on the registered ROMS
|
||||
#
|
||||
# Features:
|
||||
#
|
||||
# @unstable: This command is meant for debugging.
|
||||
#
|
||||
# Returns: registered ROMs
|
||||
#
|
||||
# Since: 6.2
|
||||
##
|
||||
{ 'command': 'x-query-roms',
|
||||
'returns': 'HumanReadableText' }
|
||||
'returns': 'HumanReadableText',
|
||||
'features': [ 'unstable' ] }
|
||||
|
||||
The ``HumanReadableText`` struct is intended to be used for all
|
||||
commands, under the ``x-`` name prefix that are returning unstructured
|
||||
text targeted at humans. It should never be used for commands outside
|
||||
the ``x-`` name prefix, as those should be using structured QAPI types.
|
||||
The ``HumanReadableText`` struct is defined in qapi/common.json as a
|
||||
struct with a string member. It is intended to be used for all
|
||||
commands that are returning unstructured text targeted at
|
||||
humans. These should all have feature 'unstable'. Note that the
|
||||
feature's documentation states why the command is unstable. We
|
||||
commonly use a ``x-`` command name prefix to make lack of stability
|
||||
obvious to human users.
|
||||
|
||||
Implementing the QMP command
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The QMP implementation will typically involve creating a ``GString``
|
||||
object and printing formatted data into it::
|
||||
object and printing formatted data into it, like this::
|
||||
|
||||
HumanReadableText *qmp_x_query_roms(Error **errp)
|
||||
{
|
||||
@ -698,6 +593,9 @@ object and printing formatted data into it::
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
The actual implementation emits more information. You can find it in
|
||||
hw/core/loader.c.
|
||||
|
||||
|
||||
Implementing the HMP command
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -706,7 +604,7 @@ Now that the QMP command is in place, we can also make it available in
|
||||
the human monitor (HMP) as shown in previous examples. The HMP
|
||||
implementations will all look fairly similar, as all they need do is
|
||||
invoke the QMP command and then print the resulting text or error
|
||||
message. Here's the implementation of the "info roms" HMP command::
|
||||
message. Here's an implementation of the "info roms" HMP command::
|
||||
|
||||
void hmp_info_roms(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
@ -746,3 +644,5 @@ field NULL::
|
||||
.help = "show roms",
|
||||
.cmd_info_hrt = qmp_x_query_roms,
|
||||
},
|
||||
|
||||
This is how the actual HMP command is done.
|
||||
|
@ -12,3 +12,11 @@
|
||||
#include "qapi/qapi-types-common.h"
|
||||
|
||||
HumanReadableText *human_readable_text_from_str(GString *str);
|
||||
|
||||
/*
|
||||
* Produce and return a NULL-terminated array of strings from @list.
|
||||
* The result is g_malloc()'d and all strings are g_strdup()'d. It
|
||||
* can be freed with g_strfreev(), or by g_auto(GStrv) automatic
|
||||
* cleanup.
|
||||
*/
|
||||
char **strv_from_str_list(const strList *list);
|
||||
|
@ -56,4 +56,17 @@ int parse_qapi_name(const char *name, bool complete);
|
||||
(tail) = &(*(tail))->next; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* For any GenericList @list, return its length.
|
||||
*/
|
||||
#define QAPI_LIST_LENGTH(list) \
|
||||
({ \
|
||||
size_t _len = 0; \
|
||||
typeof(list) _tail; \
|
||||
for (_tail = list; _tail != NULL; _tail = _tail->next) { \
|
||||
_len++; \
|
||||
} \
|
||||
_len; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/type-helpers.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "channel.h"
|
||||
#include "exec.h"
|
||||
@ -39,51 +40,16 @@ const char *exec_get_cmd_path(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* provides the length of strList */
|
||||
static int
|
||||
str_list_length(strList *list)
|
||||
{
|
||||
int len = 0;
|
||||
strList *elem;
|
||||
|
||||
for (elem = list; elem != NULL; elem = elem->next) {
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
init_exec_array(strList *command, char **argv, Error **errp)
|
||||
{
|
||||
int i = 0;
|
||||
strList *lst;
|
||||
|
||||
for (lst = command; lst; lst = lst->next) {
|
||||
argv[i++] = lst->value;
|
||||
}
|
||||
|
||||
argv[i] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
void exec_start_outgoing_migration(MigrationState *s, strList *command,
|
||||
Error **errp)
|
||||
{
|
||||
QIOChannel *ioc;
|
||||
|
||||
int length = str_list_length(command);
|
||||
g_auto(GStrv) argv = (char **) g_new0(const char *, length + 1);
|
||||
|
||||
init_exec_array(command, argv, errp);
|
||||
QIOChannel *ioc = NULL;
|
||||
g_auto(GStrv) argv = strv_from_str_list(command);
|
||||
const char * const *args = (const char * const *) argv;
|
||||
g_autofree char *new_command = g_strjoinv(" ", (char **)argv);
|
||||
|
||||
trace_migration_exec_outgoing(new_command);
|
||||
ioc = QIO_CHANNEL(
|
||||
qio_channel_command_new_spawn(
|
||||
(const char * const *) g_steal_pointer(&argv),
|
||||
O_RDWR,
|
||||
errp));
|
||||
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(args, O_RDWR, errp));
|
||||
if (!ioc) {
|
||||
return;
|
||||
}
|
||||
@ -105,19 +71,12 @@ static gboolean exec_accept_incoming_migration(QIOChannel *ioc,
|
||||
void exec_start_incoming_migration(strList *command, Error **errp)
|
||||
{
|
||||
QIOChannel *ioc;
|
||||
|
||||
int length = str_list_length(command);
|
||||
g_auto(GStrv) argv = (char **) g_new0(const char *, length + 1);
|
||||
|
||||
init_exec_array(command, argv, errp);
|
||||
g_auto(GStrv) argv = strv_from_str_list(command);
|
||||
const char * const *args = (const char * const *) argv;
|
||||
g_autofree char *new_command = g_strjoinv(" ", (char **)argv);
|
||||
|
||||
trace_migration_exec_incoming(new_command);
|
||||
ioc = QIO_CHANNEL(
|
||||
qio_channel_command_new_spawn(
|
||||
(const char * const *) g_steal_pointer(&argv),
|
||||
O_RDWR,
|
||||
errp));
|
||||
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(args, O_RDWR, errp));
|
||||
if (!ioc) {
|
||||
return;
|
||||
}
|
||||
|
@ -1456,8 +1456,7 @@
|
||||
#
|
||||
# @size: new image size in bytes
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, DeviceNotFound
|
||||
#
|
||||
# Since: 0.14
|
||||
@ -1674,8 +1673,7 @@
|
||||
#
|
||||
# For the arguments, see the documentation of BlockdevSnapshotSync.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, DeviceNotFound
|
||||
#
|
||||
# Since: 0.14
|
||||
@ -1754,8 +1752,7 @@
|
||||
# is not validated, so care should be taken when specifying the
|
||||
# string or the image chain may not be able to be reopened again.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If "device" does not exist or cannot be determined,
|
||||
# DeviceNotFound
|
||||
#
|
||||
@ -1854,8 +1851,7 @@
|
||||
# @deprecated: Members @base and @top are deprecated. Use @base-node
|
||||
# and @top-node instead.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @device does not exist, DeviceNotFound
|
||||
# - Any other error returns a GenericError.
|
||||
#
|
||||
@ -1894,8 +1890,7 @@
|
||||
# @deprecated: This command is deprecated. Use @blockdev-backup
|
||||
# instead.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, GenericError
|
||||
#
|
||||
# Since: 1.6
|
||||
@ -1921,8 +1916,7 @@
|
||||
# 'backup'. The operation can be stopped before it has completed using
|
||||
# the block-job-cancel command.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, DeviceNotFound
|
||||
#
|
||||
# Since: 2.3
|
||||
@ -2127,8 +2121,7 @@
|
||||
# specifies the format of the mirror image, default is to probe if
|
||||
# mode='existing', else the format of the source.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, GenericError
|
||||
#
|
||||
# Since: 1.3
|
||||
@ -2304,8 +2297,7 @@
|
||||
# Create a dirty bitmap with a name on the node, and start tracking
|
||||
# the writes.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @node is not a valid block device or node, DeviceNotFound
|
||||
# - If @name is already taken, GenericError with an explanation
|
||||
#
|
||||
@ -2328,8 +2320,7 @@
|
||||
# with block-dirty-bitmap-add. If the bitmap is persistent, remove it
|
||||
# from its storage too.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @node is not a valid block device or node, DeviceNotFound
|
||||
# - If @name is not found, GenericError with an explanation
|
||||
# - if @name is frozen by an operation, GenericError
|
||||
@ -2353,8 +2344,7 @@
|
||||
# backup from this point in time forward will only backup clusters
|
||||
# modified after this clear operation.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @node is not a valid block device, DeviceNotFound
|
||||
# - If @name is not found, GenericError with an explanation
|
||||
#
|
||||
@ -2375,8 +2365,7 @@
|
||||
#
|
||||
# Enables a dirty bitmap so that it will begin tracking disk changes.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @node is not a valid block device, DeviceNotFound
|
||||
# - If @name is not found, GenericError with an explanation
|
||||
#
|
||||
@ -2397,8 +2386,7 @@
|
||||
#
|
||||
# Disables a dirty bitmap so that it will stop tracking disk changes.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @node is not a valid block device, DeviceNotFound
|
||||
# - If @name is not found, GenericError with an explanation
|
||||
#
|
||||
@ -2427,8 +2415,7 @@
|
||||
# dirty in any of the source bitmaps. This can be used to achieve
|
||||
# backup checkpoints, or in simpler usages, to copy bitmaps.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @node is not a valid block device, DeviceNotFound
|
||||
# - If any bitmap in @bitmaps or @target is not found,
|
||||
# GenericError
|
||||
@ -2470,7 +2457,9 @@
|
||||
# @unstable: This command is meant for debugging.
|
||||
#
|
||||
# Returns:
|
||||
# - BlockDirtyBitmapSha256 on success
|
||||
# BlockDirtyBitmapSha256
|
||||
#
|
||||
# Errors:
|
||||
# - If @node is not a valid block device, DeviceNotFound
|
||||
# - If @name is not found or if hashing has failed, GenericError
|
||||
# with an explanation
|
||||
@ -2542,8 +2531,6 @@
|
||||
# disappear from the query list without user intervention.
|
||||
# Defaults to true. (Since 3.1)
|
||||
#
|
||||
# Returns: nothing on success.
|
||||
#
|
||||
# Since: 2.6
|
||||
#
|
||||
# Example:
|
||||
@ -2866,8 +2853,7 @@
|
||||
# disappear from the query list without user intervention.
|
||||
# Defaults to true. (Since 3.1)
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success.
|
||||
# Errors:
|
||||
# - If @device does not exist, DeviceNotFound.
|
||||
#
|
||||
# Since: 1.1
|
||||
@ -2905,8 +2891,7 @@
|
||||
# @speed: the maximum speed, in bytes per second, or 0 for unlimited.
|
||||
# Defaults to 0.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If no background operation is active on this device,
|
||||
# DeviceNotActive
|
||||
#
|
||||
@ -2950,8 +2935,7 @@
|
||||
# paused) instead of waiting for the destination to complete its
|
||||
# final synchronization (since 1.3)
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If no background operation is active on this device,
|
||||
# DeviceNotActive
|
||||
#
|
||||
@ -2977,8 +2961,7 @@
|
||||
# the name of the parameter), but since QEMU 2.7 it can have other
|
||||
# values.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If no background operation is active on this device,
|
||||
# DeviceNotActive
|
||||
#
|
||||
@ -3002,8 +2985,7 @@
|
||||
# the name of the parameter), but since QEMU 2.7 it can have other
|
||||
# values.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If no background operation is active on this device,
|
||||
# DeviceNotActive
|
||||
#
|
||||
@ -3034,8 +3016,7 @@
|
||||
# the name of the parameter), but since QEMU 2.7 it can have other
|
||||
# values.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If no background operation is active on this device,
|
||||
# DeviceNotActive
|
||||
#
|
||||
@ -3059,8 +3040,6 @@
|
||||
#
|
||||
# @id: The job identifier.
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' },
|
||||
@ -3078,8 +3057,6 @@
|
||||
#
|
||||
# @id: The job identifier.
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'command': 'block-job-finalize', 'data': { 'id': 'str' },
|
||||
@ -6070,8 +6047,7 @@
|
||||
# For the arguments, see the documentation of
|
||||
# BlockdevSnapshotInternal.
|
||||
#
|
||||
# Returns:
|
||||
# - nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, GenericError
|
||||
# - If any snapshot matching @name exists, or @name is empty,
|
||||
# GenericError
|
||||
@ -6108,7 +6084,9 @@
|
||||
# @name: optional the snapshot's name to be deleted
|
||||
#
|
||||
# Returns:
|
||||
# - SnapshotInfo on success
|
||||
# SnapshotInfo
|
||||
#
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, GenericError
|
||||
# - If snapshot not found, GenericError
|
||||
# - If the format of the image used does not support it,
|
||||
|
@ -65,7 +65,8 @@
|
||||
# server from advertising multiple client support (since 5.2;
|
||||
# default: 0).
|
||||
#
|
||||
# Returns: error if the server is already running.
|
||||
# Errors:
|
||||
# - if the server is already running
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
@ -247,8 +248,9 @@
|
||||
# @deprecated: This command is deprecated. Use @block-export-add
|
||||
# instead.
|
||||
#
|
||||
# Returns: error if the server is not running, or export with the same
|
||||
# name already exists.
|
||||
# Errors:
|
||||
# - if the server is not running
|
||||
# - if an export with the same name already exists
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
@ -294,11 +296,10 @@
|
||||
# @deprecated: This command is deprecated. Use @block-export-del
|
||||
# instead.
|
||||
#
|
||||
# Returns: error if
|
||||
#
|
||||
# - the server is not running
|
||||
# - export is not found
|
||||
# - mode is 'safe' and there are existing connections
|
||||
# Errors:
|
||||
# - if the server is not running
|
||||
# - if export is not found
|
||||
# - if mode is 'safe' and there are existing connections
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
@ -415,8 +416,10 @@
|
||||
# @mode: Mode of command operation. See @BlockExportRemoveMode
|
||||
# description. Default is 'safe'.
|
||||
#
|
||||
# Returns: Error if the export is not found or @mode is 'safe' and the
|
||||
# export is still in use (e.g. by existing client connections)
|
||||
# Errors:
|
||||
# - if the export is not found
|
||||
# - if @mode is 'safe' and the export is still in use (e.g. by
|
||||
# existing client connections)
|
||||
#
|
||||
# Since: 5.2
|
||||
##
|
||||
|
@ -110,8 +110,7 @@
|
||||
#
|
||||
# @deprecated: Member @device is deprecated. Use @id instead.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, DeviceNotFound
|
||||
#
|
||||
# Notes: Ejecting a device with no media results in success
|
||||
@ -459,8 +458,7 @@
|
||||
# the device will be removed from its group and the rest of its
|
||||
# members will not be affected. The 'group' parameter is ignored.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @device is not a valid block device, DeviceNotFound
|
||||
#
|
||||
# Since: 1.1
|
||||
@ -540,8 +538,8 @@
|
||||
# @boundaries-flush: list of interval boundary values for flush
|
||||
# latency histogram.
|
||||
#
|
||||
# Returns: error if device is not found or any boundary arrays are
|
||||
# invalid.
|
||||
# Errors:
|
||||
# - if device is not found or any boundary arrays are invalid.
|
||||
#
|
||||
# Since: 4.0
|
||||
#
|
||||
|
@ -139,8 +139,6 @@
|
||||
# - data itself is always Unicode regardless of format, like any
|
||||
# other string.
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 1.4
|
||||
#
|
||||
# Example:
|
||||
@ -772,8 +770,6 @@
|
||||
#
|
||||
# @id: the chardev's ID, must exist and not be in use
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 1.4
|
||||
#
|
||||
# Example:
|
||||
@ -791,8 +787,6 @@
|
||||
#
|
||||
# @id: the chardev's ID, must exist
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 2.10
|
||||
#
|
||||
# Example:
|
||||
|
@ -92,8 +92,6 @@
|
||||
#
|
||||
# Note: All boolean arguments default to false
|
||||
#
|
||||
# Returns: nothing on success
|
||||
#
|
||||
# Since: 1.2
|
||||
#
|
||||
# Example:
|
||||
|
@ -154,10 +154,13 @@
|
||||
# Some architectures may not support comparing CPU models. s390x
|
||||
# supports comparing CPU models.
|
||||
#
|
||||
# Returns: a CpuModelBaselineInfo. Returns an error if comparing CPU
|
||||
# models is not supported, if a model cannot be used, if a model
|
||||
# contains an unknown cpu definition name, unknown properties or
|
||||
# properties with wrong types.
|
||||
# Returns: a CpuModelBaselineInfo
|
||||
#
|
||||
# Errors:
|
||||
# - if comparing CPU models is not supported
|
||||
# - if a model cannot be used
|
||||
# - if a model contains an unknown cpu definition name, unknown
|
||||
# properties or properties with wrong types.
|
||||
#
|
||||
# Note: this command isn't specific to s390x, but is only implemented
|
||||
# on this architecture currently.
|
||||
@ -201,10 +204,13 @@
|
||||
# Some architectures may not support baselining CPU models. s390x
|
||||
# supports baselining CPU models.
|
||||
#
|
||||
# Returns: a CpuModelBaselineInfo. Returns an error if baselining CPU
|
||||
# models is not supported, if a model cannot be used, if a model
|
||||
# contains an unknown cpu definition name, unknown properties or
|
||||
# properties with wrong types.
|
||||
# Returns: a CpuModelBaselineInfo
|
||||
#
|
||||
# Errors:
|
||||
# - if baselining CPU models is not supported
|
||||
# - if a model cannot be used
|
||||
# - if a model contains an unknown cpu definition name, unknown
|
||||
# properties or properties with wrong types.
|
||||
#
|
||||
# Note: this command isn't specific to s390x, but is only implemented
|
||||
# on this architecture currently.
|
||||
@ -263,11 +269,14 @@
|
||||
# Some architectures may not support all expansion types. s390x
|
||||
# supports "full" and "static". Arm only supports "full".
|
||||
#
|
||||
# Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU
|
||||
# models is not supported, if the model cannot be expanded, if the
|
||||
# model contains an unknown CPU definition name, unknown
|
||||
# properties or properties with a wrong type. Also returns an
|
||||
# error if an expansion type is not supported.
|
||||
# Returns: a CpuModelExpansionInfo
|
||||
#
|
||||
# Errors:
|
||||
# - if expanding CPU models is not supported
|
||||
# - if the model cannot be expanded
|
||||
# - if the model contains an unknown CPU definition name, unknown
|
||||
# properties or properties with a wrong type
|
||||
# - if an expansion type is not supported
|
||||
#
|
||||
# Since: 2.8
|
||||
##
|
||||
@ -405,8 +414,6 @@
|
||||
#
|
||||
# @unstable: This command is experimental.
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 8.2
|
||||
##
|
||||
{ 'command': 'set-cpu-topology',
|
||||
|
@ -326,8 +326,6 @@
|
||||
#
|
||||
# Since: 1.1
|
||||
#
|
||||
# Returns: nothing.
|
||||
#
|
||||
# Note: prior to 4.0, this command does nothing in case the guest
|
||||
# isn't suspended.
|
||||
#
|
||||
@ -377,8 +375,6 @@
|
||||
# all CPUs (ppc64). The command fails when the guest doesn't support
|
||||
# injecting.
|
||||
#
|
||||
# Returns: If successful, nothing
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Note: prior to 2.1, this command was only supported for x86 and s390
|
||||
@ -778,8 +774,6 @@
|
||||
# @cpu-index: the index of the virtual CPU to use for translating the
|
||||
# virtual address (defaults to CPU 0)
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Notes: Errors were not reliably returned until 1.1
|
||||
@ -806,8 +800,6 @@
|
||||
#
|
||||
# @filename: the file to save the memory to as binary data
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Notes: Errors were not reliably returned until 1.1
|
||||
@ -1060,8 +1052,7 @@
|
||||
#
|
||||
# From it we have: balloon_size = vm_ram_size - @value
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If the balloon driver is enabled but not functional because
|
||||
# the KVM kernel module cannot support it, KVMMissingCap
|
||||
# - If no balloon device is present, DeviceNotActive
|
||||
@ -1099,7 +1090,9 @@
|
||||
# Return information about the balloon device.
|
||||
#
|
||||
# Returns:
|
||||
# - @BalloonInfo on success
|
||||
# @BalloonInfo
|
||||
#
|
||||
# Errors:
|
||||
# - If the balloon driver is enabled but not functional because
|
||||
# the KVM kernel module cannot support it, KVMMissingCap
|
||||
# - If no balloon device is present, DeviceNotActive
|
||||
@ -1163,7 +1156,9 @@
|
||||
# message from the guest.
|
||||
#
|
||||
# Returns:
|
||||
# - @HvBalloonInfo on success
|
||||
# @HvBalloonInfo
|
||||
#
|
||||
# Errors:
|
||||
# - If no hv-balloon device is present, guest memory status
|
||||
# reporting is not enabled or no guest memory status report
|
||||
# received yet, GenericError
|
||||
|
@ -1572,8 +1572,6 @@
|
||||
#
|
||||
# Cancel the current executing migration process.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
#
|
||||
# Notes: This command succeeds even if there is no migration process
|
||||
# running.
|
||||
#
|
||||
@ -1593,8 +1591,6 @@
|
||||
#
|
||||
# @state: The state the migration is currently expected to be in
|
||||
#
|
||||
# Returns: nothing on success
|
||||
#
|
||||
# Since: 2.11
|
||||
#
|
||||
# Example:
|
||||
@ -1716,8 +1712,6 @@
|
||||
# @deprecated: Members @inc and @blk are deprecated. Use
|
||||
# blockdev-mirror with NBD instead.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Notes:
|
||||
@ -1799,8 +1793,6 @@
|
||||
# @channels: list of migration stream channels with each stream in the
|
||||
# list connected to a destination interface endpoint.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
#
|
||||
# Since: 2.3
|
||||
#
|
||||
# Notes:
|
||||
@ -1868,8 +1860,6 @@
|
||||
# @live: Optional argument to ask QEMU to treat this command as part
|
||||
# of a live migration. Default to true. (since 2.11)
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 1.1
|
||||
#
|
||||
# Example:
|
||||
@ -1888,8 +1878,6 @@
|
||||
#
|
||||
# @enable: true to enable, false to disable.
|
||||
#
|
||||
# Returns: nothing
|
||||
#
|
||||
# Since: 1.3
|
||||
#
|
||||
# Example:
|
||||
@ -1932,8 +1920,6 @@
|
||||
# @failover: true to do failover, false to stop. but cannot be
|
||||
# specified if 'enable' is true. default value is false.
|
||||
#
|
||||
# Returns: nothing.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "xen-set-replication",
|
||||
@ -1985,8 +1971,6 @@
|
||||
#
|
||||
# Xen uses this command to notify replication to trigger a checkpoint.
|
||||
#
|
||||
# Returns: nothing.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "xen-colo-do-checkpoint" }
|
||||
@ -2043,8 +2027,6 @@
|
||||
#
|
||||
# @uri: the URI to be used for the recovery of migration stream.
|
||||
#
|
||||
# Returns: nothing.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "migrate-recover",
|
||||
@ -2062,8 +2044,6 @@
|
||||
#
|
||||
# Pause a migration. Currently it only supports postcopy.
|
||||
#
|
||||
# Returns: nothing.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "migrate-pause" }
|
||||
@ -2432,8 +2412,6 @@
|
||||
#
|
||||
# If @tag already exists, an error will be reported
|
||||
#
|
||||
# Returns: nothing
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "snapshot-save",
|
||||
@ -2504,8 +2482,6 @@
|
||||
# device nodes that can have changed since the original @snapshot-save
|
||||
# command execution.
|
||||
#
|
||||
# Returns: nothing
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "snapshot-load",
|
||||
@ -2567,8 +2543,6 @@
|
||||
# to determine completion and to fetch details of any errors that
|
||||
# arise.
|
||||
#
|
||||
# Returns: nothing
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "snapshot-delete",
|
||||
|
@ -472,9 +472,6 @@
|
||||
#
|
||||
# @port: The port number
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success.
|
||||
#
|
||||
# Since: 8.0
|
||||
#
|
||||
# Example:
|
||||
|
@ -28,8 +28,6 @@
|
||||
#
|
||||
# @tls: whether to perform TLS. Only applies to the "spice" protocol
|
||||
#
|
||||
# Returns: nothing on success.
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Example:
|
||||
@ -160,8 +158,6 @@
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Returns: If successful, nothing
|
||||
#
|
||||
# Notes: This command will succeed if the guest is currently running.
|
||||
# It will also succeed if the guest is in the "inmigrate" state;
|
||||
# in this case, the effect of the command is to make sure the
|
||||
@ -196,8 +192,6 @@
|
||||
#
|
||||
# Since: 3.0
|
||||
#
|
||||
# Returns: nothing
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "x-exit-preconfig" }
|
||||
@ -256,8 +250,6 @@
|
||||
#
|
||||
# @fdname: file descriptor name
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Notes: If @fdname already exists, the file descriptor assigned to it
|
||||
@ -285,8 +277,6 @@
|
||||
#
|
||||
# @fdname: file descriptor name
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 8.0
|
||||
#
|
||||
# Notes: If @fdname already exists, the file descriptor assigned to it
|
||||
@ -309,8 +299,6 @@
|
||||
#
|
||||
# @fdname: file descriptor name
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Example:
|
||||
@ -344,7 +332,9 @@
|
||||
# @opaque: A free-form string that can be used to describe the fd.
|
||||
#
|
||||
# Returns:
|
||||
# - @AddfdInfo on success
|
||||
# @AddfdInfo
|
||||
#
|
||||
# Errors:
|
||||
# - If file descriptor was not received, GenericError
|
||||
# - If @fdset-id is a negative value, GenericError
|
||||
#
|
||||
@ -374,8 +364,7 @@
|
||||
#
|
||||
# @fd: The file descriptor that is to be removed.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @fdset-id or @fd is not found, GenericError
|
||||
#
|
||||
# Since: 1.2
|
||||
@ -528,8 +517,10 @@
|
||||
# @option: option name
|
||||
#
|
||||
# Returns: list of @CommandLineOptionInfo for all options (or for the
|
||||
# given @option). Returns an error if the given @option doesn't
|
||||
# exist.
|
||||
# given @option).
|
||||
#
|
||||
# Errors:
|
||||
# - if the given @option doesn't exist
|
||||
#
|
||||
# Since: 1.5
|
||||
#
|
||||
|
@ -17,8 +17,7 @@
|
||||
#
|
||||
# @up: true to set the link status to be up
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @name is not a valid network device, DeviceNotFound
|
||||
#
|
||||
# Since: 0.14
|
||||
@ -44,8 +43,7 @@
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @type is not a valid network backend, DeviceNotFound
|
||||
#
|
||||
# Example:
|
||||
@ -65,8 +63,7 @@
|
||||
#
|
||||
# @id: the name of the network backend to remove
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @id is not a valid network backend, DeviceNotFound
|
||||
#
|
||||
# Since: 0.14
|
||||
@ -828,9 +825,11 @@
|
||||
# @name: net client name
|
||||
#
|
||||
# Returns: list of @RxFilterInfo for all NICs (or for the given NIC).
|
||||
# Returns an error if the given @name doesn't exist, or given NIC
|
||||
# doesn't support rx-filter querying, or given net client isn't a
|
||||
# NIC.
|
||||
#
|
||||
# Errors:
|
||||
# - if the given @name doesn't exist
|
||||
# - if the given NIC doesn't support rx-filter querying
|
||||
# - if the given net client isn't a NIC
|
||||
#
|
||||
# Since: 1.6
|
||||
#
|
||||
|
@ -21,3 +21,17 @@ HumanReadableText *human_readable_text_from_str(GString *str)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char **strv_from_str_list(const strList *list)
|
||||
{
|
||||
const strList *tail;
|
||||
int i = 0;
|
||||
char **strv = g_new(char *, QAPI_LIST_LENGTH(list) + 1);
|
||||
|
||||
for (tail = list; tail != NULL; tail = tail->next) {
|
||||
strv[i++] = g_strdup(tail->value);
|
||||
}
|
||||
strv[i] = NULL;
|
||||
|
||||
return strv;
|
||||
}
|
||||
|
@ -89,8 +89,7 @@
|
||||
#
|
||||
# @id: the device's ID or QOM path
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @id is not a valid device, DeviceNotFound
|
||||
#
|
||||
# Notes: When this command completes, the device may not be removed
|
||||
|
@ -1056,8 +1056,7 @@
|
||||
#
|
||||
# Create a QOM object.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - Error if @qom-type is not a valid class name
|
||||
#
|
||||
# Since: 2.0
|
||||
@ -1079,8 +1078,7 @@
|
||||
#
|
||||
# @id: the name of the QOM object to remove
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - Error if @id is not a valid id for a QOM object
|
||||
#
|
||||
# Since: 2.0
|
||||
|
@ -395,10 +395,7 @@
|
||||
#
|
||||
# @panic: @PanicAction action taken on guest panic.
|
||||
#
|
||||
# @watchdog: @WatchdogAction action taken when watchdog timer expires
|
||||
# .
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
# @watchdog: @WatchdogAction action taken when watchdog timer expires.
|
||||
#
|
||||
# Since: 6.0
|
||||
#
|
||||
|
@ -166,8 +166,6 @@
|
||||
#
|
||||
# Return information about the TPM device
|
||||
#
|
||||
# Returns: @TPMInfo on success
|
||||
#
|
||||
# Since: 1.5
|
||||
#
|
||||
# Example:
|
||||
|
@ -234,9 +234,8 @@
|
||||
# execution of the transaction. See @TransactionProperties for
|
||||
# additional detail.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
#
|
||||
# Errors depend on the operations of the transaction
|
||||
# Errors:
|
||||
# Any errors from commands in the transaction
|
||||
#
|
||||
# Note: The transaction aborts on the first failure. Therefore, there
|
||||
# will be information on only one failed operation returned in an
|
||||
|
17
qapi/ui.json
17
qapi/ui.json
@ -78,8 +78,7 @@
|
||||
#
|
||||
# Set the password of a remote display server.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If Spice is not enabled, DeviceNotFound
|
||||
#
|
||||
# Since: 0.14
|
||||
@ -140,8 +139,7 @@
|
||||
#
|
||||
# Expire the password of a remote display server.
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If @protocol is 'spice' and Spice is not active,
|
||||
# DeviceNotFound
|
||||
#
|
||||
@ -187,8 +185,6 @@
|
||||
#
|
||||
# @format: image format for screendump. (default: ppm) (Since 7.1)
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 0.14
|
||||
#
|
||||
# Example:
|
||||
@ -1036,8 +1032,7 @@
|
||||
# @hold-time: time to delay key up events, milliseconds. Defaults to
|
||||
# 100
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# Errors:
|
||||
# - If key is unknown or redundant, GenericError
|
||||
#
|
||||
# Since: 1.3
|
||||
@ -1259,8 +1254,6 @@
|
||||
#
|
||||
# @events: List of InputEvent union.
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 2.6
|
||||
#
|
||||
# Note: The consoles are visible in the qom tree, under
|
||||
@ -1605,8 +1598,6 @@
|
||||
#
|
||||
# Reload display configuration.
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 6.0
|
||||
#
|
||||
# Example:
|
||||
@ -1664,8 +1655,6 @@
|
||||
#
|
||||
# Update display configuration.
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 7.1
|
||||
#
|
||||
# Example:
|
||||
|
@ -78,9 +78,8 @@
|
||||
#
|
||||
# @instances: the instances to be yanked
|
||||
#
|
||||
# Returns:
|
||||
# - Nothing on success
|
||||
# - @DeviceNotFound error, if any of the YankInstances doesn't exist
|
||||
# Errors:
|
||||
# - If any of the YankInstances doesn't exist, DeviceNotFound
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
|
@ -153,8 +153,6 @@
|
||||
# @time: time of nanoseconds, relative to the Epoch of 1970-01-01 in
|
||||
# UTC.
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 1.5
|
||||
##
|
||||
{ 'command': 'guest-set-time',
|
||||
@ -230,7 +228,7 @@
|
||||
#
|
||||
# @mode: open mode, as per fopen(), "r" is the default.
|
||||
#
|
||||
# Returns: Guest file handle on success.
|
||||
# Returns: Guest file handle
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
@ -245,8 +243,6 @@
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-file-close',
|
||||
@ -281,7 +277,7 @@
|
||||
# @count: maximum number of bytes to read (default is 4KB, maximum is
|
||||
# 48MB)
|
||||
#
|
||||
# Returns: @GuestFileRead on success.
|
||||
# Returns: @GuestFileRead
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
@ -316,7 +312,7 @@
|
||||
# @count: bytes to write (actual bytes, after base64-decode), default
|
||||
# is all content in buf-b64 buffer after base64 decoding
|
||||
#
|
||||
# Returns: @GuestFileWrite on success.
|
||||
# Returns: @GuestFileWrite
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
@ -383,7 +379,7 @@
|
||||
#
|
||||
# @whence: Symbolic or numeric code for interpreting offset
|
||||
#
|
||||
# Returns: @GuestFileSeek on success.
|
||||
# Returns: @GuestFileSeek
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
@ -399,8 +395,6 @@
|
||||
#
|
||||
# @handle: filehandle returned by guest-file-open
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-file-flush',
|
||||
@ -443,15 +437,16 @@
|
||||
# command succeeded, you may call @guest-fsfreeze-thaw later to
|
||||
# unfreeze.
|
||||
#
|
||||
# On error, all filesystems will be thawed. If no filesystems are
|
||||
# frozen as a result of this call, then @guest-fsfreeze-status will
|
||||
# remain "thawed" and calling @guest-fsfreeze-thaw is not necessary.
|
||||
#
|
||||
# Returns: Number of file systems currently frozen.
|
||||
#
|
||||
# Note: On Windows, the command is implemented with the help of a
|
||||
# Volume Shadow-copy Service DLL helper. The frozen state is
|
||||
# limited for up to 10 seconds by VSS.
|
||||
#
|
||||
# Returns: Number of file systems currently frozen. On error, all
|
||||
# filesystems will be thawed. If no filesystems are frozen as a
|
||||
# result of this call, then @guest-fsfreeze-status will remain
|
||||
# "thawed" and calling @guest-fsfreeze-thaw is not necessary.
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-fsfreeze-freeze',
|
||||
@ -463,12 +458,13 @@
|
||||
# Sync and freeze specified guest filesystems. See also
|
||||
# @guest-fsfreeze-freeze.
|
||||
#
|
||||
# On error, all filesystems will be thawed.
|
||||
#
|
||||
# @mountpoints: an array of mountpoints of filesystems to be frozen.
|
||||
# If omitted, every mounted filesystem is frozen. Invalid mount
|
||||
# points are ignored.
|
||||
#
|
||||
# Returns: Number of file systems currently frozen. On error, all
|
||||
# filesystems will be thawed.
|
||||
# Returns: Number of file systems currently frozen.
|
||||
#
|
||||
# Since: 2.2
|
||||
##
|
||||
@ -561,9 +557,8 @@
|
||||
# could also exit (or set its status to "shutdown") due to other
|
||||
# reasons.
|
||||
#
|
||||
# The following errors may be returned:
|
||||
#
|
||||
# - If suspend to disk is not supported, Unsupported
|
||||
# Errors:
|
||||
# - If suspend to disk is not supported, Unsupported
|
||||
#
|
||||
# Notes: It's strongly recommended to issue the guest-sync command
|
||||
# before sending commands when the guest resumes
|
||||
@ -598,9 +593,8 @@
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# The following errors may be returned:
|
||||
#
|
||||
# - If suspend to ram is not supported, Unsupported
|
||||
# Errors:
|
||||
# - If suspend to ram is not supported, Unsupported
|
||||
#
|
||||
# Notes: It's strongly recommended to issue the guest-sync command
|
||||
# before sending commands when the guest resumes
|
||||
@ -634,9 +628,8 @@
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# The following errors may be returned:
|
||||
#
|
||||
# - If hybrid suspend is not supported, Unsupported
|
||||
# Errors:
|
||||
# - If hybrid suspend is not supported, Unsupported
|
||||
#
|
||||
# Notes: It's strongly recommended to issue the guest-sync command
|
||||
# before sending commands when the guest resumes
|
||||
@ -732,7 +725,7 @@
|
||||
#
|
||||
# Get list of guest IP addresses, MAC addresses and netmasks.
|
||||
#
|
||||
# Returns: List of GuestNetworkInterface on success.
|
||||
# Returns: List of GuestNetworkInterface
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
@ -796,9 +789,6 @@
|
||||
# - 0:
|
||||
# if the @vcpus list was empty on input. Guest state has not
|
||||
# been changed. Otherwise,
|
||||
# - Error:
|
||||
# processing the first node of @vcpus failed for the reason
|
||||
# returned. Guest state has not been changed. Otherwise,
|
||||
# - < length(@vcpus):
|
||||
# more than zero initial nodes have been processed, but not the
|
||||
# entire @vcpus list. Guest state has changed accordingly. To
|
||||
@ -808,6 +798,10 @@
|
||||
# - length(@vcpus):
|
||||
# call successful.
|
||||
#
|
||||
# Errors:
|
||||
# - If the reconfiguration of the first node in @vcpus failed.
|
||||
# Guest state has not been changed.
|
||||
#
|
||||
# Since: 1.5
|
||||
##
|
||||
{ 'command': 'guest-set-vcpus',
|
||||
@ -1079,8 +1073,6 @@
|
||||
# transmission, even if already crypt()d, to ensure it is 8-bit safe
|
||||
# when passed as JSON.
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'command': 'guest-set-user-password',
|
||||
@ -1184,9 +1176,9 @@
|
||||
# @GuestMemoryBlockResponse, which is corresponding to the input
|
||||
# list.
|
||||
#
|
||||
# Note: it will return NULL if the @mem-blks list was empty on
|
||||
# input, or there is an error, and in this case, guest state will
|
||||
# not be changed.
|
||||
# Note: it will return an empty list if the @mem-blks list was
|
||||
# empty on input, or there is an error, and in this case, guest
|
||||
# state will not be changed.
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
@ -1257,7 +1249,7 @@
|
||||
#
|
||||
# @pid: pid returned from guest-exec
|
||||
#
|
||||
# Returns: GuestExecStatus on success.
|
||||
# Returns: GuestExecStatus
|
||||
#
|
||||
# Since: 2.5
|
||||
##
|
||||
@ -1325,7 +1317,7 @@
|
||||
# @capture-output: bool flag to enable capture of stdout/stderr of
|
||||
# running process. defaults to false.
|
||||
#
|
||||
# Returns: PID on success.
|
||||
# Returns: PID
|
||||
#
|
||||
# Since: 2.5
|
||||
##
|
||||
@ -1354,7 +1346,7 @@
|
||||
# or even present in DNS or some other name service at all. It need
|
||||
# not even be unique on your local network or site, but usually it is.
|
||||
#
|
||||
# Returns: the host name of the machine on success
|
||||
# Returns: the host name of the machine
|
||||
#
|
||||
# Since: 2.10
|
||||
##
|
||||
@ -1604,8 +1596,6 @@
|
||||
#
|
||||
# @reset: ignore the existing content, set it with the given keys only
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 5.2
|
||||
##
|
||||
{ 'command': 'guest-ssh-add-authorized-keys',
|
||||
@ -1624,8 +1614,6 @@
|
||||
# @keys: the public keys to remove (in OpenSSH/sshd(8) authorized_keys
|
||||
# format)
|
||||
#
|
||||
# Returns: Nothing on success.
|
||||
#
|
||||
# Since: 5.2
|
||||
##
|
||||
{ 'command': 'guest-ssh-remove-authorized-keys',
|
||||
|
@ -543,7 +543,7 @@ class QAPISchemaParser:
|
||||
line = self.get_doc_indented(doc)
|
||||
no_more_args = True
|
||||
elif match := re.match(
|
||||
r'(Returns|Since|Notes?|Examples?|TODO): *',
|
||||
r'(Returns|Errors|Since|Notes?|Examples?|TODO): *',
|
||||
line):
|
||||
# tagged section
|
||||
doc.new_tagged_section(self.info, match.group(1))
|
||||
@ -639,6 +639,11 @@ class QAPIDoc:
|
||||
# dicts mapping parameter/feature names to their description
|
||||
self.args: Dict[str, QAPIDoc.ArgSection] = {}
|
||||
self.features: Dict[str, QAPIDoc.ArgSection] = {}
|
||||
# a command's "Returns" and "Errors" section
|
||||
self.returns: Optional[QAPIDoc.Section] = None
|
||||
self.errors: Optional[QAPIDoc.Section] = None
|
||||
# "Since" section
|
||||
self.since: Optional[QAPIDoc.Section] = None
|
||||
# sections other than .body, .args, .features
|
||||
self.sections: List[QAPIDoc.Section] = []
|
||||
|
||||
@ -660,14 +665,22 @@ class QAPIDoc:
|
||||
self.all_sections.append(section)
|
||||
|
||||
def new_tagged_section(self, info: QAPISourceInfo, tag: str) -> None:
|
||||
if tag in ('Returns', 'Since'):
|
||||
for section in self.all_sections:
|
||||
if isinstance(section, self.ArgSection):
|
||||
continue
|
||||
if section.tag == tag:
|
||||
raise QAPISemError(
|
||||
info, "duplicated '%s' section" % tag)
|
||||
section = self.Section(info, tag)
|
||||
if tag == 'Returns':
|
||||
if self.returns:
|
||||
raise QAPISemError(
|
||||
info, "duplicated '%s' section" % tag)
|
||||
self.returns = section
|
||||
elif tag == 'Errors':
|
||||
if self.errors:
|
||||
raise QAPISemError(
|
||||
info, "duplicated '%s' section" % tag)
|
||||
self.errors = section
|
||||
elif tag == 'Since':
|
||||
if self.since:
|
||||
raise QAPISemError(
|
||||
info, "duplicated '%s' section" % tag)
|
||||
self.since = section
|
||||
self.sections.append(section)
|
||||
self.all_sections.append(section)
|
||||
|
||||
@ -708,13 +721,20 @@ class QAPIDoc:
|
||||
self.features[feature.name].connect(feature)
|
||||
|
||||
def check_expr(self, expr: QAPIExpression) -> None:
|
||||
if 'command' not in expr:
|
||||
sec = next((sec for sec in self.sections
|
||||
if sec.tag == 'Returns'),
|
||||
None)
|
||||
if sec:
|
||||
raise QAPISemError(sec.info,
|
||||
"'Returns:' is only valid for commands")
|
||||
if 'command' in expr:
|
||||
if self.returns and 'returns' not in expr:
|
||||
raise QAPISemError(
|
||||
self.returns.info,
|
||||
"'Returns' section, but command doesn't return anything")
|
||||
else:
|
||||
if self.returns:
|
||||
raise QAPISemError(
|
||||
self.returns.info,
|
||||
"'Returns' section is only valid for commands")
|
||||
if self.errors:
|
||||
raise QAPISemError(
|
||||
self.returns.info,
|
||||
"'Errors' section is only valid for commands")
|
||||
|
||||
def check(self) -> None:
|
||||
|
||||
|
@ -159,6 +159,8 @@
|
||||
#
|
||||
# Returns: @Object
|
||||
#
|
||||
# Errors: some
|
||||
#
|
||||
# TODO: frobnicate
|
||||
#
|
||||
# Notes:
|
||||
|
@ -173,6 +173,8 @@ another feature
|
||||
@arg3 is undocumented
|
||||
section=Returns
|
||||
@Object
|
||||
section=Errors
|
||||
some
|
||||
section=TODO
|
||||
frobnicate
|
||||
section=Notes
|
||||
|
@ -206,6 +206,12 @@ Returns
|
||||
"Object"
|
||||
|
||||
|
||||
Errors
|
||||
~~~~~~
|
||||
|
||||
some
|
||||
|
||||
|
||||
Notes
|
||||
~~~~~
|
||||
|
||||
|
@ -1 +1 @@
|
||||
doc-invalid-return.json:6: 'Returns:' is only valid for commands
|
||||
doc-invalid-return.json:6: 'Returns' section is only valid for commands
|
||||
|
1
tests/qapi-schema/doc-invalid-return2.err
Normal file
1
tests/qapi-schema/doc-invalid-return2.err
Normal file
@ -0,0 +1 @@
|
||||
doc-invalid-return2.json:5: 'Returns' section, but command doesn't return anything
|
7
tests/qapi-schema/doc-invalid-return2.json
Normal file
7
tests/qapi-schema/doc-invalid-return2.json
Normal file
@ -0,0 +1,7 @@
|
||||
# Command doesn't return anything
|
||||
|
||||
##
|
||||
# @foo:
|
||||
# Returns: blah
|
||||
##
|
||||
{ 'command': 'foo' }
|
0
tests/qapi-schema/doc-invalid-return2.out
Normal file
0
tests/qapi-schema/doc-invalid-return2.out
Normal file
@ -79,6 +79,7 @@ schemas = [
|
||||
'doc-invalid-end.json',
|
||||
'doc-invalid-end2.json',
|
||||
'doc-invalid-return.json',
|
||||
'doc-invalid-return2.json',
|
||||
'doc-invalid-section.json',
|
||||
'doc-invalid-start.json',
|
||||
'doc-missing-colon.json',
|
||||
|
Loading…
Reference in New Issue
Block a user