qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed)
@ 2016-09-25 18:18 Marc-André Lureau
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script Marc-André Lureau
                   ` (11 more replies)
  0 siblings, 12 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Hi,

Add a qapi2texi script to generate the documentation from the qapi
schemas. Build various new documentation targets for it: pdf, man,
txt. The 7th patch in this series is a squashed version of the
documentation move from qmp-commands.txt to the schemas. The whole
version (not sent on the ML to avoid spamming) is in the following git
branch: https://github.com/elmarco/qemu/commits/qapi-doc

v1->v2:
- change licence to be lgpl2+
- fix some comments & commit message
- add more code comments
- improve the doc parsing to treat only "Since" as a special case not
  requiring ":" (common notation in the doc)
- include some early schema doc fixes (to fix generated doc)
- include the squashed version of the doc move
- include the man page and installation build changes

Marc-André Lureau (11):
  qapi: add qapi2texi script
  qapi: fix schema symbol sections
  qapi: fix missing symbol @prefix
  qapi: fix @ACPI sections
  docs: add qapi texi template
  build-sys: add qapi doc generation targets
  (SQUASHED) qmp-commands docs move to schema
  qapi: add some sections in docs and fix
  qga: fix guest-get-memory-block-info doc
  texi2pod: learn quotation, deftp and deftypefn
  build-sys: make and install the generated schema docs

 Makefile                        |   47 +-
 scripts/qapi.py                 |  100 +-
 scripts/qapi2texi.py            |  314 ++++
 scripts/texi2pod.pl             |   44 +-
 docs/qapi-code-gen.txt          |   44 +-
 docs/qemu-ga-qapi.template.texi |   58 +
 docs/qemu-qapi.template.texi    |  148 ++
 docs/qmp-commands.txt           | 3802 ---------------------------------------
 docs/qmp-events.txt             |  719 --------
 docs/qmp-intro.txt              |   87 -
 qapi-schema.json                | 1291 ++++++++++++-
 qapi/block-core.json            |  675 ++++++-
 qapi/block.json                 |   60 +-
 qapi/common.json                |   43 +-
 qapi/crypto.json                |   40 +-
 qapi/event.json                 |  245 +++
 qapi/rocker.json                |   60 +-
 qapi/trace.json                 |   16 +
 qga/qapi-schema.json            |    4 +-
 19 files changed, 3089 insertions(+), 4708 deletions(-)
 create mode 100755 scripts/qapi2texi.py
 create mode 100644 docs/qemu-ga-qapi.template.texi
 create mode 100644 docs/qemu-qapi.template.texi
 delete mode 100644 docs/qmp-intro.txt

-- 
2.10.0

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-28 16:44   ` Markus Armbruster
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 02/11] qapi: fix schema symbol sections Marc-André Lureau
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

As the name suggests, the qapi2texi script converts JSON QAPI
description into a standalone texi file suitable for different target
formats.

It parses the following kind of blocks with some little variations:

  ##
  # = Section
  # == Subsection
  #
  # Some text foo with *emphasis*
  # 1. with a list
  # 2. like that
  #
  # And some code:
  # | $ echo foo
  # | <- do this
  # | -> get that
  #
  ##

  ##
  # @symbol
  #
  # Symbol body ditto ergo sum. Foo bar
  # baz ding.
  #
  # @arg: foo
  # @arg: #optional foo
  #
  # Returns: returns bla bla
  #
  #          Or bla blah
  #
  # Since: version
  # Notes: notes, comments can have
  #        - itemized list
  #        - like this
  #
  #        and continue...
  #
  # Example:
  #
  # <- { "execute": "quit" }
  # -> { "return": {} }
  #
  ##

Thanks to the json declaration, it's able to give extra information
about the type of arguments and return value expected.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py        | 100 +++++++++++++++-
 scripts/qapi2texi.py   | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
 docs/qapi-code-gen.txt |  44 +++++--
 3 files changed, 446 insertions(+), 12 deletions(-)
 create mode 100755 scripts/qapi2texi.py

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 21bc32f..4efc7e7 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -122,6 +122,79 @@ class QAPIExprError(Exception):
             "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
 
 
+class QAPIDoc:
+    def __init__(self, comment):
+        self.symbol = None
+        self.comment = "" # the main symbol comment
+        self.args = OrderedDict()
+        # meta is for Since:, Notes:, Examples:, Returns:...
+        self.meta = OrderedDict()
+        # the current section to populate, array of [dict, key, comment...]
+        self.section = None
+
+        for line in comment.split('\n'):
+            # remove multiple spaces
+            sline = ' '.join(line.split())
+            # take the first word out
+            split = sline.split(' ', 1)
+            key = split[0]
+
+            if key.startswith("@"):
+                key = key[1:].rstrip(':')
+                sline = split[1] if len(split) > 1 else ""
+                if self.symbol is None:
+                    # the first is the section symbol
+                    self.symbol = key
+                else:
+                    # else an arg
+                    self.start_section(self.args, key)
+            elif self.symbol and \
+                    key in ("Returns:",
+                            # special case for Since often used without:
+                            "Since:", "Since",
+                            # those are often singular or plural
+                            "Note:", "Notes:",
+                            "Example:", "Examples:"):
+                sline = split[1] if len(split) > 1 else ""
+                line = None
+                # new "meta" section
+                self.start_section(self.meta, key.rstrip(':'))
+
+            if self.section and self.section[1].startswith("Example"):
+                # example is verbatim
+                self.append_comment(line)
+            else:
+                self.append_comment(sline)
+
+        self.end_section()
+
+    def append_comment(self, line):
+        """Adds a comment to the current section, or the symbol comment"""
+        if line is None:
+            return
+        if self.section is not None:
+            if self.section[-1] == "" and line == "":
+                self.end_section()
+            else:
+                self.section.append(line)
+        elif self.comment == "":
+            self.comment = line
+        else:
+            self.comment += "\n" + line
+
+    def end_section(self):
+        if self.section is not None:
+            dic = self.section[0]
+            key = self.section[1]
+            doc = "\n".join(self.section[2:])
+            dic[key] = doc
+            self.section = None
+
+    def start_section(self, dic, key):
+        self.end_section()
+        self.section = [dic, key]  # .. remaining elems will be the doc
+
+
 class QAPISchemaParser(object):
 
     def __init__(self, fp, previously_included=[], incl_info=None):
@@ -137,11 +210,14 @@ class QAPISchemaParser(object):
         self.line = 1
         self.line_pos = 0
         self.exprs = []
+        self.comment = None
+        self.apidoc = incl_info['doc'] if incl_info else []
         self.accept()
 
         while self.tok is not None:
             expr_info = {'file': fname, 'line': self.line,
-                         'parent': self.incl_info}
+                         'parent': self.incl_info, 'doc': self.apidoc}
+            self.apidoc = []
             expr = self.get_expr(False)
             if isinstance(expr, dict) and "include" in expr:
                 if len(expr) != 1:
@@ -162,6 +238,8 @@ class QAPISchemaParser(object):
                     inf = inf['parent']
                 # skip multiple include of the same file
                 if incl_abs_fname in previously_included:
+                    expr_info['doc'].extend(self.apidoc)
+                    self.apidoc = expr_info['doc']
                     continue
                 try:
                     fobj = open(incl_abs_fname, 'r')
@@ -176,6 +254,12 @@ class QAPISchemaParser(object):
                              'info': expr_info}
                 self.exprs.append(expr_elem)
 
+    def append_doc(self):
+        if self.comment:
+            apidoc = QAPIDoc(self.comment)
+            self.apidoc.append(apidoc)
+            self.comment = None
+
     def accept(self):
         while True:
             self.tok = self.src[self.cursor]
@@ -184,8 +268,20 @@ class QAPISchemaParser(object):
             self.val = None
 
             if self.tok == '#':
-                self.cursor = self.src.find('\n', self.cursor)
+                end = self.src.find('\n', self.cursor)
+                line = self.src[self.cursor:end+1]
+                # start a comment section after ##
+                if line[0] == "#":
+                    if self.comment is None:
+                        self.comment = ""
+                # skip modeline
+                elif line.find("-*") == -1 and self.comment is not None:
+                    self.comment += line
+                if self.src[end] == "\n" and self.src[end+1] == "\n":
+                    self.append_doc()
+                self.cursor = end
             elif self.tok in "{}:,[]":
+                self.append_doc()
                 return
             elif self.tok == "'":
                 string = ''
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
new file mode 100755
index 0000000..2706b16
--- /dev/null
+++ b/scripts/qapi2texi.py
@@ -0,0 +1,314 @@
+#!/usr/bin/env python
+# QAPI texi generator
+#
+# This work is licensed under the terms of the GNU LGPL, version 2+.
+# See the COPYING file in the top-level directory.
+"""This script produces the documentation of a qapi schema in texinfo format"""
+import re
+import sys
+
+from qapi import QAPISchemaParser, QAPISchemaError, check_exprs, QAPIExprError
+
+COMMAND_FMT = """
+@deftypefn {type} {{{ret}}} {name} @
+{{{args}}}
+
+{body}
+
+@end deftypefn
+
+""".format
+
+ENUM_FMT = """
+@deftp Enum {name}
+
+{body}
+
+@end deftp
+
+""".format
+
+STRUCT_FMT = """
+@deftp {type} {name} @
+{{{attrs}}}
+
+{body}
+
+@end deftp
+
+""".format
+
+EXAMPLE_FMT = """@example
+{code}
+@end example
+""".format
+
+
+def subst_strong(doc):
+    """Replaces *foo* by @strong{foo}"""
+    return re.sub(r'\*(\w+)\*', r'@emph{\1}', doc)
+
+
+def subst_emph(doc):
+    """Replaces _foo_ by @emph{foo}"""
+    return re.sub(r'\s_(\w+)_\s', r' @emph{\1} ', doc)
+
+
+def subst_vars(doc):
+    """Replaces @var by @var{var}"""
+    return re.sub(r'@(\w+)', r'@var{\1}', doc)
+
+
+def subst_braces(doc):
+    """Replaces {} with @{ @}"""
+    return doc.replace("{", "@{").replace("}", "@}")
+
+
+def texi_example(doc):
+    """Format @example"""
+    doc = subst_braces(doc).strip('\n')
+    return EXAMPLE_FMT(code=doc)
+
+
+def texi_comment(doc):
+    """
+    Format a comment
+
+    Lines starting with:
+    - |: generates an @example
+    - =: generates @section
+    - ==: generates @subsection
+    - 1. or 1): generates an @enumerate @item
+    - o/*/-: generates an @itemize list
+    """
+    lines = []
+    doc = subst_braces(doc)
+    doc = subst_vars(doc)
+    doc = subst_emph(doc)
+    doc = subst_strong(doc)
+    inlist = ""
+    lastempty = False
+    for line in doc.split('\n'):
+        empty = line == ""
+
+        if line.startswith("| "):
+            line = EXAMPLE_FMT(code=line[1:])
+        elif line.startswith("= "):
+            line = "@section " + line[1:]
+        elif line.startswith("== "):
+            line = "@subsection " + line[2:]
+        elif re.match("^([0-9]*[.)]) ", line):
+            if not inlist:
+                lines.append("@enumerate")
+                inlist = "enumerate"
+            line = line[line.find(" ")+1:]
+            lines.append("@item")
+        elif re.match("^[o*-] ", line):
+            if not inlist:
+                lines.append("@itemize %s" % {'o': "@bullet",
+                                              '*': "@minus",
+                                              '-': ""}[line[0]])
+                inlist = "itemize"
+            lines.append("@item")
+            line = line[2:]
+        elif lastempty and inlist:
+            lines.append("@end %s\n" % inlist)
+            inlist = ""
+
+        lastempty = empty
+        lines.append(line)
+
+    if inlist:
+        lines.append("@end %s\n" % inlist)
+    return "\n".join(lines)
+
+
+def texi_args(expr):
+    """
+    Format the functions/structure/events.. arguments/members
+    """
+    data = expr["data"] if "data" in expr else {}
+    if isinstance(data, str):
+        args = data
+    else:
+        arg_list = []
+        for name, typ in data.iteritems():
+            # optional arg
+            if name.startswith("*"):
+                name = name[1:]
+                arg_list.append("['%s': @var{%s}]" % (name, typ))
+            # regular arg
+            else:
+                arg_list.append("'%s': @var{%s}" % (name, typ))
+        args = ", ".join(arg_list)
+    return args
+
+
+def texi_body(doc, arg="@var"):
+    """
+    Format the body of a symbol documentation:
+    - a table of arguments
+    - followed by "Returns/Notes/Since/Example" sections
+    """
+    body = "@table %s\n" % arg
+    for arg, desc in doc.args.iteritems():
+        if desc.startswith("#optional"):
+            desc = desc[10:]
+            arg += "*"
+        elif desc.endswith("#optional"):
+            desc = desc[:-10]
+            arg += "*"
+        body += "@item %s\n%s\n" % (arg, texi_comment(desc))
+    body += "@end table\n"
+    body += texi_comment(doc.comment)
+
+    for k in ("Returns", "Note", "Notes", "Since", "Example", "Examples"):
+        if k not in doc.meta:
+            continue
+        func = texi_comment
+        if k.startswith("Example"):
+            func = texi_example
+
+        body += "\n@quotation %s\n%s\n@end quotation" % \
+                (k, func(doc.meta[k]))
+    return body
+
+
+def texi_alternate(expr, doc):
+    """
+    Format an alternate to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return STRUCT_FMT(type="Alternate",
+                      name=doc.symbol,
+                      attrs="[ " + args + " ]",
+                      body=body)
+
+
+def texi_union(expr, doc):
+    """
+    Format an union to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return STRUCT_FMT(type="Union",
+                      name=doc.symbol,
+                      attrs="[ " + args + " ]",
+                      body=body)
+
+
+def texi_enum(_, doc):
+    """
+    Format an enum to texi
+    """
+    body = texi_body(doc, "@samp")
+    return ENUM_FMT(name=doc.symbol,
+                    body=body)
+
+
+def texi_struct(expr, doc):
+    """
+    Format a struct to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return STRUCT_FMT(type="Struct",
+                      name=doc.symbol,
+                      attrs="@{ " + args + " @}",
+                      body=body)
+
+
+def texi_command(expr, doc):
+    """
+    Format a command to texi
+    """
+    args = texi_args(expr)
+    ret = expr["returns"] if "returns" in expr else ""
+    body = texi_body(doc)
+    return COMMAND_FMT(type="Command",
+                       name=doc.symbol,
+                       ret=ret,
+                       args="(" + args + ")",
+                       body=body)
+
+
+def texi_event(expr, doc):
+    """
+    Format an event to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return COMMAND_FMT(type="Event",
+                       name=doc.symbol,
+                       ret="",
+                       args="(" + args + ")",
+                       body=body)
+
+
+def texi(exprs):
+    """
+    Convert QAPI schema expressions to texi documentation
+    """
+    res = []
+    for qapi in exprs:
+        try:
+            docs = qapi['info']['doc']
+            expr = qapi['expr']
+            expr_doc = docs[-1]
+            body = docs[0:-1]
+
+            (kind, _) = expr.items()[0]
+
+            for doc in body:
+                res.append(texi_body(doc))
+
+            fmt = {"command": texi_command,
+                   "struct": texi_struct,
+                   "enum": texi_enum,
+                   "union": texi_union,
+                   "alternate": texi_alternate,
+                   "event": texi_event}
+            try:
+                fmt = fmt[kind]
+            except KeyError:
+                raise ValueError("Unknown expression kind '%s'" % kind)
+            res.append(fmt(expr, expr_doc))
+        except:
+            print >>sys.stderr, "error at @%s" % qapi
+            raise
+
+    return '\n'.join(res)
+
+
+def parse_schema(fname):
+    """
+    Parse the given schema file and return the exprs
+    """
+    try:
+        schema = QAPISchemaParser(open(fname, "r"))
+        check_exprs(schema.exprs)
+        return schema.exprs
+    except (QAPISchemaError, QAPIExprError), err:
+        print >>sys.stderr, err
+        exit(1)
+
+
+def main(argv):
+    """
+    Takes argv arguments, prints result to stdout
+    """
+    if len(argv) != 4:
+        print >>sys.stderr, "%s: need exactly 3 arguments: " \
+            "TEMPLATE VERSION SCHEMA" % argv[0]
+        sys.exit(1)
+
+    exprs = parse_schema(argv[3])
+
+    templ = open(argv[1])
+    qapi = texi(exprs)
+    print templ.read().format(version=argv[2], qapi=qapi)
+
+
+if __name__ == "__main__":
+    main(sys.argv)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 5d4c2cd..e51ae4c 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no place where a QAPI
 schema requires the use of JSON numbers or null.
 
 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 members 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
+newline is ignored.  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 members 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:
 
     ##
@@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
     #           (Since 2.0)
     #
     # Since: 0.14.0
+    #
+    # Notes: You can also make a list:
+    #        - with items
+    #        - like this
+    #
+    # Example:
+    #
+    # <- { "execute": ... }
+    # -> { "return": ... }
+    #
     ##
     { 'struct': 'BlockStats',
       'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
                '*parent': 'BlockStats',
                '*backing': 'BlockStats'} }
 
+It's also possible to create documentation sections, such as:
+
+    ##
+    # = Section
+    # == Subsection
+    #
+    # Some text foo with *emphasis*
+    # 1. with a list
+    # 2. like that
+    #
+    # And some code:
+    # | $ echo foo
+    # | <- do this
+    # | -> get that
+    #
+    ##
+
 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
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 02/11] qapi: fix schema symbol sections
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-26 13:30   ` Markus Armbruster
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 03/11] qapi: fix missing symbol @prefix Marc-André Lureau
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

According to documentation, there needs to be '##' to start a symbol
section, that's also what the documentation parser expects.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     | 9 +++++++--
 qapi/block-core.json | 1 +
 qga/qapi-schema.json | 3 +++
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index e507061..f07ffd7 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -65,6 +65,7 @@
 { 'enum': 'LostTickPolicy',
   'data': ['discard', 'delay', 'merge', 'slew' ] }
 
+##
 # @add_client
 #
 # Allow client connections for VNC, Spice and socket based
@@ -439,6 +440,7 @@
            'cache-miss': 'int', 'cache-miss-rate': 'number',
            'overflow': 'int' } }
 
+##
 # @MigrationStatus:
 #
 # An enumeration of migration status.
@@ -617,6 +619,7 @@
 ##
 { 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus']}
 
+##
 # @MigrationParameter
 #
 # Migration parameters enumeration
@@ -665,7 +668,7 @@
            'cpu-throttle-initial', 'cpu-throttle-increment',
            'tls-creds', 'tls-hostname'] }
 
-#
+##
 # @migrate-set-parameters
 #
 # Set the following migration parameters
@@ -710,7 +713,7 @@
             '*tls-creds': 'str',
             '*tls-hostname': 'str'} }
 
-#
+##
 # @MigrationParameters
 #
 # @compress-level: compression level
@@ -2172,6 +2175,7 @@
 ##
 { 'command': 'migrate-incoming', 'data': {'uri': 'str' } }
 
+##
 # @xen-save-devices-state:
 #
 # Save the state of all devices to file. The RAM and the block devices
@@ -3359,6 +3363,7 @@
             'modelb': 'CpuModelInfo' },
   'returns': 'CpuModelBaselineInfo' }
 
+##
 # @AddfdInfo:
 #
 # Information about a file descriptor that was added to an fd set.
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 92193ab..cf8e980 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2665,6 +2665,7 @@
             'offset': 'int',
             'speed' : 'int' } }
 
+##
 # @PreallocMode
 #
 # Preallocation mode of QEMU image file
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index c21f308..09c9728 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -837,6 +837,7 @@
 { 'command': 'guest-set-user-password',
   'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' } }
 
+##
 # @GuestMemoryBlock:
 #
 # @phys-index: Arbitrary guest-specific unique identifier of the MEMORY BLOCK.
@@ -936,6 +937,7 @@
   'data':    {'mem-blks': ['GuestMemoryBlock'] },
   'returns': ['GuestMemoryBlockResponse'] }
 
+##
 # @GuestMemoryBlockInfo:
 #
 # @size: the size (in bytes) of the guest memory blocks,
@@ -960,6 +962,7 @@
 { 'command': 'guest-get-memory-block-info',
   'returns': 'GuestMemoryBlockInfo' }
 
+##
 # @GuestExecStatus:
 #
 # @exited: true if process has already terminated.
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 03/11] qapi: fix missing symbol @prefix
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script Marc-André Lureau
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 02/11] qapi: fix schema symbol sections Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-26 13:37   ` Markus Armbruster
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 04/11] qapi: fix @ACPI sections Marc-André Lureau
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     |  4 ++--
 qapi/block-core.json |  4 ++--
 qapi/crypto.json     | 36 ++++++++++++++++++------------------
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index f07ffd7..3091993 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4526,7 +4526,7 @@
 { 'include': 'qapi/rocker.json' }
 
 ##
-# ReplayMode:
+# @ReplayMode:
 #
 # Mode of the replay subsystem.
 #
@@ -4594,7 +4594,7 @@
 { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
 
 ##
-# CpuInstanceProperties
+# @CpuInstanceProperties
 #
 # List of properties to be used for hotplugging a CPU instance,
 # it should be passed by management with device_add command when
diff --git a/qapi/block-core.json b/qapi/block-core.json
index cf8e980..73f4180 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1149,7 +1149,7 @@
   'data': 'DriveMirror' }
 
 ##
-# DriveMirror
+# @DriveMirror
 #
 # A set of parameters describing drive mirror setup.
 #
@@ -1373,7 +1373,7 @@
   'data': 'BlockIOThrottle' }
 
 ##
-# BlockIOThrottle
+# @BlockIOThrottle
 #
 # A set of parameters describing block throttling.
 #
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 6933b13..4ac3034 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -3,7 +3,7 @@
 # QAPI crypto definitions
 
 ##
-# QCryptoTLSCredsEndpoint:
+# @QCryptoTLSCredsEndpoint:
 #
 # The type of network endpoint that will be using the credentials.
 # Most types of credential require different setup / structures
@@ -22,7 +22,7 @@
 
 
 ##
-# QCryptoSecretFormat:
+# @QCryptoSecretFormat:
 #
 # The data format that the secret is provided in
 #
@@ -36,7 +36,7 @@
 
 
 ##
-# QCryptoHashAlgorithm:
+# @QCryptoHashAlgorithm:
 #
 # The supported algorithms for computing content digests
 #
@@ -55,7 +55,7 @@
 
 
 ##
-# QCryptoCipherAlgorithm:
+# @QCryptoCipherAlgorithm:
 #
 # The supported algorithms for content encryption ciphers
 #
@@ -82,7 +82,7 @@
 
 
 ##
-# QCryptoCipherMode:
+# @QCryptoCipherMode:
 #
 # The supported modes for content encryption ciphers
 #
@@ -97,7 +97,7 @@
 
 
 ##
-# QCryptoIVGenAlgorithm:
+# @QCryptoIVGenAlgorithm:
 #
 # The supported algorithms for generating initialization
 # vectors for full disk encryption. The 'plain' generator
@@ -115,7 +115,7 @@
   'data': ['plain', 'plain64', 'essiv']}
 
 ##
-# QCryptoBlockFormat:
+# @QCryptoBlockFormat:
 #
 # The supported full disk encryption formats
 #
@@ -130,7 +130,7 @@
   'data': ['qcow', 'luks']}
 
 ##
-# QCryptoBlockOptionsBase:
+# @QCryptoBlockOptionsBase:
 #
 # The common options that apply to all full disk
 # encryption formats
@@ -143,7 +143,7 @@
   'data': { 'format': 'QCryptoBlockFormat' }}
 
 ##
-# QCryptoBlockOptionsQCow:
+# @QCryptoBlockOptionsQCow:
 #
 # The options that apply to QCow/QCow2 AES-CBC encryption format
 #
@@ -157,7 +157,7 @@
   'data': { '*key-secret': 'str' }}
 
 ##
-# QCryptoBlockOptionsLUKS:
+# @QCryptoBlockOptionsLUKS:
 #
 # The options that apply to LUKS encryption format
 #
@@ -171,7 +171,7 @@
 
 
 ##
-# QCryptoBlockCreateOptionsLUKS:
+# @QCryptoBlockCreateOptionsLUKS:
 #
 # The options that apply to LUKS encryption format initialization
 #
@@ -201,7 +201,7 @@
 
 
 ##
-# QCryptoBlockOpenOptions:
+# @QCryptoBlockOpenOptions:
 #
 # The options that are available for all encryption formats
 # when opening an existing volume
@@ -216,7 +216,7 @@
 
 
 ##
-# QCryptoBlockCreateOptions:
+# @QCryptoBlockCreateOptions:
 #
 # The options that are available for all encryption formats
 # when initializing a new volume
@@ -231,7 +231,7 @@
 
 
 ##
-# QCryptoBlockInfoBase:
+# @QCryptoBlockInfoBase:
 #
 # The common information that applies to all full disk
 # encryption formats
@@ -245,7 +245,7 @@
 
 
 ##
-# QCryptoBlockInfoLUKSSlot:
+# @QCryptoBlockInfoLUKSSlot:
 #
 # Information about the LUKS block encryption key
 # slot options
@@ -265,7 +265,7 @@
 
 
 ##
-# QCryptoBlockInfoLUKS:
+# @QCryptoBlockInfoLUKS:
 #
 # Information about the LUKS block encryption options
 #
@@ -293,7 +293,7 @@
            'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
 
 ##
-# QCryptoBlockInfoQCow:
+# @QCryptoBlockInfoQCow:
 #
 # Information about the QCow block encryption options
 #
@@ -304,7 +304,7 @@
 
 
 ##
-# QCryptoBlockInfo:
+# @QCryptoBlockInfo:
 #
 # Information about the block encryption options
 #
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 04/11] qapi: fix @ACPI sections
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (2 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 03/11] qapi: fix missing symbol @prefix Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-26 13:38   ` Markus Armbruster
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template Marc-André Lureau
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

This helps the doc parser.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 3091993..3ac8637 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4414,14 +4414,16 @@
 ##
 { 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
 
-## @ACPISlotType
+##
+# @ACPISlotType
 #
 # @DIMM: memory slot
 # @CPU: logical CPU slot (since 2.7)
 #
 { 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
 
-## @ACPIOSTInfo
+##
+# @ACPIOSTInfo
 #
 # OSPM Status Indication for a device
 # For description of possible values of @source and @status fields
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (3 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 04/11] qapi: fix @ACPI sections Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-27 14:55   ` Markus Armbruster
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 06/11] build-sys: add qapi doc generation targets Marc-André Lureau
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

The qapi2texi scripts uses a template for the texi file. Since we are
going to generate the documentation in multiple formats, move qmp-intro
to qemu-qapi template. (it would be nice to write something similar for
qemu-ga, but this is left for a future patch)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 docs/qemu-ga-qapi.template.texi |  58 ++++++++++++++++
 docs/qemu-qapi.template.texi    | 148 ++++++++++++++++++++++++++++++++++++++++
 docs/qmp-intro.txt              |  87 -----------------------
 3 files changed, 206 insertions(+), 87 deletions(-)
 create mode 100644 docs/qemu-ga-qapi.template.texi
 create mode 100644 docs/qemu-qapi.template.texi
 delete mode 100644 docs/qmp-intro.txt

diff --git a/docs/qemu-ga-qapi.template.texi b/docs/qemu-ga-qapi.template.texi
new file mode 100644
index 0000000..3ddbf56
--- /dev/null
+++ b/docs/qemu-ga-qapi.template.texi
@@ -0,0 +1,58 @@
+\input texinfo
+@setfilename qemu-ga-qapi
+@documentlanguage en
+@exampleindent 0
+@paragraphindent 0
+
+@settitle QEMU-GA QAPI Reference Manual
+
+@ifinfo
+@direntry
+* QEMU-GA-QAPI: (qemu-doc).    QEMU-GA QAPI Reference Manual
+@end direntry
+@end ifinfo
+
+@iftex
+@titlepage
+@sp 7
+@center @titlefont{{QEMU Guest Agent {version}}}
+@sp 1
+@center @titlefont{{QAPI Reference Manual}}
+@sp 3
+@end titlepage
+@end iftex
+
+@ifnottex
+@node Top
+@top
+
+This is the QEMU Guest Agent QAPI reference for QEMU {version}.
+
+@menu
+* API Reference::
+* Commands and Events Index::
+* Data Types Index::
+@end menu
+
+@end ifnottex
+
+@contents
+
+@node API Reference
+@chapter API Reference
+
+@c man begin DESCRIPTION
+{qapi}
+@c man end
+
+@c man begin SEEALSO
+The HTML documentation of QEMU for more precise information.
+@c man end
+
+@node Commands and Events Index
+@unnumbered Commands and Events Index
+@printindex fn
+@node Data Types Index
+@unnumbered Data Types Index
+@printindex tp
+@bye
diff --git a/docs/qemu-qapi.template.texi b/docs/qemu-qapi.template.texi
new file mode 100644
index 0000000..102c8d9
--- /dev/null
+++ b/docs/qemu-qapi.template.texi
@@ -0,0 +1,148 @@
+\input texinfo
+@setfilename qemu-qapi
+@documentlanguage en
+@exampleindent 0
+@paragraphindent 0
+
+@settitle QEMU QAPI Reference Manual
+
+@ifinfo
+@direntry
+* QEMU: (qemu-doc).    QEMU QAPI Reference Manual
+@end direntry
+@end ifinfo
+
+@iftex
+@titlepage
+@sp 7
+@center @titlefont{{QEMU Emulator {version}}}
+@sp 1
+@center @titlefont{{QAPI Reference Manual}}
+@sp 3
+@end titlepage
+@end iftex
+
+@ifnottex
+@node Top
+@top
+
+This is the QMP QAPI reference for QEMU {version}.
+
+@menu
+* Introduction::
+* API Reference::
+* Commands and Events Index::
+* Data Types Index::
+@end menu
+
+@end ifnottex
+
+@contents
+
+@node Introduction
+@chapter Introduction
+
+The QEMU Machine Protocol (@acronym{{QMP}}) allows applications to
+operate a QEMU instance.
+
+QMP is @uref{{http://www.json.org, JSON}} based and features the
+following:
+
+@itemize @minus
+@item
+Lightweight, text-based, easy to parse data format
+@item
+Asynchronous messages support (ie. events)
+@item
+Capabilities Negotiation
+@end itemize
+
+For detailed information on QEMU Machine Protocol, the specification
+is in @file{{qmp-spec.txt}}.
+
+@section Usage
+
+You can use the @option{{-qmp}} option to enable QMP. For example, the
+following makes QMP available on localhost port 4444:
+
+@example
+$ qemu [...] -qmp tcp:localhost:4444,server,nowait
+@end example
+
+However, for more flexibility and to make use of more options, the
+@option{{-mon}} command-line option should be used. For instance, the
+following example creates one HMP instance (human monitor) on stdio
+and one QMP instance on localhost port 4444:
+
+@example
+$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
+             -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
+             -mon chardev=mon1,mode=control,pretty=on
+@end example
+
+Please, refer to QEMU's manpage for more information.
+
+@section Simple testing
+
+To manually test QMP one can connect with telnet and issue commands by
+hand:
+
+@example
+$ telnet localhost 4444
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+@{{
+    "QMP": @{{
+        "version": @{{
+            "qemu": @{{
+                "micro": 50,
+                "minor": 6,
+                "major": 1
+            @}},
+            "package": ""
+        @}},
+        "capabilities": [
+        ]
+    @}}
+@}}
+
+@{{ "execute": "qmp_capabilities" @}}
+@{{
+    "return": @{{
+    @}}
+@}}
+
+@{{ "execute": "query-status" @}}
+@{{
+    "return": @{{
+        "status": "prelaunch",
+        "singlestep": false,
+        "running": false
+    @}}
+@}}
+@end example
+
+@section Wiki
+
+Please refer to the @uref{{http://wiki.qemu-project.org/QMP, QMP QEMU
+ wiki page}} for more details on QMP.
+
+@node API Reference
+@chapter API Reference
+
+@c man begin DESCRIPTION
+{qapi}
+@c man end
+
+@c man begin SEEALSO
+The HTML documentation of QEMU for more precise information.
+@c man end
+
+@node Commands and Events Index
+@unnumbered Commands and Events Index
+@printindex fn
+@node Data Types Index
+@unnumbered Data Types Index
+@printindex tp
+@bye
diff --git a/docs/qmp-intro.txt b/docs/qmp-intro.txt
deleted file mode 100644
index f6a3a03..0000000
--- a/docs/qmp-intro.txt
+++ /dev/null
@@ -1,87 +0,0 @@
-                          QEMU Machine Protocol
-                          =====================
-
-Introduction
-------------
-
-The QEMU Machine Protocol (QMP) allows applications to operate a
-QEMU instance.
-
-QMP is JSON[1] based and features the following:
-
-- Lightweight, text-based, easy to parse data format
-- Asynchronous messages support (ie. events)
-- Capabilities Negotiation
-
-For detailed information on QMP's usage, please, refer to the following files:
-
-o qmp-spec.txt      QEMU Machine Protocol current specification
-o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
-o qmp-events.txt    List of available asynchronous events
-
-[1] http://www.json.org
-
-Usage
------
-
-You can use the -qmp option to enable QMP. For example, the following
-makes QMP available on localhost port 4444:
-
-$ qemu [...] -qmp tcp:localhost:4444,server,nowait
-
-However, for more flexibility and to make use of more options, the -mon
-command-line option should be used. For instance, the following example
-creates one HMP instance (human monitor) on stdio and one QMP instance
-on localhost port 4444:
-
-$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
-             -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
-             -mon chardev=mon1,mode=control,pretty=on
-
-Please, refer to QEMU's manpage for more information.
-
-Simple Testing
---------------
-
-To manually test QMP one can connect with telnet and issue commands by hand:
-
-$ telnet localhost 4444
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-{
-    "QMP": {
-        "version": {
-            "qemu": {
-                "micro": 50, 
-                "minor": 6, 
-                "major": 1
-            }, 
-            "package": ""
-        }, 
-        "capabilities": [
-        ]
-    }
-}
-
-{ "execute": "qmp_capabilities" }
-{
-    "return": {
-    }
-}
-
-{ "execute": "query-status" }
-{
-    "return": {
-        "status": "prelaunch", 
-        "singlestep": false, 
-        "running": false
-    }
-}
-
-Please, refer to the qapi-schema.json file for a complete command reference.
-
-QMP wiki page
--------------
-
-http://wiki.qemu-project.org/QMP
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 06/11] build-sys: add qapi doc generation targets
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (4 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-27 16:16   ` Markus Armbruster
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 07/11] (SQUASHED) qmp-commands docs move to schema Marc-André Lureau
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Add qapi doc generation targets, qemu-qapi.texi, qemu-ga-qapi.texi
(implicit pdf works too) and qemu-qapi.txt. The generated
documentation isn't complete yet, so don't bother to build it by
default or install it yet.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 Makefile | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/Makefile b/Makefile
index f103616..6e00559 100644
--- a/Makefile
+++ b/Makefile
@@ -269,6 +269,7 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
 gen-out-type = $(subst .,-,$(suffix $@))
 
 qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
+qapi-py += $(SRC_PATH)/scripts/qapi2texi.py
 
 qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
 $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
@@ -558,9 +559,23 @@ qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
 qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
 
+qemu-qapi.txt: qemu-qapi.texi
+	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --plaintext $< -o $@,\
+	"  GEN   $@")
+
 qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
 
+qemu-qapi.texi: $(qapi-modules) $(qapi-py) \
+	$(SRC_PATH)/docs/qemu-qapi.template.texi
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py \
+	$(SRC_PATH)/docs/qemu-qapi.template.texi $(VERSION) $< > $@,"  GEN   $@")
+
+qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py) \
+	$(SRC_PATH)/docs/qemu-ga-qapi.template.texi
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py \
+	$(SRC_PATH)/docs/qemu-ga-qapi.template.texi $(VERSION) $< > $@,"  GEN   $@")
+
 qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
 	$(call quiet-command, \
 	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 07/11] (SQUASHED) qmp-commands docs move to schema
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (5 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 06/11] build-sys: add qapi doc generation targets Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 08/11] qapi: add some sections in docs and fix Marc-André Lureau
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

This is a squashed version of the following commits, available
individually to ease review:

qmp-commands: move 'add_client' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-name' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-kvm' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-status' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-uuid' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-chardev' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-chardev-backends' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'ringbuf-write' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'ringbuf-read' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-events' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-migrate' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate-set-capabilities' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-migrate-capabilities' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate-set-parameters' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-migrate-parameters' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'client_migrate_info' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate-start-postcopy' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-mice' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-cpus' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-iothreads' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-vnc' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-spice' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-balloon' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-pci' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'quit' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'stop' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'system_reset' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'system_powerdown' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'cpu-add' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'memsave' doc to schema

Notice that "cpu" argument is actually "cpu-index" in the json.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'pmemsave' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'cont' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'system_wakeup' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'inject-nmi' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'set_link' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'balloon' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'transaction' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'human-monitor-command' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate_cancel' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate_set_downtime' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate_set_speed' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-migrate-cache-size' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'set_password' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'expire_password' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'change' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate-incoming' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'xen-save-devices-state' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'xen-set-global-dirty-log' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'device_del' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'dump-guest-memory' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-dump-guest-memory-capability' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'dump-skeys' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'netdev_add' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'netdev_del' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'object-add' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'object-del' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'getfd' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'closefd' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'add-fd' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'remove-fd' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-fdsets' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'send-key' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'screendump' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'chardev-add' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'chardev-remove' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-tpm-models' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-tpm-types' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-tpm' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-command-line-options' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-rx-filter' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'input-send-event' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-memdev' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-memory-devices' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-acpi-ospm-status' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'rtc-reset-reinjection' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-block' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-blockstats' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block_passwd' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block_resize' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-snapshot-sync' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-snapshot' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'change-backing-file' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block-commit' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'drive-backup' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-backup' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-named-block-nodes' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'drive-mirror' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block-dirty-bitmap-add' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block-dirty-bitmap-remove' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block-dirty-bitmap-clear' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block_set_io_throttle' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block-stream' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-add' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'x-blockdev-del' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-open-tray' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-close-tray' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'x-blockdev-remove-medium' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'x-blockdev-insert-medium' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-change-medium' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'block-set-write-threshold' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-snapshot-internal-sync' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-snapshot-delete-internal-sync' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'eject' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-version' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: remove qemu. prefix from VersionTriple doc

qemu is the name of the field in VersionInfo.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-commands' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-rocker' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-rocker-ports' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-rocker-of-dpa-flows' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-rocker-of-dpa-groups' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'trace-event-get-state' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'trace-event-set-state' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-hotpluggable-cpus' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-gic-capabilities' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'x-blockdev-change' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'blockdev-mirror' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'query-dump' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'migrate-set-cache-size' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move 'xen-load-devices-state' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: remove query-qmp-schema from txt

It's better described in the schema already.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: remove qmp_capabilities from txt

It's better described in the schema already.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: remove cpu from txt

The cpu command is deprecated since commit 755f196898.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: remove device_add from txt

It's already fully described in the schema. Fix the schema to document
the command and not the argument (place doc before first arg).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-commands: move documentation bits to schema

Moving the remaining bits of documentation to the json
file (text improvements is not the objective of this patch)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'BLOCK_IMAGE_CORRUPTED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'BLOCK_IO_ERROR' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'BLOCK_JOB_COMPLETED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'BLOCK_JOB_CANCELLED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'BLOCK_JOB_ERROR' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'BLOCK_JOB_READY' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'DEVICE_TRAY_MOVED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'SHUTDOWN' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'POWERDOWN' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'RESET' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'STOP' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'RESUME' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'SUSPEND' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'SUSPEND_DISK' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'WAKEUP' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'RTC_CHANGE' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'WATCHDOG' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'DEVICE_DELETED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'NIC_RX_FILTER_CHANGED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'VNC_CONNECTED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'VNC_INITIALIZED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'VNC_DISCONNECTED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'SPICE_CONNECTED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'SPICE_INITIALIZED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'SPICE_DISCONNECTED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'SPICE_MIGRATE_COMPLETED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'MIGRATION' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'ACPI_DEVICE_OST' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'BALLOON_CHANGE' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'GUEST_PANICKED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'QUORUM_FAILURE' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'QUORUM_REPORT_BAD' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'VSERPORT_CHANGE' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'MEM_UNPLUG_ERROR' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'DUMP_COMPLETED' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

qmp-events: move 'MIGRATION_PASS' doc to schema

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 docs/qmp-commands.txt | 3802 -------------------------------------------------
 docs/qmp-events.txt   |  719 ----------
 qapi-schema.json      | 1269 ++++++++++++++++-
 qapi/block-core.json  |  665 ++++++++-
 qapi/block.json       |   55 +-
 qapi/common.json      |   38 +-
 qapi/event.json       |  240 ++++
 qapi/rocker.json      |   57 +-
 qapi/trace.json       |   14 +
 9 files changed, 2290 insertions(+), 4569 deletions(-)

diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt
index e0adceb..e69de29 100644
--- a/docs/qmp-commands.txt
+++ b/docs/qmp-commands.txt
@@ -1,3802 +0,0 @@
-                        QMP Supported Commands
-                        ----------------------
-
-This document describes all commands currently supported by QMP.
-
-Most of the time their usage is exactly the same as in the user Monitor, this
-means that any other document which also describe commands (the manpage,
-QEMU's manual, etc) can and should be consulted.
-
-QMP has two types of commands: regular and query commands. Regular commands
-usually change the Virtual Machine's state someway, while query commands just
-return information. The sections below are divided accordingly.
-
-It's important to observe that all communication examples are formatted in
-a reader-friendly way, so that they're easier to understand. However, in real
-protocol usage, they're emitted as a single line.
-
-Also, the following notation is used to denote data flow:
-
--> data issued by the Client
-<- Server data response
-
-Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed
-information on the Server command and response formats.
-
-NOTE: This document is temporary and will be replaced soon.
-
-1. Stability Considerations
-===========================
-
-The current QMP command set (described in this file) may be useful for a
-number of use cases, however it's limited and several commands have bad
-defined semantics, specially with regard to command completion.
-
-These problems are going to be solved incrementally in the next QEMU releases
-and we're going to establish a deprecation policy for badly defined commands.
-
-If you're planning to adopt QMP, please observe the following:
-
-    1. The deprecation policy will take effect and be documented soon, please
-       check the documentation of each used command as soon as a new release of
-       QEMU is available
-
-    2. DO NOT rely on anything which is not explicit documented
-
-    3. Errors, in special, are not documented. Applications should NOT check
-       for specific errors classes or data (it's strongly recommended to only
-       check for the "error" key)
-
-2. Regular Commands
-===================
-
-Server's responses in the examples below are always a success response, please
-refer to the QMP specification for more details on error responses.
-
-quit
-----
-
-Quit the emulator.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "quit" }
-<- { "return": {} }
-
-eject
------
-
-Eject a removable medium.
-
-Arguments:
-
-- "force": force ejection (json-bool, optional)
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-
-Example:
-
--> { "execute": "eject", "arguments": { "id": "ide0-1-0" } }
-<- { "return": {} }
-
-Note: The "force" argument defaults to false.
-
-change
-------
-
-Change a removable medium or VNC configuration.
-
-Arguments:
-
-- "device": device name (json-string)
-- "target": filename or item (json-string)
-- "arg": additional argument (json-string, optional)
-
-Examples:
-
-1. Change a removable medium
-
--> { "execute": "change",
-             "arguments": { "device": "ide1-cd0",
-                            "target": "/srv/images/Fedora-12-x86_64-DVD.iso" } }
-<- { "return": {} }
-
-2. Change VNC password
-
--> { "execute": "change",
-             "arguments": { "device": "vnc", "target": "password",
-                            "arg": "foobar1" } }
-<- { "return": {} }
-
-screendump
-----------
-
-Save screen into PPM image.
-
-Arguments:
-
-- "filename": file path (json-string)
-
-Example:
-
--> { "execute": "screendump", "arguments": { "filename": "/tmp/image" } }
-<- { "return": {} }
-
-stop
-----
-
-Stop the emulator.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "stop" }
-<- { "return": {} }
-
-cont
-----
-
-Resume emulation.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "cont" }
-<- { "return": {} }
-
-system_wakeup
--------------
-
-Wakeup guest from suspend.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "system_wakeup" }
-<- { "return": {} }
-
-system_reset
-------------
-
-Reset the system.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "system_reset" }
-<- { "return": {} }
-
-system_powerdown
-----------------
-
-Send system power down event.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "system_powerdown" }
-<- { "return": {} }
-
-device_add
-----------
-
-Add a device.
-
-Arguments:
-
-- "driver": the name of the new device's driver (json-string)
-- "bus": the device's parent bus (device tree path, json-string, optional)
-- "id": the device's ID, must be unique (json-string)
-- device properties
-
-Example:
-
--> { "execute": "device_add", "arguments": { "driver": "e1000", "id": "net1" } }
-<- { "return": {} }
-
-Notes:
-
-(1) For detailed information about this command, please refer to the
-    'docs/qdev-device-use.txt' file.
-
-(2) It's possible to list device properties by running QEMU with the
-    "-device DEVICE,\?" command-line argument, where DEVICE is the device's name
-
-device_del
-----------
-
-Remove a device.
-
-Arguments:
-
-- "id": the device's ID or QOM path (json-string)
-
-Example:
-
--> { "execute": "device_del", "arguments": { "id": "net1" } }
-<- { "return": {} }
-
-Example:
-
--> { "execute": "device_del", "arguments": { "id": "/machine/peripheral-anon/device[0]" } }
-<- { "return": {} }
-
-send-key
-----------
-
-Send keys to VM.
-
-Arguments:
-
-keys array:
-    - "key": key sequence (a json-array of key union values,
-             union can be number or qcode enum)
-
-- hold-time: time to delay key up events, milliseconds. Defaults to 100
-             (json-int, optional)
-
-Example:
-
--> { "execute": "send-key",
-     "arguments": { "keys": [ { "type": "qcode", "data": "ctrl" },
-                              { "type": "qcode", "data": "alt" },
-                              { "type": "qcode", "data": "delete" } ] } }
-<- { "return": {} }
-
-cpu
----
-
-Set the default CPU.
-
-Arguments:
-
-- "index": the CPU's index (json-int)
-
-Example:
-
--> { "execute": "cpu", "arguments": { "index": 0 } }
-<- { "return": {} }
-
-Note: CPUs' indexes are obtained with the 'query-cpus' command.
-
-cpu-add
--------
-
-Adds virtual cpu
-
-Arguments:
-
-- "id": cpu id (json-int)
-
-Example:
-
--> { "execute": "cpu-add", "arguments": { "id": 2 } }
-<- { "return": {} }
-
-memsave
--------
-
-Save to disk virtual memory dump starting at 'val' of size 'size'.
-
-Arguments:
-
-- "val": the starting address (json-int)
-- "size": the memory size, in bytes (json-int)
-- "filename": file path (json-string)
-- "cpu": virtual CPU index (json-int, optional)
-
-Example:
-
--> { "execute": "memsave",
-             "arguments": { "val": 10,
-                            "size": 100,
-                            "filename": "/tmp/virtual-mem-dump" } }
-<- { "return": {} }
-
-pmemsave
---------
-
-Save to disk physical memory dump starting at 'val' of size 'size'.
-
-Arguments:
-
-- "val": the starting address (json-int)
-- "size": the memory size, in bytes (json-int)
-- "filename": file path (json-string)
-
-Example:
-
--> { "execute": "pmemsave",
-             "arguments": { "val": 10,
-                            "size": 100,
-                            "filename": "/tmp/physical-mem-dump" } }
-<- { "return": {} }
-
-inject-nmi
-----------
-
-Inject an NMI on the default CPU (x86/s390) or all CPUs (ppc64).
-
-Arguments: None.
-
-Example:
-
--> { "execute": "inject-nmi" }
-<- { "return": {} }
-
-Note: inject-nmi fails when the guest doesn't support injecting.
-
-ringbuf-write
--------------
-
-Write to a ring buffer character device.
-
-Arguments:
-
-- "device": ring buffer character device name (json-string)
-- "data": data to write (json-string)
-- "format": data format (json-string, optional)
-          - Possible values: "utf8" (default), "base64"
-
-Example:
-
--> { "execute": "ringbuf-write",
-                "arguments": { "device": "foo",
-                               "data": "abcdefgh",
-                               "format": "utf8" } }
-<- { "return": {} }
-
-ringbuf-read
--------------
-
-Read from a ring buffer character device.
-
-Arguments:
-
-- "device": ring buffer character device name (json-string)
-- "size": how many bytes to read at most (json-int)
-          - Number of data bytes, not number of characters in encoded data
-- "format": data format (json-string, optional)
-          - Possible values: "utf8" (default), "base64"
-          - Naturally, format "utf8" works only when the ring buffer
-            contains valid UTF-8 text.  Invalid UTF-8 sequences get
-            replaced.  Bug: replacement doesn't work.  Bug: can screw
-            up on encountering NUL characters, after the ring buffer
-            lost data, and when reading stops because the size limit
-            is reached.
-
-Example:
-
--> { "execute": "ringbuf-read",
-                "arguments": { "device": "foo",
-                               "size": 1000,
-                               "format": "utf8" } }
-<- {"return": "abcdefgh"}
-
-xen-save-devices-state
--------
-
-Save the state of all devices to file. The RAM and the block devices
-of the VM are not saved by this command.
-
-Arguments:
-
-- "filename": the file to save the state of the devices to as binary
-data. See xen-save-devices-state.txt for a description of the binary
-format.
-
-Example:
-
--> { "execute": "xen-save-devices-state",
-     "arguments": { "filename": "/tmp/save" } }
-<- { "return": {} }
-
-xen-load-devices-state
-----------------------
-
-Load the state of all devices from file. The RAM and the block devices
-of the VM are not loaded by this command.
-
-Arguments:
-
-- "filename": the file to load the state of the devices from as binary
-data. See xen-save-devices-state.txt for a description of the binary
-format.
-
-Example:
-
--> { "execute": "xen-load-devices-state",
-     "arguments": { "filename": "/tmp/resume" } }
-<- { "return": {} }
-
-xen-set-global-dirty-log
--------
-
-Enable or disable the global dirty log mode.
-
-Arguments:
-
-- "enable": Enable it or disable it.
-
-Example:
-
--> { "execute": "xen-set-global-dirty-log",
-     "arguments": { "enable": true } }
-<- { "return": {} }
-
-migrate
--------
-
-Migrate to URI.
-
-Arguments:
-
-- "blk": block migration, full disk copy (json-bool, optional)
-- "inc": incremental disk copy (json-bool, optional)
-- "uri": Destination URI (json-string)
-
-Example:
-
--> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } }
-<- { "return": {} }
-
-Notes:
-
-(1) The 'query-migrate' command should be used to check migration's progress
-    and final result (this information is provided by the 'status' member)
-(2) All boolean arguments default to false
-(3) The user Monitor's "detach" argument is invalid in QMP and should not
-    be used
-
-migrate_cancel
---------------
-
-Cancel the current migration.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "migrate_cancel" }
-<- { "return": {} }
-
-migrate-incoming
-----------------
-
-Continue an incoming migration
-
-Arguments:
-
-- "uri": Source/listening URI (json-string)
-
-Example:
-
--> { "execute": "migrate-incoming", "arguments": { "uri": "tcp::4446" } }
-<- { "return": {} }
-
-Notes:
-
-(1) QEMU must be started with -incoming defer to allow migrate-incoming to
-    be used
-(2) The uri format is the same as for -incoming
-
-migrate-set-cache-size
-----------------------
-
-Set cache size to be used by XBZRLE migration, the cache size will be rounded
-down to the nearest power of 2
-
-Arguments:
-
-- "value": cache size in bytes (json-int)
-
-Example:
-
--> { "execute": "migrate-set-cache-size", "arguments": { "value": 536870912 } }
-<- { "return": {} }
-
-migrate-start-postcopy
-----------------------
-
-Switch an in-progress migration to postcopy mode. Ignored after the end of
-migration (or once already in postcopy).
-
-Example:
--> { "execute": "migrate-start-postcopy" }
-<- { "return": {} }
-
-query-migrate-cache-size
-------------------------
-
-Show cache size to be used by XBZRLE migration
-
-returns a json-object with the following information:
-- "size" : json-int
-
-Example:
-
--> { "execute": "query-migrate-cache-size" }
-<- { "return": 67108864 }
-
-migrate_set_speed
------------------
-
-Set maximum speed for migrations.
-
-Arguments:
-
-- "value": maximum speed, in bytes per second (json-int)
-
-Example:
-
--> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } }
-<- { "return": {} }
-
-migrate_set_downtime
---------------------
-
-Set maximum tolerated downtime (in seconds) for migrations.
-
-Arguments:
-
-- "value": maximum downtime (json-number)
-
-Example:
-
--> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } }
-<- { "return": {} }
-
-client_migrate_info
--------------------
-
-Set migration information for remote display.  This makes the server
-ask the client to automatically reconnect using the new parameters
-once migration finished successfully.  Only implemented for SPICE.
-
-Arguments:
-
-- "protocol":     must be "spice" (json-string)
-- "hostname":     migration target hostname (json-string)
-- "port":         spice tcp port for plaintext channels (json-int, optional)
-- "tls-port":     spice tcp port for tls-secured channels (json-int, optional)
-- "cert-subject": server certificate subject (json-string, optional)
-
-Example:
-
--> { "execute": "client_migrate_info",
-     "arguments": { "protocol": "spice",
-                    "hostname": "virt42.lab.kraxel.org",
-                    "port": 1234 } }
-<- { "return": {} }
-
-dump
-
-
-Dump guest memory to file. The file can be processed with crash or gdb.
-
-Arguments:
-
-- "paging": do paging to get guest's memory mapping (json-bool)
-- "protocol": destination file(started with "file:") or destination file
-              descriptor (started with "fd:") (json-string)
-- "detach": if specified, command will return immediately, without waiting
-            for the dump to finish. The user can track progress using
-            "query-dump". (json-bool)
-- "begin": the starting physical address. It's optional, and should be specified
-           with length together (json-int)
-- "length": the memory size, in bytes. It's optional, and should be specified
-            with begin together (json-int)
-- "format": the format of guest memory dump. It's optional, and can be
-            elf|kdump-zlib|kdump-lzo|kdump-snappy, but non-elf formats will
-            conflict with paging and filter, ie. begin and length (json-string)
-
-Example:
-
--> { "execute": "dump-guest-memory", "arguments": { "protocol": "fd:dump" } }
-<- { "return": {} }
-
-Notes:
-
-(1) All boolean arguments default to false
-
-query-dump-guest-memory-capability
-----------
-
-Show available formats for 'dump-guest-memory'
-
-Example:
-
--> { "execute": "query-dump-guest-memory-capability" }
-<- { "return": { "formats":
-                    ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
-
-query-dump
-----------
-
-Query background dump status.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "query-dump" }
-<- { "return": { "status": "active", "completed": 1024000,
-                 "total": 2048000 } }
-
-dump-skeys
-----------
-
-Save guest storage keys to file.
-
-Arguments:
-
-- "filename": file path (json-string)
-
-Example:
-
--> { "execute": "dump-skeys", "arguments": { "filename": "/tmp/skeys" } }
-<- { "return": {} }
-
-netdev_add
-----------
-
-Add host network device.
-
-Arguments:
-
-- "type": the device type, "tap", "user", ... (json-string)
-- "id": the device's ID, must be unique (json-string)
-- device options
-
-Example:
-
--> { "execute": "netdev_add",
-     "arguments": { "type": "user", "id": "netdev1",
-                    "dnssearch": "example.org" } }
-<- { "return": {} }
-
-Note: The supported device options are the same ones supported by the '-netdev'
-      command-line argument, which are listed in the '-help' output or QEMU's
-      manual
-
-netdev_del
-----------
-
-Remove host network device.
-
-Arguments:
-
-- "id": the device's ID, must be unique (json-string)
-
-Example:
-
--> { "execute": "netdev_del", "arguments": { "id": "netdev1" } }
-<- { "return": {} }
-
-
-object-add
-----------
-
-Create QOM object.
-
-Arguments:
-
-- "qom-type": the object's QOM type, i.e. the class name (json-string)
-- "id": the object's ID, must be unique (json-string)
-- "props": a dictionary of object property values (optional, json-dict)
-
-Example:
-
--> { "execute": "object-add", "arguments": { "qom-type": "rng-random", "id": "rng1",
-     "props": { "filename": "/dev/hwrng" } } }
-<- { "return": {} }
-
-object-del
-----------
-
-Remove QOM object.
-
-Arguments:
-
-- "id": the object's ID (json-string)
-
-Example:
-
--> { "execute": "object-del", "arguments": { "id": "rng1" } }
-<- { "return": {} }
-
-
-block_resize
-------------
-
-Resize a block image while a guest is running.
-
-Arguments:
-
-- "device": the device's ID, must be unique (json-string)
-- "node-name": the node name in the block driver state graph (json-string)
-- "size": new size
-
-Example:
-
--> { "execute": "block_resize", "arguments": { "device": "scratch", "size": 1073741824 } }
-<- { "return": {} }
-
-block-stream
-------------
-
-Copy data from a backing file into a block device.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": The device name or node-name of a root node (json-string)
-- "base": The file name of the backing image above which copying starts
-          (json-string, optional)
-- "backing-file": The backing file string to write into the active layer. This
-                  filename is not validated.
-
-                  If a pathname string is such that it cannot be resolved by
-                  QEMU, that means that subsequent QMP or HMP commands must use
-                  node-names for the image in question, as filename lookup
-                  methods will fail.
-
-                  If not specified, QEMU will automatically determine the
-                  backing file string to use, or error out if there is no
-                  obvious choice.  Care should be taken when specifying the
-                  string, to specify a valid filename or protocol.
-                  (json-string, optional) (Since 2.1)
-- "speed":  the maximum speed, in bytes per second (json-int, optional)
-- "on-error": the action to take on an error (default 'report').  'stop' and
-              'enospc' can only be used if the block device supports io-status.
-              (json-string, optional) (Since 2.1)
-
-Example:
-
--> { "execute": "block-stream", "arguments": { "device": "virtio0",
-                                               "base": "/tmp/master.qcow2" } }
-<- { "return": {} }
-
-block-commit
-------------
-
-Live commit of data from overlay image nodes into backing nodes - i.e., writes
-data between 'top' and 'base' into 'base'.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": The device name or node-name of a root node (json-string)
-- "base": The file name of the backing image to write data into.
-          If not specified, this is the deepest backing image
-          (json-string, optional)
-- "top":  The file name of the backing image within the image chain,
-          which contains the topmost data to be committed down. If
-          not specified, this is the active layer. (json-string, optional)
-
-- backing-file:     The backing file string to write into the overlay
-                    image of 'top'.  If 'top' is the active layer,
-                    specifying a backing file string is an error. This
-                    filename is not validated.
-
-                    If a pathname string is such that it cannot be
-                    resolved by QEMU, that means that subsequent QMP or
-                    HMP commands must use node-names for the image in
-                    question, as filename lookup methods will fail.
-
-                    If not specified, QEMU will automatically determine
-                    the backing file string to use, or error out if
-                    there is no obvious choice. Care should be taken
-                    when specifying the string, to specify a valid
-                    filename or protocol.
-                    (json-string, optional) (Since 2.1)
-
-          If top == base, that is an error.
-          If top == active, the job will not be completed by itself,
-          user needs to complete the job with the block-job-complete
-          command after getting the ready event. (Since 2.0)
-
-          If the base image is smaller than top, then the base image
-          will be resized to be the same size as top.  If top is
-          smaller than the base image, the base will not be
-          truncated.  If you want the base image size to match the
-          size of the smaller top, you can safely truncate it
-          yourself once the commit operation successfully completes.
-          (json-string)
-- "speed":  the maximum speed, in bytes per second (json-int, optional)
-
-
-Example:
-
--> { "execute": "block-commit", "arguments": { "device": "virtio0",
-                                              "top": "/tmp/snap1.qcow2" } }
-<- { "return": {} }
-
-drive-backup
-------------
-
-Start a point-in-time copy of a block device to a new destination.  The
-status of ongoing drive-backup operations can be checked with
-query-block-jobs where the BlockJobInfo.type field has the value 'backup'.
-The operation can be stopped before it has completed using the
-block-job-cancel command.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": the device name or node-name of a root node which should be copied.
-            (json-string)
-- "target": the target of the new image. If the file exists, or if it is a
-            device, the existing file/device will be used as the new
-            destination.  If it does not exist, a new file will be created.
-            (json-string)
-- "format": the format of the new destination, default is to probe if 'mode' is
-            'existing', else the format of the source
-            (json-string, optional)
-- "sync": what parts of the disk image should be copied to the destination;
-  possibilities include "full" for all the disk, "top" for only the sectors
-  allocated in the topmost image, "incremental" for only the dirty sectors in
-  the bitmap, or "none" to only replicate new I/O (MirrorSyncMode).
-- "bitmap": dirty bitmap name for sync==incremental. Must be present if sync
-            is "incremental", must NOT be present otherwise.
-- "mode": whether and how QEMU should create a new image
-          (NewImageMode, optional, default 'absolute-paths')
-- "speed": the maximum speed, in bytes per second (json-int, optional)
-- "compress": true to compress data, if the target format supports it.
-              (json-bool, optional, default false)
-- "on-source-error": the action to take on an error on the source, default
-                     'report'.  'stop' and 'enospc' can only be used
-                     if the block device supports io-status.
-                     (BlockdevOnError, optional)
-- "on-target-error": the action to take on an error on the target, default
-                     'report' (no limitations, since this applies to
-                     a different block device than device).
-                     (BlockdevOnError, optional)
-
-Example:
--> { "execute": "drive-backup", "arguments": { "device": "drive0",
-                                               "sync": "full",
-                                               "target": "backup.img" } }
-<- { "return": {} }
-
-blockdev-backup
----------------
-
-The device version of drive-backup: this command takes an existing named device
-as backup target.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": the device name or node-name of a root node which should be copied.
-            (json-string)
-- "target": the name of the backup target device. (json-string)
-- "sync": what parts of the disk image should be copied to the destination;
-          possibilities include "full" for all the disk, "top" for only the
-          sectors allocated in the topmost image, or "none" to only replicate
-          new I/O (MirrorSyncMode).
-- "speed": the maximum speed, in bytes per second (json-int, optional)
-- "compress": true to compress data, if the target format supports it.
-              (json-bool, optional, default false)
-- "on-source-error": the action to take on an error on the source, default
-                     'report'.  'stop' and 'enospc' can only be used
-                     if the block device supports io-status.
-                     (BlockdevOnError, optional)
-- "on-target-error": the action to take on an error on the target, default
-                     'report' (no limitations, since this applies to
-                     a different block device than device).
-                     (BlockdevOnError, optional)
-
-Example:
--> { "execute": "blockdev-backup", "arguments": { "device": "src-id",
-                                                  "sync": "full",
-                                                  "target": "tgt-id" } }
-<- { "return": {} }
-
-transaction
------------
-
-Atomically operate on one or more block devices.  Operations that are
-currently supported:
-
-    - drive-backup
-    - blockdev-backup
-    - blockdev-snapshot-sync
-    - blockdev-snapshot-internal-sync
-    - abort
-    - block-dirty-bitmap-add
-    - block-dirty-bitmap-clear
-
-Refer to the qemu/qapi-schema.json file for minimum required QEMU
-versions for these operations.  A list of dictionaries is accepted,
-that contains the actions to be performed.  If there is any failure
-performing any of the operations, all operations for the group are
-abandoned.
-
-For external snapshots, the dictionary contains the device, the file to use for
-the new snapshot, and the format.  The default format, if not specified, is
-qcow2.
-
-Each new snapshot defaults to being created by QEMU (wiping any
-contents if the file already exists), but it is also possible to reuse
-an externally-created file.  In the latter case, you should ensure that
-the new image file has the same contents as the current one; QEMU cannot
-perform any meaningful check.  Typically this is achieved by using the
-current image file as the backing file for the new image.
-
-On failure, the original disks pre-snapshot attempt will be used.
-
-For internal snapshots, the dictionary contains the device and the snapshot's
-name.  If an internal snapshot matching name already exists, the request will
-be rejected.  Only some image formats support it, for example, qcow2, rbd,
-and sheepdog.
-
-On failure, qemu will try delete the newly created internal snapshot in the
-transaction.  When an I/O error occurs during deletion, the user needs to fix
-it later with qemu-img or other command.
-
-Arguments:
-
-actions array:
-    - "type": the operation to perform (json-string).  Possible
-              values: "drive-backup", "blockdev-backup",
-                      "blockdev-snapshot-sync",
-                      "blockdev-snapshot-internal-sync",
-                      "abort", "block-dirty-bitmap-add",
-                      "block-dirty-bitmap-clear"
-    - "data": a dictionary.  The contents depend on the value
-      of "type".  When "type" is "blockdev-snapshot-sync":
-      - "device": device name to snapshot (json-string)
-      - "node-name": graph node name to snapshot (json-string)
-      - "snapshot-file": name of new image file (json-string)
-      - "snapshot-node-name": graph node name of the new snapshot (json-string)
-      - "format": format of new image (json-string, optional)
-      - "mode": whether and how QEMU should create the snapshot file
-        (NewImageMode, optional, default "absolute-paths")
-      When "type" is "blockdev-snapshot-internal-sync":
-      - "device": the device name or node-name of a root node to snapshot
-                  (json-string)
-      - "name": name of the new snapshot (json-string)
-
-Example:
-
--> { "execute": "transaction",
-     "arguments": { "actions": [
-         { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd0",
-                                         "snapshot-file": "/some/place/my-image",
-                                         "format": "qcow2" } },
-         { "type": "blockdev-snapshot-sync", "data" : { "node-name": "myfile",
-                                         "snapshot-file": "/some/place/my-image2",
-                                         "snapshot-node-name": "node3432",
-                                         "mode": "existing",
-                                         "format": "qcow2" } },
-         { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd1",
-                                         "snapshot-file": "/some/place/my-image2",
-                                         "mode": "existing",
-                                         "format": "qcow2" } },
-         { "type": "blockdev-snapshot-internal-sync", "data" : {
-                                         "device": "ide-hd2",
-                                         "name": "snapshot0" } } ] } }
-<- { "return": {} }
-
-block-dirty-bitmap-add
-----------------------
-Since 2.4
-
-Create a dirty bitmap with a name on the device, and start tracking the writes.
-
-Arguments:
-
-- "node": device/node on which to create dirty bitmap (json-string)
-- "name": name of the new dirty bitmap (json-string)
-- "granularity": granularity to track writes with (int, optional)
-
-Example:
-
--> { "execute": "block-dirty-bitmap-add", "arguments": { "node": "drive0",
-                                                   "name": "bitmap0" } }
-<- { "return": {} }
-
-block-dirty-bitmap-remove
--------------------------
-Since 2.4
-
-Stop write tracking and remove the dirty bitmap that was created with
-block-dirty-bitmap-add.
-
-Arguments:
-
-- "node": device/node on which to remove dirty bitmap (json-string)
-- "name": name of the dirty bitmap to remove (json-string)
-
-Example:
-
--> { "execute": "block-dirty-bitmap-remove", "arguments": { "node": "drive0",
-                                                      "name": "bitmap0" } }
-<- { "return": {} }
-
-block-dirty-bitmap-clear
-------------------------
-Since 2.4
-
-Reset the dirty bitmap associated with a node so that an incremental backup
-from this point in time forward will only backup clusters modified after this
-clear operation.
-
-Arguments:
-
-- "node": device/node on which to remove dirty bitmap (json-string)
-- "name": name of the dirty bitmap to remove (json-string)
-
-Example:
-
--> { "execute": "block-dirty-bitmap-clear", "arguments": { "node": "drive0",
-                                                           "name": "bitmap0" } }
-<- { "return": {} }
-
-blockdev-snapshot-sync
-----------------------
-
-Synchronous snapshot of a block device. snapshot-file specifies the
-target of the new image. If the file exists, or if it is a device, the
-snapshot will be created in the existing file/device. If does not
-exist, a new file will be created. format specifies the format of the
-snapshot image, default is qcow2.
-
-Arguments:
-
-- "device": device name to snapshot (json-string)
-- "node-name": graph node name to snapshot (json-string)
-- "snapshot-file": name of new image file (json-string)
-- "snapshot-node-name": graph node name of the new snapshot (json-string)
-- "mode": whether and how QEMU should create the snapshot file
-  (NewImageMode, optional, default "absolute-paths")
-- "format": format of new image (json-string, optional)
-
-Example:
-
--> { "execute": "blockdev-snapshot-sync", "arguments": { "device": "ide-hd0",
-                                                         "snapshot-file":
-                                                        "/some/place/my-image",
-                                                        "format": "qcow2" } }
-<- { "return": {} }
-
-blockdev-snapshot
------------------
-Since 2.5
-
-Create a snapshot, by installing 'node' as the backing image of
-'overlay'. Additionally, if 'node' is associated with a block
-device, the block device changes to using 'overlay' as its new active
-image.
-
-Arguments:
-
-- "node": device that will have a snapshot created (json-string)
-- "overlay": device that will have 'node' as its backing image (json-string)
-
-Example:
-
--> { "execute": "blockdev-add",
-                "arguments": { "options": { "driver": "qcow2",
-                                            "node-name": "node1534",
-                                            "file": { "driver": "file",
-                                                      "filename": "hd1.qcow2" },
-                                            "backing": "" } } }
-
-<- { "return": {} }
-
--> { "execute": "blockdev-snapshot", "arguments": { "node": "ide-hd0",
-                                                    "overlay": "node1534" } }
-<- { "return": {} }
-
-blockdev-snapshot-internal-sync
--------------------------------
-
-Synchronously take an internal snapshot of a block device when the format of
-image used supports it.  If the name is an empty string, or a snapshot with
-name already exists, the operation will fail.
-
-Arguments:
-
-- "device": the device name or node-name of a root node to snapshot
-            (json-string)
-- "name": name of the new snapshot (json-string)
-
-Example:
-
--> { "execute": "blockdev-snapshot-internal-sync",
-                "arguments": { "device": "ide-hd0",
-                               "name": "snapshot0" }
-   }
-<- { "return": {} }
-
-blockdev-snapshot-delete-internal-sync
---------------------------------------
-
-Synchronously delete an internal snapshot of a block device when the format of
-image used supports it.  The snapshot is identified by name or id or both.  One
-of name or id is required.  If the snapshot is not found, the operation will
-fail.
-
-Arguments:
-
-- "device": the device name or node-name of a root node (json-string)
-- "id": ID of the snapshot (json-string, optional)
-- "name": name of the snapshot (json-string, optional)
-
-Example:
-
--> { "execute": "blockdev-snapshot-delete-internal-sync",
-                "arguments": { "device": "ide-hd0",
-                               "name": "snapshot0" }
-   }
-<- { "return": {
-                   "id": "1",
-                   "name": "snapshot0",
-                   "vm-state-size": 0,
-                   "date-sec": 1000012,
-                   "date-nsec": 10,
-                   "vm-clock-sec": 100,
-                   "vm-clock-nsec": 20
-     }
-   }
-
-drive-mirror
-------------
-
-Start mirroring a block device's writes to a new destination. target
-specifies the target of the new image. If the file exists, or if it is
-a device, it will be used as the new destination for writes. If it does not
-exist, a new file will be created. format specifies the format of the
-mirror image, default is to probe if mode='existing', else the format
-of the source.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": the device name or node-name of a root node whose writes should be
-            mirrored. (json-string)
-- "target": name of new image file (json-string)
-- "format": format of new image (json-string, optional)
-- "node-name": the name of the new block driver state in the node graph
-               (json-string, optional)
-- "replaces": the block driver node name to replace when finished
-              (json-string, optional)
-- "mode": how an image file should be created into the target
-  file/device (NewImageMode, optional, default 'absolute-paths')
-- "speed": maximum speed of the streaming job, in bytes per second
-  (json-int)
-- "granularity": granularity of the dirty bitmap, in bytes (json-int, optional)
-- "buf-size": maximum amount of data in flight from source to target, in bytes
-  (json-int, default 10M)
-- "sync": what parts of the disk image should be copied to the destination;
-  possibilities include "full" for all the disk, "top" for only the sectors
-  allocated in the topmost image, or "none" to only replicate new I/O
-  (MirrorSyncMode).
-- "on-source-error": the action to take on an error on the source
-  (BlockdevOnError, default 'report')
-- "on-target-error": the action to take on an error on the target
-  (BlockdevOnError, default 'report')
-- "unmap": whether the target sectors should be discarded where source has only
-  zeroes. (json-bool, optional, default true)
-
-The default value of the granularity is the image cluster size clamped
-between 4096 and 65536, if the image format defines one.  If the format
-does not define a cluster size, the default value of the granularity
-is 65536.
-
-
-Example:
-
--> { "execute": "drive-mirror", "arguments": { "device": "ide-hd0",
-                                               "target": "/some/place/my-image",
-                                               "sync": "full",
-                                               "format": "qcow2" } }
-<- { "return": {} }
-
-blockdev-mirror
-------------
-
-Start mirroring a block device's writes to another block device. target
-specifies the target of mirror operation.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": The device name or node-name of a root node whose writes should be
-            mirrored (json-string)
-- "target": device name to mirror to (json-string)
-- "replaces": the block driver node name to replace when finished
-              (json-string, optional)
-- "speed": maximum speed of the streaming job, in bytes per second
-  (json-int)
-- "granularity": granularity of the dirty bitmap, in bytes (json-int, optional)
-- "buf_size": maximum amount of data in flight from source to target, in bytes
-  (json-int, default 10M)
-- "sync": what parts of the disk image should be copied to the destination;
-  possibilities include "full" for all the disk, "top" for only the sectors
-  allocated in the topmost image, or "none" to only replicate new I/O
-  (MirrorSyncMode).
-- "on-source-error": the action to take on an error on the source
-  (BlockdevOnError, default 'report')
-- "on-target-error": the action to take on an error on the target
-  (BlockdevOnError, default 'report')
-
-The default value of the granularity is the image cluster size clamped
-between 4096 and 65536, if the image format defines one.  If the format
-does not define a cluster size, the default value of the granularity
-is 65536.
-
-Example:
-
--> { "execute": "blockdev-mirror", "arguments": { "device": "ide-hd0",
-                                                  "target": "target0",
-                                                  "sync": "full" } }
-<- { "return": {} }
-
-change-backing-file
--------------------
-Since: 2.1
-
-Change the backing file in the image file metadata.  This does not cause
-QEMU to reopen the image file to reparse the backing filename (it may,
-however, perform a reopen to change permissions from r/o -> r/w -> r/o,
-if needed). The new backing file string is written into the image file
-metadata, and the QEMU internal strings are updated.
-
-Arguments:
-
-- "image-node-name":    The name of the block driver state node of the
-                        image to modify.  The "device" is argument is used to
-                        verify "image-node-name" is in the chain described by
-                        "device".
-                        (json-string, optional)
-
-- "device":             The device name or node-name of the root node that owns
-                        image-node-name.
-                        (json-string)
-
-- "backing-file":       The string to write as the backing file.  This string is
-                        not validated, so care should be taken when specifying
-                        the string or the image chain may not be able to be
-                        reopened again.
-                        (json-string)
-
-Returns: Nothing on success
-         If "device" does not exist or cannot be determined, DeviceNotFound
-
-balloon
--------
-
-Request VM to change its memory allocation (in bytes).
-
-Arguments:
-
-- "value": New memory allocation (json-int)
-
-Example:
-
--> { "execute": "balloon", "arguments": { "value": 536870912 } }
-<- { "return": {} }
-
-set_link
---------
-
-Change the link status of a network adapter.
-
-Arguments:
-
-- "name": network device name (json-string)
-- "up": status is up (json-bool)
-
-Example:
-
--> { "execute": "set_link", "arguments": { "name": "e1000.0", "up": false } }
-<- { "return": {} }
-
-getfd
------
-
-Receive a file descriptor via SCM rights and assign it a name.
-
-Arguments:
-
-- "fdname": file descriptor name (json-string)
-
-Example:
-
--> { "execute": "getfd", "arguments": { "fdname": "fd1" } }
-<- { "return": {} }
-
-Notes:
-
-(1) If the name specified by the "fdname" argument already exists,
-    the file descriptor assigned to it will be closed and replaced
-    by the received file descriptor.
-(2) The 'closefd' command can be used to explicitly close the file
-    descriptor when it is no longer needed.
-
-closefd
--------
-
-Close a file descriptor previously passed via SCM rights.
-
-Arguments:
-
-- "fdname": file descriptor name (json-string)
-
-Example:
-
--> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
-<- { "return": {} }
-
-add-fd
--------
-
-Add a file descriptor, that was passed via SCM rights, to an fd set.
-
-Arguments:
-
-- "fdset-id": The ID of the fd set to add the file descriptor to.
-              (json-int, optional)
-- "opaque": A free-form string that can be used to describe the fd.
-            (json-string, optional)
-
-Return a json-object with the following information:
-
-- "fdset-id": The ID of the fd set that the fd was added to. (json-int)
-- "fd": The file descriptor that was received via SCM rights and added to the
-        fd set. (json-int)
-
-Example:
-
--> { "execute": "add-fd", "arguments": { "fdset-id": 1 } }
-<- { "return": { "fdset-id": 1, "fd": 3 } }
-
-Notes:
-
-(1) The list of fd sets is shared by all monitor connections.
-(2) If "fdset-id" is not specified, a new fd set will be created.
-
-remove-fd
----------
-
-Remove a file descriptor from an fd set.
-
-Arguments:
-
-- "fdset-id": The ID of the fd set that the file descriptor belongs to.
-              (json-int)
-- "fd": The file descriptor that is to be removed. (json-int, optional)
-
-Example:
-
--> { "execute": "remove-fd", "arguments": { "fdset-id": 1, "fd": 3 } }
-<- { "return": {} }
-
-Notes:
-
-(1) The list of fd sets is shared by all monitor connections.
-(2) If "fd" is not specified, all file descriptors in "fdset-id" will be
-    removed.
-
-query-fdsets
--------------
-
-Return information describing all fd sets.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-fdsets" }
-<- { "return": [
-       {
-         "fds": [
-           {
-             "fd": 30,
-             "opaque": "rdonly:/path/to/file"
-           },
-           {
-             "fd": 24,
-             "opaque": "rdwr:/path/to/file"
-           }
-         ],
-         "fdset-id": 1
-       },
-       {
-         "fds": [
-           {
-             "fd": 28
-           },
-           {
-             "fd": 29
-           }
-         ],
-         "fdset-id": 0
-       }
-     ]
-   }
-
-Note: The list of fd sets is shared by all monitor connections.
-
-block_passwd
-------------
-
-Set the password of encrypted block devices.
-
-Arguments:
-
-- "device": device name (json-string)
-- "node-name": name in the block driver state graph (json-string)
-- "password": password (json-string)
-
-Example:
-
--> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0",
-                                               "password": "12345" } }
-<- { "return": {} }
-
-block_set_io_throttle
-------------
-
-Change I/O throttle limits for a block drive.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "bps": total throughput limit in bytes per second (json-int)
-- "bps_rd": read throughput limit in bytes per second (json-int)
-- "bps_wr": write throughput limit in bytes per second (json-int)
-- "iops": total I/O operations per second (json-int)
-- "iops_rd": read I/O operations per second (json-int)
-- "iops_wr": write I/O operations per second (json-int)
-- "bps_max": total throughput limit during bursts, in bytes (json-int, optional)
-- "bps_rd_max": read throughput limit during bursts, in bytes (json-int, optional)
-- "bps_wr_max": write throughput limit during bursts, in bytes (json-int, optional)
-- "iops_max": total I/O operations per second during bursts (json-int, optional)
-- "iops_rd_max": read I/O operations per second during bursts (json-int, optional)
-- "iops_wr_max": write I/O operations per second during bursts (json-int, optional)
-- "bps_max_length": maximum length of the @bps_max burst period, in seconds (json-int, optional)
-- "bps_rd_max_length": maximum length of the @bps_rd_max burst period, in seconds (json-int, optional)
-- "bps_wr_max_length": maximum length of the @bps_wr_max burst period, in seconds (json-int, optional)
-- "iops_max_length": maximum length of the @iops_max burst period, in seconds (json-int, optional)
-- "iops_rd_max_length": maximum length of the @iops_rd_max burst period, in seconds (json-int, optional)
-- "iops_wr_max_length": maximum length of the @iops_wr_max burst period, in seconds (json-int, optional)
-- "iops_size":  I/O size in bytes when limiting (json-int, optional)
-- "group": throttle group name (json-string, optional)
-
-Example:
-
--> { "execute": "block_set_io_throttle", "arguments": { "id": "ide0-1-0",
-                                               "bps": 1000000,
-                                               "bps_rd": 0,
-                                               "bps_wr": 0,
-                                               "iops": 0,
-                                               "iops_rd": 0,
-                                               "iops_wr": 0,
-                                               "bps_max": 8000000,
-                                               "bps_rd_max": 0,
-                                               "bps_wr_max": 0,
-                                               "iops_max": 0,
-                                               "iops_rd_max": 0,
-                                               "iops_wr_max": 0,
-                                               "bps_max_length": 60,
-                                               "iops_size": 0 } }
-<- { "return": {} }
-
-set_password
-------------
-
-Set the password for vnc/spice protocols.
-
-Arguments:
-
-- "protocol": protocol name (json-string)
-- "password": password (json-string)
-- "connected": [ keep | disconnect | fail ] (json-string, optional)
-
-Example:
-
--> { "execute": "set_password", "arguments": { "protocol": "vnc",
-                                               "password": "secret" } }
-<- { "return": {} }
-
-expire_password
----------------
-
-Set the password expire time for vnc/spice protocols.
-
-Arguments:
-
-- "protocol": protocol name (json-string)
-- "time": [ now | never | +secs | secs ] (json-string)
-
-Example:
-
--> { "execute": "expire_password", "arguments": { "protocol": "vnc",
-                                                  "time": "+60" } }
-<- { "return": {} }
-
-add_client
-----------
-
-Add a graphics client
-
-Arguments:
-
-- "protocol": protocol name (json-string)
-- "fdname": file descriptor name (json-string)
-- "skipauth": whether to skip authentication (json-bool, optional)
-- "tls": whether to perform TLS (json-bool, optional)
-
-Example:
-
--> { "execute": "add_client", "arguments": { "protocol": "vnc",
-                                             "fdname": "myclient" } }
-<- { "return": {} }
-
-qmp_capabilities
-----------------
-
-Enable QMP capabilities.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "qmp_capabilities" }
-<- { "return": {} }
-
-Note: This command must be issued before issuing any other command.
-
-human-monitor-command
----------------------
-
-Execute a Human Monitor command.
-
-Arguments:
-
-- command-line: the command name and its arguments, just like the
-                Human Monitor's shell (json-string)
-- cpu-index: select the CPU number to be used by commands which access CPU
-             data, like 'info registers'. The Monitor selects CPU 0 if this
-             argument is not provided (json-int, optional)
-
-Example:
-
--> { "execute": "human-monitor-command", "arguments": { "command-line": "info kvm" } }
-<- { "return": "kvm support: enabled\r\n" }
-
-Notes:
-
-(1) The Human Monitor is NOT an stable interface, this means that command
-    names, arguments and responses can change or be removed at ANY time.
-    Applications that rely on long term stability guarantees should NOT
-    use this command
-
-(2) Limitations:
-
-    o This command is stateless, this means that commands that depend
-      on state information (such as getfd) might not work
-
-    o Commands that prompt the user for data (eg. 'cont' when the block
-      device is encrypted) don't currently work
-
-3. Query Commands
-=================
-
-
-query-version
--------------
-
-Show QEMU version.
-
-Return a json-object with the following information:
-
-- "qemu": A json-object containing three integer values:
-    - "major": QEMU's major version (json-int)
-    - "minor": QEMU's minor version (json-int)
-    - "micro": QEMU's micro version (json-int)
-- "package": package's version (json-string)
-
-Example:
-
--> { "execute": "query-version" }
-<- {
-      "return":{
-         "qemu":{
-            "major":0,
-            "minor":11,
-            "micro":5
-         },
-         "package":""
-      }
-   }
-
-query-commands
---------------
-
-List QMP available commands.
-
-Each command is represented by a json-object, the returned value is a json-array
-of all commands.
-
-Each json-object contain:
-
-- "name": command's name (json-string)
-
-Example:
-
--> { "execute": "query-commands" }
-<- {
-      "return":[
-         {
-            "name":"query-balloon"
-         },
-         {
-            "name":"system_powerdown"
-         }
-      ]
-   }
-
-Note: This example has been shortened as the real response is too long.
-
-query-events
---------------
-
-List QMP available events.
-
-Each event is represented by a json-object, the returned value is a json-array
-of all events.
-
-Each json-object contains:
-
-- "name": event's name (json-string)
-
-Example:
-
--> { "execute": "query-events" }
-<- {
-      "return":[
-         {
-            "name":"SHUTDOWN"
-         },
-         {
-            "name":"RESET"
-         }
-      ]
-   }
-
-Note: This example has been shortened as the real response is too long.
-
-query-qmp-schema
-----------------
-
-Return the QMP wire schema.  The returned value is a json-array of
-named schema entities.  Entities are commands, events and various
-types.  See docs/qapi-code-gen.txt for information on their structure
-and intended use.
-
-query-chardev
--------------
-
-Each device is represented by a json-object. The returned value is a json-array
-of all devices.
-
-Each json-object contain the following:
-
-- "label": device's label (json-string)
-- "filename": device's file (json-string)
-- "frontend-open": open/closed state of the frontend device attached to this
-                   backend (json-bool)
-
-Example:
-
--> { "execute": "query-chardev" }
-<- {
-      "return": [
-         {
-            "label": "charchannel0",
-            "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.agent,server",
-            "frontend-open": false
-         },
-         {
-            "label": "charmonitor",
-            "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.monitor,server",
-            "frontend-open": true
-         },
-         {
-            "label": "charserial0",
-            "filename": "pty:/dev/pts/2",
-            "frontend-open": true
-         }
-      ]
-   }
-
-query-chardev-backends
--------------
-
-List available character device backends.
-
-Each backend is represented by a json-object, the returned value is a json-array
-of all backends.
-
-Each json-object contains:
-
-- "name": backend name (json-string)
-
-Example:
-
--> { "execute": "query-chardev-backends" }
-<- {
-      "return":[
-         {
-            "name":"udp"
-         },
-         {
-            "name":"tcp"
-         },
-         {
-            "name":"unix"
-         },
-         {
-            "name":"spiceport"
-         }
-      ]
-   }
-
-query-block
------------
-
-Show the block devices.
-
-Each block device information is stored in a json-object and the returned value
-is a json-array of all devices.
-
-Each json-object contain the following:
-
-- "device": device name (json-string)
-- "type": device type (json-string)
-         - deprecated, retained for backward compatibility
-         - Possible values: "unknown"
-- "removable": true if the device is removable, false otherwise (json-bool)
-- "locked": true if the device is locked, false otherwise (json-bool)
-- "tray_open": only present if removable, true if the device has a tray,
-               and it is open (json-bool)
-- "inserted": only present if the device is inserted, it is a json-object
-   containing the following:
-         - "file": device file name (json-string)
-         - "ro": true if read-only, false otherwise (json-bool)
-         - "drv": driver format name (json-string)
-             - Possible values: "blkdebug", "bochs", "cloop", "dmg",
-                                "file", "file", "ftp", "ftps", "host_cdrom",
-                                "host_device", "http", "https",
-                                "nbd", "parallels", "qcow", "qcow2", "raw",
-                                "tftp", "vdi", "vmdk", "vpc", "vvfat"
-         - "backing_file": backing file name (json-string, optional)
-         - "backing_file_depth": number of files in the backing file chain (json-int)
-         - "encrypted": true if encrypted, false otherwise (json-bool)
-         - "bps": limit total bytes per second (json-int)
-         - "bps_rd": limit read bytes per second (json-int)
-         - "bps_wr": limit write bytes per second (json-int)
-         - "iops": limit total I/O operations per second (json-int)
-         - "iops_rd": limit read operations per second (json-int)
-         - "iops_wr": limit write operations per second (json-int)
-         - "bps_max":  total max in bytes (json-int)
-         - "bps_rd_max":  read max in bytes (json-int)
-         - "bps_wr_max":  write max in bytes (json-int)
-         - "iops_max":  total I/O operations max (json-int)
-         - "iops_rd_max":  read I/O operations max (json-int)
-         - "iops_wr_max":  write I/O operations max (json-int)
-         - "iops_size": I/O size when limiting by iops (json-int)
-         - "detect_zeroes": detect and optimize zero writing (json-string)
-             - Possible values: "off", "on", "unmap"
-         - "write_threshold": write offset threshold in bytes, a event will be
-                              emitted if crossed. Zero if disabled (json-int)
-         - "image": the detail of the image, it is a json-object containing
-            the following:
-             - "filename": image file name (json-string)
-             - "format": image format (json-string)
-             - "virtual-size": image capacity in bytes (json-int)
-             - "dirty-flag": true if image is not cleanly closed, not present
-                             means clean (json-bool, optional)
-             - "actual-size": actual size on disk in bytes of the image, not
-                              present when image does not support thin
-                              provision (json-int, optional)
-             - "cluster-size": size of a cluster in bytes, not present if image
-                               format does not support it (json-int, optional)
-             - "encrypted": true if the image is encrypted, not present means
-                            false or the image format does not support
-                            encryption (json-bool, optional)
-             - "backing_file": backing file name, not present means no backing
-                               file is used or the image format does not
-                               support backing file chain
-                               (json-string, optional)
-             - "full-backing-filename": full path of the backing file, not
-                                        present if it equals backing_file or no
-                                        backing file is used
-                                        (json-string, optional)
-             - "backing-filename-format": the format of the backing file, not
-                                          present means unknown or no backing
-                                          file (json-string, optional)
-             - "snapshots": the internal snapshot info, it is an optional list
-                of json-object containing the following:
-                 - "id": unique snapshot id (json-string)
-                 - "name": snapshot name (json-string)
-                 - "vm-state-size": size of the VM state in bytes (json-int)
-                 - "date-sec": UTC date of the snapshot in seconds (json-int)
-                 - "date-nsec": fractional part in nanoseconds to be used with
-                                date-sec (json-int)
-                 - "vm-clock-sec": VM clock relative to boot in seconds
-                                   (json-int)
-                 - "vm-clock-nsec": fractional part in nanoseconds to be used
-                                    with vm-clock-sec (json-int)
-             - "backing-image": the detail of the backing image, it is an
-                                optional json-object only present when a
-                                backing image present for this image
-
-- "io-status": I/O operation status, only present if the device supports it
-               and the VM is configured to stop on errors. It's always reset
-               to "ok" when the "cont" command is issued (json_string, optional)
-             - Possible values: "ok", "failed", "nospace"
-
-Example:
-
--> { "execute": "query-block" }
-<- {
-      "return":[
-         {
-            "io-status": "ok",
-            "device":"ide0-hd0",
-            "locked":false,
-            "removable":false,
-            "inserted":{
-               "ro":false,
-               "drv":"qcow2",
-               "encrypted":false,
-               "file":"disks/test.qcow2",
-               "backing_file_depth":1,
-               "bps":1000000,
-               "bps_rd":0,
-               "bps_wr":0,
-               "iops":1000000,
-               "iops_rd":0,
-               "iops_wr":0,
-               "bps_max": 8000000,
-               "bps_rd_max": 0,
-               "bps_wr_max": 0,
-               "iops_max": 0,
-               "iops_rd_max": 0,
-               "iops_wr_max": 0,
-               "iops_size": 0,
-               "detect_zeroes": "on",
-               "write_threshold": 0,
-               "image":{
-                  "filename":"disks/test.qcow2",
-                  "format":"qcow2",
-                  "virtual-size":2048000,
-                  "backing_file":"base.qcow2",
-                  "full-backing-filename":"disks/base.qcow2",
-                  "backing-filename-format":"qcow2",
-                  "snapshots":[
-                     {
-                        "id": "1",
-                        "name": "snapshot1",
-                        "vm-state-size": 0,
-                        "date-sec": 10000200,
-                        "date-nsec": 12,
-                        "vm-clock-sec": 206,
-                        "vm-clock-nsec": 30
-                     }
-                  ],
-                  "backing-image":{
-                      "filename":"disks/base.qcow2",
-                      "format":"qcow2",
-                      "virtual-size":2048000
-                  }
-               }
-            },
-            "type":"unknown"
-         },
-         {
-            "io-status": "ok",
-            "device":"ide1-cd0",
-            "locked":false,
-            "removable":true,
-            "type":"unknown"
-         },
-         {
-            "device":"floppy0",
-            "locked":false,
-            "removable":true,
-            "type":"unknown"
-         },
-         {
-            "device":"sd0",
-            "locked":false,
-            "removable":true,
-            "type":"unknown"
-         }
-      ]
-   }
-
-query-blockstats
-----------------
-
-Show block device statistics.
-
-Each device statistic information is stored in a json-object and the returned
-value is a json-array of all devices.
-
-Each json-object contain the following:
-
-- "device": device name (json-string)
-- "stats": A json-object with the statistics information, it contains:
-    - "rd_bytes": bytes read (json-int)
-    - "wr_bytes": bytes written (json-int)
-    - "rd_operations": read operations (json-int)
-    - "wr_operations": write operations (json-int)
-    - "flush_operations": cache flush operations (json-int)
-    - "wr_total_time_ns": total time spend on writes in nano-seconds (json-int)
-    - "rd_total_time_ns": total time spend on reads in nano-seconds (json-int)
-    - "flush_total_time_ns": total time spend on cache flushes in nano-seconds (json-int)
-    - "wr_highest_offset": The offset after the greatest byte written to the
-                           BlockDriverState since it has been opened (json-int)
-    - "rd_merged": number of read requests that have been merged into
-                   another request (json-int)
-    - "wr_merged": number of write requests that have been merged into
-                   another request (json-int)
-    - "idle_time_ns": time since the last I/O operation, in
-                      nanoseconds. If the field is absent it means
-                      that there haven't been any operations yet
-                      (json-int, optional)
-    - "failed_rd_operations": number of failed read operations
-                              (json-int)
-    - "failed_wr_operations": number of failed write operations
-                              (json-int)
-    - "failed_flush_operations": number of failed flush operations
-                               (json-int)
-    - "invalid_rd_operations": number of invalid read operations
-                               (json-int)
-    - "invalid_wr_operations": number of invalid write operations
-                               (json-int)
-    - "invalid_flush_operations": number of invalid flush operations
-                                  (json-int)
-    - "account_invalid": whether invalid operations are included in
-                         the last access statistics (json-bool)
-    - "account_failed": whether failed operations are included in the
-                         latency and last access statistics
-                         (json-bool)
-    - "timed_stats": A json-array containing statistics collected in
-                     specific intervals, with the following members:
-        - "interval_length": interval used for calculating the
-                             statistics, in seconds (json-int)
-        - "min_rd_latency_ns": minimum latency of read operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "min_wr_latency_ns": minimum latency of write operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "min_flush_latency_ns": minimum latency of flush operations
-                                  in the defined interval, in
-                                  nanoseconds (json-int)
-        - "max_rd_latency_ns": maximum latency of read operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "max_wr_latency_ns": maximum latency of write operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "max_flush_latency_ns": maximum latency of flush operations
-                                  in the defined interval, in
-                                  nanoseconds (json-int)
-        - "avg_rd_latency_ns": average latency of read operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "avg_wr_latency_ns": average latency of write operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "avg_flush_latency_ns": average latency of flush operations
-                                  in the defined interval, in
-                                  nanoseconds (json-int)
-        - "avg_rd_queue_depth": average number of pending read
-                                operations in the defined interval
-                                (json-number)
-        - "avg_wr_queue_depth": average number of pending write
-                                operations in the defined interval
-                                (json-number).
-- "parent": Contains recursively the statistics of the underlying
-            protocol (e.g. the host file for a qcow2 image). If there is
-            no underlying protocol, this field is omitted
-            (json-object, optional)
-
-Example:
-
--> { "execute": "query-blockstats" }
-<- {
-      "return":[
-         {
-            "device":"ide0-hd0",
-            "parent":{
-               "stats":{
-                  "wr_highest_offset":3686448128,
-                  "wr_bytes":9786368,
-                  "wr_operations":751,
-                  "rd_bytes":122567168,
-                  "rd_operations":36772
-                  "wr_total_times_ns":313253456
-                  "rd_total_times_ns":3465673657
-                  "flush_total_times_ns":49653
-                  "flush_operations":61,
-                  "rd_merged":0,
-                  "wr_merged":0,
-                  "idle_time_ns":2953431879,
-                  "account_invalid":true,
-                  "account_failed":false
-               }
-            },
-            "stats":{
-               "wr_highest_offset":2821110784,
-               "wr_bytes":9786368,
-               "wr_operations":692,
-               "rd_bytes":122739200,
-               "rd_operations":36604
-               "flush_operations":51,
-               "wr_total_times_ns":313253456
-               "rd_total_times_ns":3465673657
-               "flush_total_times_ns":49653,
-               "rd_merged":0,
-               "wr_merged":0,
-               "idle_time_ns":2953431879,
-               "account_invalid":true,
-               "account_failed":false
-            }
-         },
-         {
-            "device":"ide1-cd0",
-            "stats":{
-               "wr_highest_offset":0,
-               "wr_bytes":0,
-               "wr_operations":0,
-               "rd_bytes":0,
-               "rd_operations":0
-               "flush_operations":0,
-               "wr_total_times_ns":0
-               "rd_total_times_ns":0
-               "flush_total_times_ns":0,
-               "rd_merged":0,
-               "wr_merged":0,
-               "account_invalid":false,
-               "account_failed":false
-            }
-         },
-         {
-            "device":"floppy0",
-            "stats":{
-               "wr_highest_offset":0,
-               "wr_bytes":0,
-               "wr_operations":0,
-               "rd_bytes":0,
-               "rd_operations":0
-               "flush_operations":0,
-               "wr_total_times_ns":0
-               "rd_total_times_ns":0
-               "flush_total_times_ns":0,
-               "rd_merged":0,
-               "wr_merged":0,
-               "account_invalid":false,
-               "account_failed":false
-            }
-         },
-         {
-            "device":"sd0",
-            "stats":{
-               "wr_highest_offset":0,
-               "wr_bytes":0,
-               "wr_operations":0,
-               "rd_bytes":0,
-               "rd_operations":0
-               "flush_operations":0,
-               "wr_total_times_ns":0
-               "rd_total_times_ns":0
-               "flush_total_times_ns":0,
-               "rd_merged":0,
-               "wr_merged":0,
-               "account_invalid":false,
-               "account_failed":false
-            }
-         }
-      ]
-   }
-
-query-cpus
-----------
-
-Show CPU information.
-
-Return a json-array. Each CPU is represented by a json-object, which contains:
-
-- "CPU": CPU index (json-int)
-- "current": true if this is the current CPU, false otherwise (json-bool)
-- "halted": true if the cpu is halted, false otherwise (json-bool)
-- "qom_path": path to the CPU object in the QOM tree (json-str)
-- "arch": architecture of the cpu, which determines what additional
-          keys will be present (json-str)
-- Current program counter. The key's name depends on the architecture:
-     "pc": i386/x86_64 (json-int)
-     "nip": PPC (json-int)
-     "pc" and "npc": sparc (json-int)
-     "PC": mips (json-int)
-- "thread_id": ID of the underlying host thread (json-int)
-
-Example:
-
--> { "execute": "query-cpus" }
-<- {
-      "return":[
-         {
-            "CPU":0,
-            "current":true,
-            "halted":false,
-            "qom_path":"/machine/unattached/device[0]",
-            "arch":"x86",
-            "pc":3227107138,
-            "thread_id":3134
-         },
-         {
-            "CPU":1,
-            "current":false,
-            "halted":true,
-            "qom_path":"/machine/unattached/device[2]",
-            "arch":"x86",
-            "pc":7108165,
-            "thread_id":3135
-         }
-      ]
-   }
-
-query-iothreads
----------------
-
-Returns a list of information about each iothread.
-
-Note this list excludes the QEMU main loop thread, which is not declared
-using the -object iothread command-line option.  It is always the main thread
-of the process.
-
-Return a json-array. Each iothread is represented by a json-object, which contains:
-
-- "id": name of iothread (json-str)
-- "thread-id": ID of the underlying host thread (json-int)
-
-Example:
-
--> { "execute": "query-iothreads" }
-<- {
-      "return":[
-         {
-            "id":"iothread0",
-            "thread-id":3134
-         },
-         {
-            "id":"iothread1",
-            "thread-id":3135
-         }
-      ]
-   }
-
-query-pci
----------
-
-PCI buses and devices information.
-
-The returned value is a json-array of all buses. Each bus is represented by
-a json-object, which has a key with a json-array of all PCI devices attached
-to it. Each device is represented by a json-object.
-
-The bus json-object contains the following:
-
-- "bus": bus number (json-int)
-- "devices": a json-array of json-objects, each json-object represents a
-             PCI device
-
-The PCI device json-object contains the following:
-
-- "bus": identical to the parent's bus number (json-int)
-- "slot": slot number (json-int)
-- "function": function number (json-int)
-- "class_info": a json-object containing:
-     - "desc": device class description (json-string, optional)
-     - "class": device class number (json-int)
-- "id": a json-object containing:
-     - "device": device ID (json-int)
-     - "vendor": vendor ID (json-int)
-- "irq": device's IRQ if assigned (json-int, optional)
-- "qdev_id": qdev id string (json-string)
-- "pci_bridge": It's a json-object, only present if this device is a
-                PCI bridge, contains:
-     - "bus": bus number (json-int)
-     - "secondary": secondary bus number (json-int)
-     - "subordinate": subordinate bus number (json-int)
-     - "io_range": I/O memory range information, a json-object with the
-                   following members:
-                 - "base": base address, in bytes (json-int)
-                 - "limit": limit address, in bytes (json-int)
-     - "memory_range": memory range information, a json-object with the
-                       following members:
-                 - "base": base address, in bytes (json-int)
-                 - "limit": limit address, in bytes (json-int)
-     - "prefetchable_range": Prefetchable memory range information, a
-                             json-object with the following members:
-                 - "base": base address, in bytes (json-int)
-                 - "limit": limit address, in bytes (json-int)
-     - "devices": a json-array of PCI devices if there's any attached, each
-                  each element is represented by a json-object, which contains
-                  the same members of the 'PCI device json-object' described
-                  above (optional)
-- "regions": a json-array of json-objects, each json-object represents a
-             memory region of this device
-
-The memory range json-object contains the following:
-
-- "base": base memory address (json-int)
-- "limit": limit value (json-int)
-
-The region json-object can be an I/O region or a memory region, an I/O region
-json-object contains the following:
-
-- "type": "io" (json-string, fixed)
-- "bar": BAR number (json-int)
-- "address": memory address (json-int)
-- "size": memory size (json-int)
-
-A memory region json-object contains the following:
-
-- "type": "memory" (json-string, fixed)
-- "bar": BAR number (json-int)
-- "address": memory address (json-int)
-- "size": memory size (json-int)
-- "mem_type_64": true or false (json-bool)
-- "prefetch": true or false (json-bool)
-
-Example:
-
--> { "execute": "query-pci" }
-<- {
-      "return":[
-         {
-            "bus":0,
-            "devices":[
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":0,
-                  "class_info":{
-                     "class":1536,
-                     "desc":"Host bridge"
-                  },
-                  "id":{
-                     "device":32902,
-                     "vendor":4663
-                  },
-                  "function":0,
-                  "regions":[
-
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":1,
-                  "class_info":{
-                     "class":1537,
-                     "desc":"ISA bridge"
-                  },
-                  "id":{
-                     "device":32902,
-                     "vendor":28672
-                  },
-                  "function":0,
-                  "regions":[
-
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":1,
-                  "class_info":{
-                     "class":257,
-                     "desc":"IDE controller"
-                  },
-                  "id":{
-                     "device":32902,
-                     "vendor":28688
-                  },
-                  "function":1,
-                  "regions":[
-                     {
-                        "bar":4,
-                        "size":16,
-                        "address":49152,
-                        "type":"io"
-                     }
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":2,
-                  "class_info":{
-                     "class":768,
-                     "desc":"VGA controller"
-                  },
-                  "id":{
-                     "device":4115,
-                     "vendor":184
-                  },
-                  "function":0,
-                  "regions":[
-                     {
-                        "prefetch":true,
-                        "mem_type_64":false,
-                        "bar":0,
-                        "size":33554432,
-                        "address":4026531840,
-                        "type":"memory"
-                     },
-                     {
-                        "prefetch":false,
-                        "mem_type_64":false,
-                        "bar":1,
-                        "size":4096,
-                        "address":4060086272,
-                        "type":"memory"
-                     },
-                     {
-                        "prefetch":false,
-                        "mem_type_64":false,
-                        "bar":6,
-                        "size":65536,
-                        "address":-1,
-                        "type":"memory"
-                     }
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "irq":11,
-                  "slot":4,
-                  "class_info":{
-                     "class":1280,
-                     "desc":"RAM controller"
-                  },
-                  "id":{
-                     "device":6900,
-                     "vendor":4098
-                  },
-                  "function":0,
-                  "regions":[
-                     {
-                        "bar":0,
-                        "size":32,
-                        "address":49280,
-                        "type":"io"
-                     }
-                  ]
-               }
-            ]
-         }
-      ]
-   }
-
-Note: This example has been shortened as the real response is too long.
-
-query-kvm
----------
-
-Show KVM information.
-
-Return a json-object with the following information:
-
-- "enabled": true if KVM support is enabled, false otherwise (json-bool)
-- "present": true if QEMU has KVM support, false otherwise (json-bool)
-
-Example:
-
--> { "execute": "query-kvm" }
-<- { "return": { "enabled": true, "present": true } }
-
-query-status
-------------
-
-Return a json-object with the following information:
-
-- "running": true if the VM is running, or false if it is paused (json-bool)
-- "singlestep": true if the VM is in single step mode,
-                false otherwise (json-bool)
-- "status": one of the following values (json-string)
-    "debug" - QEMU is running on a debugger
-    "inmigrate" - guest is paused waiting for an incoming migration
-    "internal-error" - An internal error that prevents further guest
-    execution has occurred
-    "io-error" - the last IOP has failed and the device is configured
-    to pause on I/O errors
-    "paused" - guest has been paused via the 'stop' command
-    "postmigrate" - guest is paused following a successful 'migrate'
-    "prelaunch" - QEMU was started with -S and guest has not started
-    "finish-migrate" - guest is paused to finish the migration process
-    "restore-vm" - guest is paused to restore VM state
-    "running" - guest is actively running
-    "save-vm" - guest is paused to save the VM state
-    "shutdown" - guest is shut down (and -no-shutdown is in use)
-    "watchdog" - the watchdog action is configured to pause and
-     has been triggered
-
-Example:
-
--> { "execute": "query-status" }
-<- { "return": { "running": true, "singlestep": false, "status": "running" } }
-
-query-mice
-----------
-
-Show VM mice information.
-
-Each mouse is represented by a json-object, the returned value is a json-array
-of all mice.
-
-The mouse json-object contains the following:
-
-- "name": mouse's name (json-string)
-- "index": mouse's index (json-int)
-- "current": true if this mouse is receiving events, false otherwise (json-bool)
-- "absolute": true if the mouse generates absolute input events (json-bool)
-
-Example:
-
--> { "execute": "query-mice" }
-<- {
-      "return":[
-         {
-            "name":"QEMU Microsoft Mouse",
-            "index":0,
-            "current":false,
-            "absolute":false
-         },
-         {
-            "name":"QEMU PS/2 Mouse",
-            "index":1,
-            "current":true,
-            "absolute":true
-         }
-      ]
-   }
-
-query-vnc
----------
-
-Show VNC server information.
-
-Return a json-object with server information. Connected clients are returned
-as a json-array of json-objects.
-
-The main json-object contains the following:
-
-- "enabled": true or false (json-bool)
-- "host": server's IP address (json-string)
-- "family": address family (json-string)
-         - Possible values: "ipv4", "ipv6", "unix", "unknown"
-- "service": server's port number (json-string)
-- "auth": authentication method (json-string)
-         - Possible values: "invalid", "none", "ra2", "ra2ne", "sasl", "tight",
-                            "tls", "ultra", "unknown", "vencrypt", "vencrypt",
-                            "vencrypt+plain", "vencrypt+tls+none",
-                            "vencrypt+tls+plain", "vencrypt+tls+sasl",
-                            "vencrypt+tls+vnc", "vencrypt+x509+none",
-                            "vencrypt+x509+plain", "vencrypt+x509+sasl",
-                            "vencrypt+x509+vnc", "vnc"
-- "clients": a json-array of all connected clients
-
-Clients are described by a json-object, each one contain the following:
-
-- "host": client's IP address (json-string)
-- "family": address family (json-string)
-         - Possible values: "ipv4", "ipv6", "unix", "unknown"
-- "service": client's port number (json-string)
-- "x509_dname": TLS dname (json-string, optional)
-- "sasl_username": SASL username (json-string, optional)
-
-Example:
-
--> { "execute": "query-vnc" }
-<- {
-      "return":{
-         "enabled":true,
-         "host":"0.0.0.0",
-         "service":"50402",
-         "auth":"vnc",
-         "family":"ipv4",
-         "clients":[
-            {
-               "host":"127.0.0.1",
-               "service":"50401",
-               "family":"ipv4"
-            }
-         ]
-      }
-   }
-
-query-spice
------------
-
-Show SPICE server information.
-
-Return a json-object with server information. Connected clients are returned
-as a json-array of json-objects.
-
-The main json-object contains the following:
-
-- "enabled": true or false (json-bool)
-- "host": server's IP address (json-string)
-- "port": server's port number (json-int, optional)
-- "tls-port": server's port number (json-int, optional)
-- "auth": authentication method (json-string)
-         - Possible values: "none", "spice"
-- "channels": a json-array of all active channels clients
-
-Channels are described by a json-object, each one contain the following:
-
-- "host": client's IP address (json-string)
-- "family": address family (json-string)
-         - Possible values: "ipv4", "ipv6", "unix", "unknown"
-- "port": client's port number (json-string)
-- "connection-id": spice connection id.  All channels with the same id
-                   belong to the same spice session (json-int)
-- "channel-type": channel type.  "1" is the main control channel, filter for
-                  this one if you want track spice sessions only (json-int)
-- "channel-id": channel id.  Usually "0", might be different needed when
-                multiple channels of the same type exist, such as multiple
-                display channels in a multihead setup (json-int)
-- "tls": whether the channel is encrypted (json-bool)
-
-Example:
-
--> { "execute": "query-spice" }
-<- {
-      "return": {
-         "enabled": true,
-         "auth": "spice",
-         "port": 5920,
-         "tls-port": 5921,
-         "host": "0.0.0.0",
-         "channels": [
-            {
-               "port": "54924",
-               "family": "ipv4",
-               "channel-type": 1,
-               "connection-id": 1804289383,
-               "host": "127.0.0.1",
-               "channel-id": 0,
-               "tls": true
-            },
-            {
-               "port": "36710",
-               "family": "ipv4",
-               "channel-type": 4,
-               "connection-id": 1804289383,
-               "host": "127.0.0.1",
-               "channel-id": 0,
-               "tls": false
-            },
-            [ ... more channels follow ... ]
-         ]
-      }
-   }
-
-query-name
-----------
-
-Show VM name.
-
-Return a json-object with the following information:
-
-- "name": VM's name (json-string, optional)
-
-Example:
-
--> { "execute": "query-name" }
-<- { "return": { "name": "qemu-name" } }
-
-query-uuid
-----------
-
-Show VM UUID.
-
-Return a json-object with the following information:
-
-- "UUID": Universally Unique Identifier (json-string)
-
-Example:
-
--> { "execute": "query-uuid" }
-<- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
-
-query-command-line-options
---------------------------
-
-Show command line option schema.
-
-Return a json-array of command line option schema for all options (or for
-the given option), returning an error if the given option doesn't exist.
-
-Each array entry contains the following:
-
-- "option": option name (json-string)
-- "parameters": a json-array describes all parameters of the option:
-    - "name": parameter name (json-string)
-    - "type": parameter type (one of 'string', 'boolean', 'number',
-              or 'size')
-    - "help": human readable description of the parameter
-              (json-string, optional)
-    - "default": default value string for the parameter
-                 (json-string, optional)
-
-Example:
-
--> { "execute": "query-command-line-options", "arguments": { "option": "option-rom" } }
-<- { "return": [
-        {
-            "parameters": [
-                {
-                    "name": "romfile",
-                    "type": "string"
-                },
-                {
-                    "name": "bootindex",
-                    "type": "number"
-                }
-            ],
-            "option": "option-rom"
-        }
-     ]
-   }
-
-query-migrate
--------------
-
-Migration status.
-
-Return a json-object. If migration is active there will be another json-object
-with RAM migration status and if block migration is active another one with
-block migration status.
-
-The main json-object contains the following:
-
-- "status": migration status (json-string)
-     - Possible values: "setup", "active", "completed", "failed", "cancelled"
-- "total-time": total amount of ms since migration started.  If
-                migration has ended, it returns the total migration
-                time (json-int)
-- "setup-time" amount of setup time in milliseconds _before_ the
-               iterations begin but _after_ the QMP command is issued.
-               This is designed to provide an accounting of any activities
-               (such as RDMA pinning) which may be expensive, but do not
-               actually occur during the iterative migration rounds
-               themselves. (json-int)
-- "downtime": only present when migration has finished correctly
-              total amount in ms for downtime that happened (json-int)
-- "expected-downtime": only present while migration is active
-                total amount in ms for downtime that was calculated on
-                the last bitmap round (json-int)
-- "ram": only present if "status" is "active", it is a json-object with the
-  following RAM information:
-         - "transferred": amount transferred in bytes (json-int)
-         - "remaining": amount remaining to transfer in bytes (json-int)
-         - "total": total amount of memory in bytes (json-int)
-         - "duplicate": number of pages filled entirely with the same
-            byte (json-int)
-            These are sent over the wire much more efficiently.
-         - "skipped": number of skipped zero pages (json-int)
-         - "normal" : number of whole pages transferred.  I.e. they
-            were not sent as duplicate or xbzrle pages (json-int)
-         - "normal-bytes" : number of bytes transferred in whole
-            pages. This is just normal pages times size of one page,
-            but this way upper levels don't need to care about page
-            size (json-int)
-         - "dirty-sync-count": times that dirty ram was synchronized (json-int)
-- "disk": only present if "status" is "active" and it is a block migration,
-  it is a json-object with the following disk information:
-         - "transferred": amount transferred in bytes (json-int)
-         - "remaining": amount remaining to transfer in bytes json-int)
-         - "total": total disk size in bytes (json-int)
-- "xbzrle-cache": only present if XBZRLE is active.
-  It is a json-object with the following XBZRLE information:
-         - "cache-size": XBZRLE cache size in bytes
-         - "bytes": number of bytes transferred for XBZRLE compressed pages
-         - "pages": number of XBZRLE compressed pages
-         - "cache-miss": number of XBRZRLE page cache misses
-         - "cache-miss-rate": rate of XBRZRLE page cache misses
-         - "overflow": number of times XBZRLE overflows.  This means
-           that the XBZRLE encoding was bigger than just sent the
-           whole page, and then we sent the whole page instead (as as
-           normal page).
-
-Examples:
-
-1. Before the first migration
-
--> { "execute": "query-migrate" }
-<- { "return": {} }
-
-2. Migration is done and has succeeded
-
--> { "execute": "query-migrate" }
-<- { "return": {
-        "status": "completed",
-        "ram":{
-          "transferred":123,
-          "remaining":123,
-          "total":246,
-          "total-time":12345,
-          "setup-time":12345,
-          "downtime":12345,
-          "duplicate":123,
-          "normal":123,
-          "normal-bytes":123456,
-          "dirty-sync-count":15
-        }
-     }
-   }
-
-3. Migration is done and has failed
-
--> { "execute": "query-migrate" }
-<- { "return": { "status": "failed" } }
-
-4. Migration is being performed and is not a block migration:
-
--> { "execute": "query-migrate" }
-<- {
-      "return":{
-         "status":"active",
-         "ram":{
-            "transferred":123,
-            "remaining":123,
-            "total":246,
-            "total-time":12345,
-            "setup-time":12345,
-            "expected-downtime":12345,
-            "duplicate":123,
-            "normal":123,
-            "normal-bytes":123456,
-            "dirty-sync-count":15
-         }
-      }
-   }
-
-5. Migration is being performed and is a block migration:
-
--> { "execute": "query-migrate" }
-<- {
-      "return":{
-         "status":"active",
-         "ram":{
-            "total":1057024,
-            "remaining":1053304,
-            "transferred":3720,
-            "total-time":12345,
-            "setup-time":12345,
-            "expected-downtime":12345,
-            "duplicate":123,
-            "normal":123,
-            "normal-bytes":123456,
-            "dirty-sync-count":15
-         },
-         "disk":{
-            "total":20971520,
-            "remaining":20880384,
-            "transferred":91136
-         }
-      }
-   }
-
-6. Migration is being performed and XBZRLE is active:
-
--> { "execute": "query-migrate" }
-<- {
-      "return":{
-         "status":"active",
-         "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
-         "ram":{
-            "total":1057024,
-            "remaining":1053304,
-            "transferred":3720,
-            "total-time":12345,
-            "setup-time":12345,
-            "expected-downtime":12345,
-            "duplicate":10,
-            "normal":3333,
-            "normal-bytes":3412992,
-            "dirty-sync-count":15
-         },
-         "xbzrle-cache":{
-            "cache-size":67108864,
-            "bytes":20971520,
-            "pages":2444343,
-            "cache-miss":2244,
-            "cache-miss-rate":0.123,
-            "overflow":34434
-         }
-      }
-   }
-
-migrate-set-capabilities
-------------------------
-
-Enable/Disable migration capabilities
-
-- "xbzrle": XBZRLE support
-- "rdma-pin-all": pin all pages when using RDMA during migration
-- "auto-converge": throttle down guest to help convergence of migration
-- "zero-blocks": compress zero blocks during block migration
-- "compress": use multiple compression threads to accelerate live migration
-- "events": generate events for each migration state change
-- "postcopy-ram": postcopy mode for live migration
-
-Arguments:
-
-Example:
-
--> { "execute": "migrate-set-capabilities" , "arguments":
-     { "capabilities": [ { "capability": "xbzrle", "state": true } ] } }
-
-query-migrate-capabilities
---------------------------
-
-Query current migration capabilities
-
-- "capabilities": migration capabilities state
-         - "xbzrle" : XBZRLE state (json-bool)
-         - "rdma-pin-all" : RDMA Pin Page state (json-bool)
-         - "auto-converge" : Auto Converge state (json-bool)
-         - "zero-blocks" : Zero Blocks state (json-bool)
-         - "compress": Multiple compression threads state (json-bool)
-         - "events": Migration state change event state (json-bool)
-         - "postcopy-ram": postcopy ram state (json-bool)
-
-Arguments:
-
-Example:
-
--> { "execute": "query-migrate-capabilities" }
-<- {"return": [
-     {"state": false, "capability": "xbzrle"},
-     {"state": false, "capability": "rdma-pin-all"},
-     {"state": false, "capability": "auto-converge"},
-     {"state": false, "capability": "zero-blocks"},
-     {"state": false, "capability": "compress"},
-     {"state": true, "capability": "events"},
-     {"state": false, "capability": "postcopy-ram"}
-   ]}
-
-migrate-set-parameters
-----------------------
-
-Set migration parameters
-
-- "compress-level": set compression level during migration (json-int)
-- "compress-threads": set compression thread count for migration (json-int)
-- "decompress-threads": set decompression thread count for migration (json-int)
-- "cpu-throttle-initial": set initial percentage of time guest cpus are
-                          throttled for auto-converge (json-int)
-- "cpu-throttle-increment": set throttle increasing percentage for
-                            auto-converge (json-int)
-
-Arguments:
-
-Example:
-
--> { "execute": "migrate-set-parameters" , "arguments":
-      { "compress-level": 1 } }
-
-query-migrate-parameters
-------------------------
-
-Query current migration parameters
-
-- "parameters": migration parameters value
-         - "compress-level" : compression level value (json-int)
-         - "compress-threads" : compression thread count value (json-int)
-         - "decompress-threads" : decompression thread count value (json-int)
-         - "cpu-throttle-initial" : initial percentage of time guest cpus are
-                                    throttled (json-int)
-         - "cpu-throttle-increment" : throttle increasing percentage for
-                                      auto-converge (json-int)
-
-Arguments:
-
-Example:
-
--> { "execute": "query-migrate-parameters" }
-<- {
-      "return": {
-         "decompress-threads": 2,
-         "cpu-throttle-increment": 10,
-         "compress-threads": 8,
-         "compress-level": 1,
-         "cpu-throttle-initial": 20
-      }
-   }
-
-query-balloon
--------------
-
-Show balloon information.
-
-Make an asynchronous request for balloon info. When the request completes a
-json-object will be returned containing the following data:
-
-- "actual": current balloon value in bytes (json-int)
-
-Example:
-
--> { "execute": "query-balloon" }
-<- {
-      "return":{
-         "actual":1073741824,
-      }
-   }
-
-query-tpm
----------
-
-Return information about the TPM device.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-tpm" }
-<- { "return":
-     [
-       { "model": "tpm-tis",
-         "options":
-           { "type": "passthrough",
-             "data":
-               { "cancel-path": "/sys/class/misc/tpm0/device/cancel",
-                 "path": "/dev/tpm0"
-               }
-           },
-         "id": "tpm0"
-       }
-     ]
-   }
-
-query-tpm-models
-----------------
-
-Return a list of supported TPM models.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-tpm-models" }
-<- { "return": [ "tpm-tis" ] }
-
-query-tpm-types
----------------
-
-Return a list of supported TPM types.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-tpm-types" }
-<- { "return": [ "passthrough" ] }
-
-chardev-add
-----------------
-
-Add a chardev.
-
-Arguments:
-
-- "id": the chardev's ID, must be unique (json-string)
-- "backend": chardev backend type + parameters
-
-Examples:
-
--> { "execute" : "chardev-add",
-     "arguments" : { "id" : "foo",
-                     "backend" : { "type" : "null", "data" : {} } } }
-<- { "return": {} }
-
--> { "execute" : "chardev-add",
-     "arguments" : { "id" : "bar",
-                     "backend" : { "type" : "file",
-                                   "data" : { "out" : "/tmp/bar.log" } } } }
-<- { "return": {} }
-
--> { "execute" : "chardev-add",
-     "arguments" : { "id" : "baz",
-                     "backend" : { "type" : "pty", "data" : {} } } }
-<- { "return": { "pty" : "/dev/pty/42" } }
-
-chardev-remove
---------------
-
-Remove a chardev.
-
-Arguments:
-
-- "id": the chardev's ID, must exist and not be in use (json-string)
-
-Example:
-
--> { "execute": "chardev-remove", "arguments": { "id" : "foo" } }
-<- { "return": {} }
-
-query-rx-filter
----------------
-
-Show rx-filter information.
-
-Returns a json-array of rx-filter information for all NICs (or for the
-given NIC), returning an error if the given NIC doesn't exist, or
-given NIC doesn't support rx-filter querying, or given net client
-isn't a NIC.
-
-The query will clear the event notification flag of each NIC, then qemu
-will start to emit event to QMP monitor.
-
-Each array entry contains the following:
-
-- "name": net client name (json-string)
-- "promiscuous": promiscuous mode is enabled (json-bool)
-- "multicast": multicast receive state (one of 'normal', 'none', 'all')
-- "unicast": unicast receive state  (one of 'normal', 'none', 'all')
-- "vlan": vlan receive state (one of 'normal', 'none', 'all') (Since 2.0)
-- "broadcast-allowed": allow to receive broadcast (json-bool)
-- "multicast-overflow": multicast table is overflowed (json-bool)
-- "unicast-overflow": unicast table is overflowed (json-bool)
-- "main-mac": main macaddr string (json-string)
-- "vlan-table": a json-array of active vlan id
-- "unicast-table": a json-array of unicast macaddr string
-- "multicast-table": a json-array of multicast macaddr string
-
-Example:
-
--> { "execute": "query-rx-filter", "arguments": { "name": "vnet0" } }
-<- { "return": [
-        {
-            "promiscuous": true,
-            "name": "vnet0",
-            "main-mac": "52:54:00:12:34:56",
-            "unicast": "normal",
-            "vlan": "normal",
-            "vlan-table": [
-                4,
-                0
-            ],
-            "unicast-table": [
-            ],
-            "multicast": "normal",
-            "multicast-overflow": false,
-            "unicast-overflow": false,
-            "multicast-table": [
-                "01:00:5e:00:00:01",
-                "33:33:00:00:00:01",
-                "33:33:ff:12:34:56"
-            ],
-            "broadcast-allowed": false
-        }
-      ]
-   }
-
-blockdev-add
-------------
-
-Add a block device.
-
-This command is still a work in progress.  It doesn't support all
-block drivers among other things.  Stay away from it unless you want
-to help with its development.
-
-Arguments:
-
-- "options": block driver options
-
-Example (1):
-
--> { "execute": "blockdev-add",
-    "arguments": { "options" : { "driver": "qcow2",
-                                 "file": { "driver": "file",
-                                           "filename": "test.qcow2" } } } }
-<- { "return": {} }
-
-Example (2):
-
--> { "execute": "blockdev-add",
-     "arguments": {
-         "options": {
-           "driver": "qcow2",
-           "node-name": "my_disk",
-           "discard": "unmap",
-           "cache": {
-               "direct": true,
-               "writeback": true
-           },
-           "file": {
-               "driver": "file",
-               "filename": "/tmp/test.qcow2"
-           },
-           "backing": {
-               "driver": "raw",
-               "file": {
-                   "driver": "file",
-                   "filename": "/dev/fdset/4"
-               }
-           }
-         }
-       }
-     }
-
-<- { "return": {} }
-
-x-blockdev-del
-------------
-Since 2.5
-
-Deletes a block device that has been added using blockdev-add.
-The command will fail if the node is attached to a device or is
-otherwise being used.
-
-This command is still a work in progress and is considered
-experimental. Stay away from it unless you want to help with its
-development.
-
-Arguments:
-
-- "node-name": Name of the graph node to delete (json-string)
-
-Example:
-
--> { "execute": "blockdev-add",
-     "arguments": {
-         "options": {
-             "driver": "qcow2",
-             "node-name": "node0",
-             "file": {
-                 "driver": "file",
-                 "filename": "test.qcow2"
-             }
-         }
-     }
-   }
-
-<- { "return": {} }
-
--> { "execute": "x-blockdev-del",
-     "arguments": { "node-name": "node0" }
-   }
-<- { "return": {} }
-
-blockdev-open-tray
-------------------
-
-Opens a block device's tray. If there is a block driver state tree inserted as a
-medium, it will become inaccessible to the guest (but it will remain associated
-to the block device, so closing the tray will make it accessible again).
-
-If the tray was already open before, this will be a no-op.
-
-Once the tray opens, a DEVICE_TRAY_MOVED event is emitted. There are cases in
-which no such event will be generated, these include:
-- if the guest has locked the tray, @force is false and the guest does not
-  respond to the eject request
-- if the BlockBackend denoted by @device does not have a guest device attached
-  to it
-- if the guest device does not have an actual tray and is empty, for instance
-  for floppy disk drives
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "force": if false (the default), an eject request will be sent to the guest if
-           it has locked the tray (and the tray will not be opened immediately);
-           if true, the tray will be opened regardless of whether it is locked
-           (json-bool, optional)
-
-Example:
-
--> { "execute": "blockdev-open-tray",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "timestamp": { "seconds": 1418751016,
-                    "microseconds": 716996 },
-     "event": "DEVICE_TRAY_MOVED",
-     "data": { "device": "ide1-cd0",
-               "tray-open": true } }
-
-<- { "return": {} }
-
-blockdev-close-tray
--------------------
-
-Closes a block device's tray. If there is a block driver state tree associated
-with the block device (which is currently ejected), that tree will be loaded as
-the medium.
-
-If the tray was already closed before, this will be a no-op.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-
-Example:
-
--> { "execute": "blockdev-close-tray",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "timestamp": { "seconds": 1418751345,
-                    "microseconds": 272147 },
-     "event": "DEVICE_TRAY_MOVED",
-     "data": { "device": "ide1-cd0",
-               "tray-open": false } }
-
-<- { "return": {} }
-
-x-blockdev-remove-medium
-------------------------
-
-Removes a medium (a block driver state tree) from a block device. That block
-device's tray must currently be open (unless there is no attached guest device).
-
-If the tray is open and there is no medium inserted, this will be a no-op.
-
-This command is still a work in progress and is considered experimental.
-Stay away from it unless you want to help with its development.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-
-Example:
-
--> { "execute": "x-blockdev-remove-medium",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "error": { "class": "GenericError",
-                "desc": "Tray of device 'ide0-1-0' is not open" } }
-
--> { "execute": "blockdev-open-tray",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "timestamp": { "seconds": 1418751627,
-                    "microseconds": 549958 },
-     "event": "DEVICE_TRAY_MOVED",
-     "data": { "device": "ide1-cd0",
-               "tray-open": true } }
-
-<- { "return": {} }
-
--> { "execute": "x-blockdev-remove-medium",
-     "arguments": { "device": "ide0-1-0" } }
-
-<- { "return": {} }
-
-x-blockdev-insert-medium
-------------------------
-
-Inserts a medium (a block driver state tree) into a block device. That block
-device's tray must currently be open (unless there is no attached guest device)
-and there must be no medium inserted already.
-
-This command is still a work in progress and is considered experimental.
-Stay away from it unless you want to help with its development.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "node-name": root node of the BDS tree to insert into the block device
-
-Example:
-
--> { "execute": "blockdev-add",
-     "arguments": { "options": { "node-name": "node0",
-                                 "driver": "raw",
-                                 "file": { "driver": "file",
-                                           "filename": "fedora.iso" } } } }
-
-<- { "return": {} }
-
--> { "execute": "x-blockdev-insert-medium",
-     "arguments": { "id": "ide0-1-0",
-                    "node-name": "node0" } }
-
-<- { "return": {} }
-
-x-blockdev-change
------------------
-
-Dynamically reconfigure the block driver state graph. It can be used
-to add, remove, insert or replace a graph node. Currently only the
-Quorum driver implements this feature to add or remove its child. This
-is useful to fix a broken quorum child.
-
-If @node is specified, it will be inserted under @parent. @child
-may not be specified in this case. If both @parent and @child are
-specified but @node is not, @child will be detached from @parent.
-
-Arguments:
-- "parent": the id or name of the parent node (json-string)
-- "child": the name of a child under the given parent node (json-string, optional)
-- "node": the name of the node that will be added (json-string, optional)
-
-Note: this command is experimental, and not a stable API. It doesn't
-support all kinds of operations, all kinds of children, nor all block
-drivers.
-
-Warning: The data in a new quorum child MUST be consistent with that of
-the rest of the array.
-
-Example:
-
-Add a new node to a quorum
--> { "execute": "blockdev-add",
-     "arguments": { "options": { "driver": "raw",
-                                 "node-name": "new_node",
-                                 "file": { "driver": "file",
-                                           "filename": "test.raw" } } } }
-<- { "return": {} }
--> { "execute": "x-blockdev-change",
-     "arguments": { "parent": "disk1",
-                    "node": "new_node" } }
-<- { "return": {} }
-
-Delete a quorum's node
--> { "execute": "x-blockdev-change",
-     "arguments": { "parent": "disk1",
-                    "child": "children.1" } }
-<- { "return": {} }
-
-query-named-block-nodes
------------------------
-
-Return a list of BlockDeviceInfo for all the named block driver nodes
-
-Example:
-
--> { "execute": "query-named-block-nodes" }
-<- { "return": [ { "ro":false,
-                   "drv":"qcow2",
-                   "encrypted":false,
-                   "file":"disks/test.qcow2",
-                   "node-name": "my-node",
-                   "backing_file_depth":1,
-                   "bps":1000000,
-                   "bps_rd":0,
-                   "bps_wr":0,
-                   "iops":1000000,
-                   "iops_rd":0,
-                   "iops_wr":0,
-                   "bps_max": 8000000,
-                   "bps_rd_max": 0,
-                   "bps_wr_max": 0,
-                   "iops_max": 0,
-                   "iops_rd_max": 0,
-                   "iops_wr_max": 0,
-                   "iops_size": 0,
-                   "write_threshold": 0,
-                   "image":{
-                      "filename":"disks/test.qcow2",
-                      "format":"qcow2",
-                      "virtual-size":2048000,
-                      "backing_file":"base.qcow2",
-                      "full-backing-filename":"disks/base.qcow2",
-                      "backing-filename-format":"qcow2",
-                      "snapshots":[
-                         {
-                            "id": "1",
-                            "name": "snapshot1",
-                            "vm-state-size": 0,
-                            "date-sec": 10000200,
-                            "date-nsec": 12,
-                            "vm-clock-sec": 206,
-                            "vm-clock-nsec": 30
-                         }
-                      ],
-                      "backing-image":{
-                          "filename":"disks/base.qcow2",
-                          "format":"qcow2",
-                          "virtual-size":2048000
-                      }
-                   } } ] }
-
-blockdev-change-medium
-----------------------
-
-Changes the medium inserted into a block device by ejecting the current medium
-and loading a new image file which is inserted as the new medium.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "filename": filename of the new image (json-string)
-- "format": format of the new image (json-string, optional)
-- "read-only-mode": new read-only mode (json-string, optional)
-          - Possible values: "retain" (default), "read-only", "read-write"
-
-Examples:
-
-1. Change a removable medium
-
--> { "execute": "blockdev-change-medium",
-             "arguments": { "id": "ide0-1-0",
-                            "filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
-                            "format": "raw" } }
-<- { "return": {} }
-
-2. Load a read-only medium into a writable drive
-
--> { "execute": "blockdev-change-medium",
-             "arguments": { "id": "floppyA",
-                            "filename": "/srv/images/ro.img",
-                            "format": "raw",
-                            "read-only-mode": "retain" } }
-
-<- { "error":
-     { "class": "GenericError",
-       "desc": "Could not open '/srv/images/ro.img': Permission denied" } }
-
--> { "execute": "blockdev-change-medium",
-             "arguments": { "id": "floppyA",
-                            "filename": "/srv/images/ro.img",
-                            "format": "raw",
-                            "read-only-mode": "read-only" } }
-
-<- { "return": {} }
-
-query-memdev
-------------
-
-Show memory devices information.
-
-
-Example (1):
-
--> { "execute": "query-memdev" }
-<- { "return": [
-       {
-         "size": 536870912,
-         "merge": false,
-         "dump": true,
-         "prealloc": false,
-         "host-nodes": [0, 1],
-         "policy": "bind"
-       },
-       {
-         "size": 536870912,
-         "merge": false,
-         "dump": true,
-         "prealloc": true,
-         "host-nodes": [2, 3],
-         "policy": "preferred"
-       }
-     ]
-   }
-
-query-memory-devices
---------------------
-
-Return a list of memory devices.
-
-Example:
--> { "execute": "query-memory-devices" }
-<- { "return": [ { "data":
-                      { "addr": 5368709120,
-                        "hotpluggable": true,
-                        "hotplugged": true,
-                        "id": "d1",
-                        "memdev": "/objects/memX",
-                        "node": 0,
-                        "size": 1073741824,
-                        "slot": 0},
-                   "type": "dimm"
-                 } ] }
-
-query-acpi-ospm-status
-----------------------
-
-Return list of ACPIOSTInfo for devices that support status reporting
-via ACPI _OST method.
-
-Example:
--> { "execute": "query-acpi-ospm-status" }
-<- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
-                 { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
-                 { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
-                 { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
-   ]}
-
-rtc-reset-reinjection
----------------------
-
-Reset the RTC interrupt reinjection backlog.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "rtc-reset-reinjection" }
-<- { "return": {} }
-
-trace-event-get-state
----------------------
-
-Query the state of events.
-
-Arguments:
-
-- "name": Event name pattern (json-string).
-- "vcpu": The vCPU to query, any vCPU by default (json-int, optional).
-
-An event is returned if:
-- its name matches the "name" pattern, and
-- if "vcpu" is given, the event has the "vcpu" property.
-
-Therefore, if "vcpu" is given, the operation will only match per-vCPU events,
-returning their state on the specified vCPU. Special case: if "name" is an exact
-match, "vcpu" is given and the event does not have the "vcpu" property, an error
-is returned.
-
-Example:
-
--> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } }
-<- { "return": [ { "name": "qemu_memalign", "state": "disabled" } ] }
-
-trace-event-set-state
----------------------
-
-Set the state of events.
-
-Arguments:
-
-- "name": Event name pattern (json-string).
-- "enable": Whether to enable or disable the event (json-bool).
-- "ignore-unavailable": Whether to ignore errors for events that cannot be
-  changed (json-bool, optional).
-- "vcpu": The vCPU to act upon, all vCPUs by default (json-int, optional).
-
-An event's state is modified if:
-- its name matches the "name" pattern, and
-- if "vcpu" is given, the event has the "vcpu" property.
-
-Therefore, if "vcpu" is given, the operation will only match per-vCPU events,
-setting their state on the specified vCPU. Special case: if "name" is an exact
-match, "vcpu" is given and the event does not have the "vcpu" property, an error
-is returned.
-
-Example:
-
--> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } }
-<- { "return": {} }
-
-input-send-event
-----------------
-
-Send input event to guest.
-
-Arguments:
-
-- "device": display device (json-string, optional)
-- "head": display head (json-int, optional)
-- "events": list of input events
-
-The consoles are visible in the qom tree, under
-/backend/console[$index]. They have a device link and head property, so
-it is possible to map which console belongs to which device and display.
-
-Example (1):
-
-Press left mouse button.
-
--> { "execute": "input-send-event",
-    "arguments": { "device": "video0",
-                   "events": [ { "type": "btn",
-                   "data" : { "down": true, "button": "left" } } ] } }
-<- { "return": {} }
-
--> { "execute": "input-send-event",
-    "arguments": { "device": "video0",
-                   "events": [ { "type": "btn",
-                   "data" : { "down": false, "button": "left" } } ] } }
-<- { "return": {} }
-
-Example (2):
-
-Press ctrl-alt-del.
-
--> { "execute": "input-send-event",
-     "arguments": { "events": [
-        { "type": "key", "data" : { "down": true,
-          "key": {"type": "qcode", "data": "ctrl" } } },
-        { "type": "key", "data" : { "down": true,
-          "key": {"type": "qcode", "data": "alt" } } },
-        { "type": "key", "data" : { "down": true,
-          "key": {"type": "qcode", "data": "delete" } } } ] } }
-<- { "return": {} }
-
-Example (3):
-
-Move mouse pointer to absolute coordinates (20000, 400).
-
--> { "execute": "input-send-event" ,
-  "arguments": { "events": [
-               { "type": "abs", "data" : { "axis": "x", "value" : 20000 } },
-               { "type": "abs", "data" : { "axis": "y", "value" : 400 } } ] } }
-<- { "return": {} }
-
-block-set-write-threshold
-------------
-
-Change the write threshold for a block drive. The threshold is an offset,
-thus must be non-negative. Default is no write threshold.
-Setting the threshold to zero disables it.
-
-Arguments:
-
-- "node-name": the node name in the block driver state graph (json-string)
-- "write-threshold": the write threshold in bytes (json-int)
-
-Example:
-
--> { "execute": "block-set-write-threshold",
-  "arguments": { "node-name": "mydev",
-                 "write-threshold": 17179869184 } }
-<- { "return": {} }
-
-Show rocker switch
-------------------
-
-Arguments:
-
-- "name": switch name
-
-Example:
-
--> { "execute": "query-rocker", "arguments": { "name": "sw1" } }
-<- { "return": {"name": "sw1", "ports": 2, "id": 1327446905938}}
-
-Show rocker switch ports
-------------------------
-
-Arguments:
-
-- "name": switch name
-
-Example:
-
--> { "execute": "query-rocker-ports", "arguments": { "name": "sw1" } }
-<- { "return": [ {"duplex": "full", "enabled": true, "name": "sw1.1",
-                  "autoneg": "off", "link-up": true, "speed": 10000},
-                 {"duplex": "full", "enabled": true, "name": "sw1.2",
-                  "autoneg": "off", "link-up": true, "speed": 10000}
-   ]}
-
-Show rocker switch OF-DPA flow tables
--------------------------------------
-
-Arguments:
-
-- "name": switch name
-- "tbl-id": (optional) flow table ID
-
-Example:
-
--> { "execute": "query-rocker-of-dpa-flows", "arguments": { "name": "sw1" } }
-<- { "return": [ {"key": {"in-pport": 0, "priority": 1, "tbl-id": 0},
-                  "hits": 138,
-                  "cookie": 0,
-                  "action": {"goto-tbl": 10},
-                  "mask": {"in-pport": 4294901760}
-                 },
-                 {...more...},
-   ]}
-
-Show rocker OF-DPA group tables
--------------------------------
-
-Arguments:
-
-- "name": switch name
-- "type": (optional) group type
-
-Example:
-
--> { "execute": "query-rocker-of-dpa-groups", "arguments": { "name": "sw1" } }
-<- { "return": [ {"type": 0, "out-pport": 2, "pport": 2, "vlan-id": 3841,
-                  "pop-vlan": 1, "id": 251723778},
-                 {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3841,
-                  "pop-vlan": 1, "id": 251723776},
-                 {"type": 0, "out-pport": 1, "pport": 1, "vlan-id": 3840,
-                  "pop-vlan": 1, "id": 251658241},
-                 {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3840,
-                  "pop-vlan": 1, "id": 251658240}
-   ]}
-
-query-gic-capabilities
----------------
-
-Return a list of GICCapability objects, describing supported GIC
-(Generic Interrupt Controller) versions.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-gic-capabilities" }
-<- { "return": [{ "version": 2, "emulated": true, "kernel": false },
-                { "version": 3, "emulated": false, "kernel": true } ] }
-
-Show existing/possible CPUs
----------------------------
-
-Arguments: None.
-
-Example for pseries machine type started with
--smp 2,cores=2,maxcpus=4 -cpu POWER8:
-
--> { "execute": "query-hotpluggable-cpus" }
-<- {"return": [
-     { "props": { "core-id": 8 }, "type": "POWER8-spapr-cpu-core",
-       "vcpus-count": 1 },
-     { "props": { "core-id": 0 }, "type": "POWER8-spapr-cpu-core",
-       "vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
-   ]}'
-
-Example for pc machine type started with
--smp 1,maxcpus=2:
-    -> { "execute": "query-hotpluggable-cpus" }
-    <- {"return": [
-         {
-            "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
-            "props": {"core-id": 0, "socket-id": 1, "thread-id": 0}
-         },
-         {
-            "qom-path": "/machine/unattached/device[0]",
-            "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
-            "props": {"core-id": 0, "socket-id": 0, "thread-id": 0}
-         }
-       ]}
diff --git a/docs/qmp-events.txt b/docs/qmp-events.txt
index 7967ec4..5888b71 100644
--- a/docs/qmp-events.txt
+++ b/docs/qmp-events.txt
@@ -1,721 +1,2 @@
                    QEMU Machine Protocol Events
                    ============================
-
-ACPI_DEVICE_OST
----------------
-
-Emitted when guest executes ACPI _OST method.
-
- - data: ACPIOSTInfo type as described in qapi-schema.json
-
-{ "event": "ACPI_DEVICE_OST",
-     "data": { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0 } }
-
-BALLOON_CHANGE
---------------
-
-Emitted when the guest changes the actual BALLOON level. This
-value is equivalent to the 'actual' field return by the
-'query-balloon' command
-
-Data:
-
-- "actual": actual level of the guest memory balloon in bytes (json-number)
-
-Example:
-
-{ "event": "BALLOON_CHANGE",
-    "data": { "actual": 944766976 },
-    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-
-Note: this event is rate-limited.
-
-BLOCK_IMAGE_CORRUPTED
----------------------
-
-Emitted when a disk image is being marked corrupt. The image can be
-identified by its device or node name. The 'device' field is always
-present for compatibility reasons, but it can be empty ("") if the
-image does not have a device name associated.
-
-Data:
-
-- "device":    Device name (json-string)
-- "node-name": Node name (json-string, optional)
-- "msg":       Informative message (e.g., reason for the corruption)
-               (json-string)
-- "offset":    If the corruption resulted from an image access, this
-               is the host's access offset into the image
-               (json-int, optional)
-- "size":      If the corruption resulted from an image access, this
-               is the access size (json-int, optional)
-
-Example:
-
-{ "event": "BLOCK_IMAGE_CORRUPTED",
-    "data": { "device": "ide0-hd0", "node-name": "node0",
-        "msg": "Prevented active L1 table overwrite", "offset": 196608,
-        "size": 65536 },
-    "timestamp": { "seconds": 1378126126, "microseconds": 966463 } }
-
-BLOCK_IO_ERROR
---------------
-
-Emitted when a disk I/O error occurs.
-
-Data:
-
-- "device": device name (json-string)
-- "operation": I/O operation (json-string, "read" or "write")
-- "action": action that has been taken, it's one of the following (json-string):
-    "ignore": error has been ignored
-    "report": error has been reported to the device
-    "stop": the VM is going to stop because of the error
-
-Example:
-
-{ "event": "BLOCK_IO_ERROR",
-    "data": { "device": "ide0-hd1",
-              "operation": "write",
-              "action": "stop" },
-    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-Note: If action is "stop", a STOP event will eventually follow the
-BLOCK_IO_ERROR event.
-
-BLOCK_JOB_CANCELLED
--------------------
-
-Emitted when a block job has been cancelled.
-
-Data:
-
-- "type":     Job type (json-string; "stream" for image streaming
-                                     "commit" for block commit)
-- "device":   Job identifier. Originally the device name but other
-              values are allowed since QEMU 2.7 (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-
-Example:
-
-{ "event": "BLOCK_JOB_CANCELLED",
-     "data": { "type": "stream", "device": "virtio-disk0",
-               "len": 10737418240, "offset": 134217728,
-               "speed": 0 },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-BLOCK_JOB_COMPLETED
--------------------
-
-Emitted when a block job has completed.
-
-Data:
-
-- "type":     Job type (json-string; "stream" for image streaming
-                                     "commit" for block commit)
-- "device":   Job identifier. Originally the device name but other
-              values are allowed since QEMU 2.7 (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-- "error":    Error message (json-string, optional)
-              Only present on failure.  This field contains a human-readable
-              error message.  There are no semantics other than that streaming
-              has failed and clients should not try to interpret the error
-              string.
-
-Example:
-
-{ "event": "BLOCK_JOB_COMPLETED",
-     "data": { "type": "stream", "device": "virtio-disk0",
-               "len": 10737418240, "offset": 10737418240,
-               "speed": 0 },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-BLOCK_JOB_ERROR
----------------
-
-Emitted when a block job encounters an error.
-
-Data:
-
-- "device": Job identifier. Originally the device name but other
-            values are allowed since QEMU 2.7 (json-string)
-- "operation": I/O operation (json-string, "read" or "write")
-- "action": action that has been taken, it's one of the following (json-string):
-    "ignore": error has been ignored, the job may fail later
-    "report": error will be reported and the job canceled
-    "stop": error caused job to be paused
-
-Example:
-
-{ "event": "BLOCK_JOB_ERROR",
-    "data": { "device": "ide0-hd1",
-              "operation": "write",
-              "action": "stop" },
-    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-BLOCK_JOB_READY
----------------
-
-Emitted when a block job is ready to complete.
-
-Data:
-
-- "type":     Job type (json-string; "stream" for image streaming
-                                     "commit" for block commit)
-- "device":   Job identifier. Originally the device name but other
-              values are allowed since QEMU 2.7 (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-
-Example:
-
-{ "event": "BLOCK_JOB_READY",
-    "data": { "device": "drive0", "type": "mirror", "speed": 0,
-              "len": 2097152, "offset": 2097152 }
-    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
-event.
-
-DEVICE_DELETED
---------------
-
-Emitted whenever the device removal completion is acknowledged
-by the guest.
-At this point, it's safe to reuse the specified device ID.
-Device removal can be initiated by the guest or by HMP/QMP commands.
-
-Data:
-
-- "device": device name (json-string, optional)
-- "path": device path (json-string)
-
-{ "event": "DEVICE_DELETED",
-  "data": { "device": "virtio-net-pci-0",
-            "path": "/machine/peripheral/virtio-net-pci-0" },
-  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-DEVICE_TRAY_MOVED
------------------
-
-It's emitted whenever the tray of a removable device is moved by the guest
-or by HMP/QMP commands.
-
-Data:
-
-- "device": device name (json-string)
-- "tray-open": true if the tray has been opened or false if it has been closed
-               (json-bool)
-
-{ "event": "DEVICE_TRAY_MOVED",
-  "data": { "device": "ide1-cd0",
-            "tray-open": true
-  },
-  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-DUMP_COMPLETED
---------------
-
-Emitted when the guest has finished one memory dump.
-
-Data:
-
-- "result": DumpQueryResult type described in qapi-schema.json
-- "error": Error message when dump failed. This is only a
-  human-readable string provided when dump failed. It should not be
-  parsed in any way (json-string, optional)
-
-Example:
-
-{ "event": "DUMP_COMPLETED",
-  "data": {"result": {"total": 1090650112, "status": "completed",
-                      "completed": 1090650112} } }
-
-GUEST_PANICKED
---------------
-
-Emitted when guest OS panic is detected.
-
-Data:
-
-- "action": Action that has been taken (json-string, currently always "pause").
-
-Example:
-
-{ "event": "GUEST_PANICKED",
-     "data": { "action": "pause" } }
-
-MEM_UNPLUG_ERROR
---------------------
-Emitted when memory hot unplug error occurs.
-
-Data:
-
-- "device": device name (json-string)
-- "msg": Informative message (e.g., reason for the error) (json-string)
-
-Example:
-
-{ "event": "MEM_UNPLUG_ERROR"
-  "data": { "device": "dimm1",
-            "msg": "acpi: device unplug for unsupported device"
-  },
-  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-NIC_RX_FILTER_CHANGED
----------------------
-
-The event is emitted once until the query command is executed,
-the first event will always be emitted.
-
-Data:
-
-- "name": net client name (json-string)
-- "path": device path (json-string)
-
-{ "event": "NIC_RX_FILTER_CHANGED",
-  "data": { "name": "vnet0",
-            "path": "/machine/peripheral/vnet0/virtio-backend" },
-  "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
-}
-
-POWERDOWN
----------
-
-Emitted when the Virtual Machine is powered down through the power
-control system, such as via ACPI.
-
-Data: None.
-
-Example:
-
-{ "event": "POWERDOWN",
-    "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
-
-QUORUM_FAILURE
---------------
-
-Emitted by the Quorum block driver if it fails to establish a quorum.
-
-Data:
-
-- "reference":     device name if defined else node name.
-- "sector-num":    Number of the first sector of the failed read operation.
-- "sectors-count": Failed read operation sector count.
-
-Example:
-
-{ "event": "QUORUM_FAILURE",
-     "data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 },
-     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-Note: this event is rate-limited.
-
-QUORUM_REPORT_BAD
------------------
-
-Emitted to report a corruption of a Quorum file.
-
-Data:
-
-- "type":          Quorum operation type
-- "error":         Error message (json-string, optional)
-                   Only present on failure.  This field contains a human-readable
-                   error message.  There are no semantics other than that the
-                   block layer reported an error and clients should not try to
-                   interpret the error string.
-- "node-name":     The graph node name of the block driver state.
-- "sector-num":    Number of the first sector of the failed read operation.
-- "sectors-count": Failed read operation sector count.
-
-Example:
-
-Read operation:
-{ "event": "QUORUM_REPORT_BAD",
-     "data": { "node-name": "node0", "sector-num": 345435, "sectors-count": 5,
-               "type": "read" },
-     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-Flush operation:
-{ "event": "QUORUM_REPORT_BAD",
-     "data": { "node-name": "node0", "sector-num": 0, "sectors-count": 2097120,
-               "type": "flush", "error": "Broken pipe" },
-     "timestamp": { "seconds": 1456406829, "microseconds": 291763 } }
-
-Note: this event is rate-limited.
-
-RESET
------
-
-Emitted when the Virtual Machine is reset.
-
-Data: None.
-
-Example:
-
-{ "event": "RESET",
-    "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
-
-RESUME
-------
-
-Emitted when the Virtual Machine resumes execution.
-
-Data: None.
-
-Example:
-
-{ "event": "RESUME",
-    "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
-
-RTC_CHANGE
-----------
-
-Emitted when the guest changes the RTC time.
-
-Data:
-
-- "offset": Offset between base RTC clock (as specified by -rtc base), and
-new RTC clock value (json-number)
-
-Example:
-
-{ "event": "RTC_CHANGE",
-    "data": { "offset": 78 },
-    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-
-Note: this event is rate-limited.
-
-SHUTDOWN
---------
-
-Emitted when the Virtual Machine has shut down, indicating that qemu
-is about to exit.
-
-Data: None.
-
-Example:
-
-{ "event": "SHUTDOWN",
-    "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
-
-Note: If the command-line option "-no-shutdown" has been specified, a STOP
-event will eventually follow the SHUTDOWN event.
-
-SPICE_CONNECTED
----------------
-
-Emitted when a SPICE client connects.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
-  "event": "SPICE_CONNECTED",
-  "data": {
-    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
-    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
-}}
-
-SPICE_DISCONNECTED
-------------------
-
-Emitted when a SPICE client disconnects.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
-  "event": "SPICE_DISCONNECTED",
-  "data": {
-    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
-    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
-}}
-
-SPICE_INITIALIZED
------------------
-
-Emitted after initial handshake and authentication takes place (if any)
-and the SPICE channel is up and running
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "connection-id": spice connection id.  All channels with the same id
-                     belong to the same spice session (json-int)
-  - "channel-type": channel type.  "1" is the main control channel, filter for
-                    this one if you want track spice sessions only (json-int)
-  - "channel-id": channel id.  Usually "0", might be different needed when
-                  multiple channels of the same type exist, such as multiple
-                  display channels in a multihead setup (json-int)
-  - "tls": whevener the channel is encrypted (json-bool)
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
-  "event": "SPICE_INITIALIZED",
-  "data": {"server": {"auth": "spice", "port": "5921",
-                      "family": "ipv4", "host": "127.0.0.1"},
-           "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
-                      "connection-id": 1804289383, "host": "127.0.0.1",
-                      "channel-id": 0, "tls": true}
-}}
-
-SPICE_MIGRATE_COMPLETED
------------------------
-
-Emitted when SPICE migration has completed
-
-Data: None.
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
-  "event": "SPICE_MIGRATE_COMPLETED" }
-
-MIGRATION
----------
-
-Emitted when a migration event happens
-
-Data: None.
-
- - "status": migration status
-     See MigrationStatus in ~/qapi-schema.json for possible values
-
-Example:
-
-{"timestamp": {"seconds": 1432121972, "microseconds": 744001},
- "event": "MIGRATION", "data": {"status": "completed"}}
-
-MIGRATION_PASS
---------------
-
-Emitted from the source side of a migration at the start of each pass
-(when it syncs the dirty bitmap)
-
-Data: None.
-
-  - "pass": An incrementing count (starting at 1 on the first pass)
-
-Example:
-{"timestamp": {"seconds": 1449669631, "microseconds": 239225},
- "event": "MIGRATION_PASS", "data": {"pass": 2}}
-
-STOP
-----
-
-Emitted when the Virtual Machine is stopped.
-
-Data: None.
-
-Example:
-
-{ "event": "STOP",
-    "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
-
-SUSPEND
--------
-
-Emitted when guest enters S3 state.
-
-Data: None.
-
-Example:
-
-{ "event": "SUSPEND",
-     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
-
-SUSPEND_DISK
-------------
-
-Emitted when the guest makes a request to enter S4 state.
-
-Data: None.
-
-Example:
-
-{ "event": "SUSPEND_DISK",
-     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
-
-Note: QEMU shuts down when entering S4 state.
-
-VNC_CONNECTED
--------------
-
-Emitted when a VNC client establishes a connection.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "event": "VNC_CONNECTED",
-    "data": {
-        "server": { "auth": "sasl", "family": "ipv4",
-                    "service": "5901", "host": "0.0.0.0" },
-        "client": { "family": "ipv4", "service": "58425",
-                    "host": "127.0.0.1" } },
-    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
-
-
-Note: This event is emitted before any authentication takes place, thus
-the authentication ID is not provided.
-
-VNC_DISCONNECTED
-----------------
-
-Emitted when the connection is closed.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "x509_dname": TLS dname (json-string, optional)
-  - "sasl_username": SASL username (json-string, optional)
-
-Example:
-
-{ "event": "VNC_DISCONNECTED",
-    "data": {
-        "server": { "auth": "sasl", "family": "ipv4",
-                    "service": "5901", "host": "0.0.0.0" },
-        "client": { "family": "ipv4", "service": "58425",
-                    "host": "127.0.0.1", "sasl_username": "luiz" } },
-    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
-
-VNC_INITIALIZED
----------------
-
-Emitted after authentication takes place (if any) and the VNC session is
-made active.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "x509_dname": TLS dname (json-string, optional)
-  - "sasl_username": SASL username (json-string, optional)
-
-Example:
-
-{ "event": "VNC_INITIALIZED",
-    "data": {
-        "server": { "auth": "sasl", "family": "ipv4",
-                    "service": "5901", "host": "0.0.0.0"},
-        "client": { "family": "ipv4", "service": "46089",
-                    "host": "127.0.0.1", "sasl_username": "luiz" } },
-        "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
-
-VSERPORT_CHANGE
----------------
-
-Emitted when the guest opens or closes a virtio-serial port.
-
-Data:
-
-- "id": device identifier of the virtio-serial port (json-string)
-- "open": true if the guest has opened the virtio-serial port (json-bool)
-
-Example:
-
-{ "event": "VSERPORT_CHANGE",
-    "data": { "id": "channel0", "open": true },
-    "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
-
-Note: this event is rate-limited separately for each "id".
-
-WAKEUP
-------
-
-Emitted when the guest has woken up from S3 and is running.
-
-Data: None.
-
-Example:
-
-{ "event": "WAKEUP",
-     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-WATCHDOG
---------
-
-Emitted when the watchdog device's timer is expired.
-
-Data:
-
-- "action": Action that has been taken, it's one of the following (json-string):
-            "reset", "shutdown", "poweroff", "pause", "debug", or "none"
-
-Example:
-
-{ "event": "WATCHDOG",
-     "data": { "action": "reset" },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
-followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-Note: this event is rate-limited.
diff --git a/qapi-schema.json b/qapi-schema.json
index 3ac8637..250baee 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1,6 +1,52 @@
 # -*- Mode: Python -*-
+##
+# = Introduction
+#
+# This document describes all commands currently supported by QMP.
+#
+# Most of the time their usage is exactly the same as in the user Monitor, this
+# means that any other document which also describe commands (the manpage,
+# QEMU's manual, etc) can and should be consulted.
+#
+# QMP has two types of commands: regular and query commands. Regular commands
+# usually change the Virtual Machine's state someway, while query commands just
+# return information. The sections below are divided accordingly.
+#
+# It's important to observe that all communication examples are formatted in
+# a reader-friendly way, so that they're easier to understand. However, in real
+# protocol usage, they're emitted as a single line.
+#
+# Also, the following notation is used to denote data flow:
+#
+# Example:
+#
+# | -> data issued by the Client
+# | <- Server data response
+#
+# Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed
+# information on the Server command and response formats.
+#
+# = Stability Considerations
+#
+# The current QMP command set (described in this file) may be useful for a
+# number of use cases, however it's limited and several commands have bad
+# defined semantics, specially with regard to command completion.
+#
+# These problems are going to be solved incrementally in the next QEMU releases
+# and we're going to establish a deprecation policy for badly defined commands.
+#
+# If you're planning to adopt QMP, please observe the following:
+#
+#     1. The deprecation policy will take effect and be documented soon, please
+#        check the documentation of each used command as soon as a new release of
+#        QEMU is available
+#
+#     2. DO NOT rely on anything which is not explicit documented
+#
+#     3. Errors, in special, are not documented. Applications should NOT check
+#        for specific errors classes or data (it's strongly recommended to only
+#        check for the "error" key)
 #
-# QAPI Schema
 
 # QAPI common definitions
 { 'include': 'qapi/common.json' }
@@ -85,6 +131,13 @@
 # Returns: nothing on success.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "add_client", "arguments": { "protocol": "vnc",
+#                                              "fdname": "myclient" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'add_client',
   'data': { 'protocol': 'str', 'fdname': 'str', '*skipauth': 'bool',
@@ -109,6 +162,12 @@
 # Returns: @NameInfo of the guest
 #
 # Since 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-name" }
+# <- { "return": { "name": "qemu-name" } }
+#
 ##
 { 'command': 'query-name', 'returns': 'NameInfo' }
 
@@ -133,6 +192,12 @@
 # Returns: @KvmInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-kvm" }
+# <- { "return": { "enabled": true, "present": true } }
+#
 ##
 { 'command': 'query-kvm', 'returns': 'KvmInfo' }
 
@@ -209,13 +274,21 @@
 # Returns: @StatusInfo reflecting all VCPUs
 #
 # Since:  0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-status" }
+# <- { "return": { "running": true,
+#                  "singlestep": false,
+#                  "status": "running" } }
+#
 ##
 { 'command': 'query-status', 'returns': 'StatusInfo' }
 
 ##
 # @UuidInfo:
 #
-# Guest UUID information.
+# Guest UUID information (Universally Unique Identifier).
 #
 # @UUID: the UUID of the guest
 #
@@ -233,6 +306,12 @@
 # Returns: The @UuidInfo for the guest
 #
 # Since 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-uuid" }
+# <- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
+#
 ##
 { 'command': 'query-uuid', 'returns': 'UuidInfo' }
 
@@ -266,6 +345,30 @@
 # Returns: a list of @ChardevInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-chardev" }
+# <- {
+#       "return": [
+#          {
+#             "label": "charchannel0",
+#             "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.agent,server",
+#             "frontend-open": false
+#          },
+#          {
+#             "label": "charmonitor",
+#             "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.monitor,server",
+#             "frontend-open": true
+#          },
+#          {
+#             "label": "charserial0",
+#             "filename": "pty:/dev/pts/2",
+#             "frontend-open": true
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-chardev', 'returns': ['ChardevInfo'] }
 
@@ -288,6 +391,27 @@
 # Returns: a list of @ChardevBackendInfo
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-chardev-backends" }
+# <- {
+#       "return":[
+#          {
+#             "name":"udp"
+#          },
+#          {
+#             "name":"tcp"
+#          },
+#          {
+#             "name":"unix"
+#          },
+#          {
+#             "name":"spiceport"
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-chardev-backends', 'returns': ['ChardevBackendInfo'] }
 
@@ -324,6 +448,15 @@
 # Returns: Nothing on success
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute": "ringbuf-write",
+#      "arguments": { "device": "foo",
+#                     "data": "abcdefgh",
+#                     "format": "utf8" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'ringbuf-write',
   'data': {'device': 'str', 'data': 'str',
@@ -351,6 +484,15 @@
 # Returns: data read from the device
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute": "ringbuf-read",
+#      "arguments": { "device": "foo",
+#                     "size": 1000,
+#                     "format": "utf8" } }
+# <- { "return": "abcdefgh" }
+#
 ##
 { 'command': 'ringbuf-read',
   'data': {'device': 'str', 'size': 'int', '*format': 'DataFormat'},
@@ -375,6 +517,23 @@
 # Returns: A list of @EventInfo for all supported events
 #
 # Since: 1.2.0
+#
+# Example:
+#
+# -> { "execute": "query-events" }
+# <- {
+#      "return": [
+#          {
+#             "name":"SHUTDOWN"
+#          },
+#          {
+#             "name":"RESET"
+#          }
+#       ]
+#    }
+#
+# Note: This example has been shortened as the real response is too long.
+#
 ##
 { 'command': 'query-events', 'returns': ['EventInfo'] }
 
@@ -531,11 +690,124 @@
 ##
 # @query-migrate
 #
-# Returns information about current migration process.
+# Returns information about current migration process. If migration
+# is active there will be another json-object with RAM migration
+# status and if block migration is active another one with block
+# migration status.
 #
 # Returns: @MigrationInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# 1. Before the first migration
+#
+# -> { "execute": "query-migrate" }
+# <- { "return": {} }
+#
+# 2. Migration is done and has succeeded
+#
+# -> { "execute": "query-migrate" }
+# <- { "return": {
+#         "status": "completed",
+#         "ram":{
+#           "transferred":123,
+#           "remaining":123,
+#           "total":246,
+#           "total-time":12345,
+#           "setup-time":12345,
+#           "downtime":12345,
+#           "duplicate":123,
+#           "normal":123,
+#           "normal-bytes":123456,
+#           "dirty-sync-count":15
+#         }
+#      }
+#    }
+#
+# 3. Migration is done and has failed
+#
+# -> { "execute": "query-migrate" }
+# <- { "return": { "status": "failed" } }
+#
+# 4. Migration is being performed and is not a block migration:
+#
+# -> { "execute": "query-migrate" }
+# <- {
+#       "return":{
+#          "status":"active",
+#          "ram":{
+#             "transferred":123,
+#             "remaining":123,
+#             "total":246,
+#             "total-time":12345,
+#             "setup-time":12345,
+#             "expected-downtime":12345,
+#             "duplicate":123,
+#             "normal":123,
+#             "normal-bytes":123456,
+#             "dirty-sync-count":15
+#          }
+#       }
+#    }
+#
+# 5. Migration is being performed and is a block migration:
+#
+# -> { "execute": "query-migrate" }
+# <- {
+#       "return":{
+#          "status":"active",
+#          "ram":{
+#             "total":1057024,
+#             "remaining":1053304,
+#             "transferred":3720,
+#             "total-time":12345,
+#             "setup-time":12345,
+#             "expected-downtime":12345,
+#             "duplicate":123,
+#             "normal":123,
+#             "normal-bytes":123456,
+#             "dirty-sync-count":15
+#          },
+#          "disk":{
+#             "total":20971520,
+#             "remaining":20880384,
+#             "transferred":91136
+#          }
+#       }
+#    }
+#
+# 6. Migration is being performed and XBZRLE is active:
+#
+# -> { "execute": "query-migrate" }
+# <- {
+#       "return":{
+#          "status":"active",
+#          "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+#          "ram":{
+#             "total":1057024,
+#             "remaining":1053304,
+#             "transferred":3720,
+#             "total-time":12345,
+#             "setup-time":12345,
+#             "expected-downtime":12345,
+#             "duplicate":10,
+#             "normal":3333,
+#             "normal-bytes":3412992,
+#             "dirty-sync-count":15
+#          },
+#          "xbzrle-cache":{
+#             "cache-size":67108864,
+#             "bytes":20971520,
+#             "pages":2444343,
+#             "cache-miss":2244,
+#             "cache-miss-rate":0.123,
+#             "overflow":34434
+#          }
+#       }
+#    }
+#
 ##
 { 'command': 'query-migrate', 'returns': 'MigrationInfo' }
 
@@ -604,6 +876,12 @@
 # @capabilities: json array of capability modifications to make
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "migrate-set-capabilities" , "arguments":
+#      { "capabilities": [ { "capability": "xbzrle", "state": true } ] } }
+#
 ##
 { 'command': 'migrate-set-capabilities',
   'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
@@ -616,6 +894,20 @@
 # Returns: @MigrationCapabilitiesStatus
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "query-migrate-capabilities" }
+# <- { "return": [
+#       {"state": false, "capability": "xbzrle"},
+#       {"state": false, "capability": "rdma-pin-all"},
+#       {"state": false, "capability": "auto-converge"},
+#       {"state": false, "capability": "zero-blocks"},
+#       {"state": false, "capability": "compress"},
+#       {"state": true, "capability": "events"},
+#       {"state": false, "capability": "postcopy-ram"}
+#    ]}
+#
 ##
 { 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus']}
 
@@ -703,6 +995,12 @@
 #                certificate identity can be validated. (Since 2.7)
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "migrate-set-parameters" ,
+#      "arguments": { "compress-level": 1 } }
+#
 ##
 { 'command': 'migrate-set-parameters',
   'data': { '*compress-level': 'int',
@@ -763,6 +1061,19 @@
 # Returns: @MigrationParameters
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-migrate-parameters" }
+# <- { "return": {
+#          "decompress-threads": 2,
+#          "cpu-throttle-increment": 10,
+#          "compress-threads": 8,
+#          "compress-level": 1,
+#          "cpu-throttle-initial": 20
+#       }
+#    }
+#
 ##
 { 'command': 'query-migrate-parameters',
   'returns': 'MigrationParameters' }
@@ -781,6 +1092,15 @@
 # @cert-subject: #optional server certificate subject
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "client_migrate_info",
+#      "arguments": { "protocol": "spice",
+#                     "hostname": "virt42.lab.kraxel.org",
+#                     "port": 1234 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'client_migrate_info',
   'data': { 'protocol': 'str', 'hostname': 'str', '*port': 'int',
@@ -794,6 +1114,13 @@
 # command.
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "migrate-start-postcopy" }
+# <- { "return": {} }
+#
+##
 { 'command': 'migrate-start-postcopy' }
 
 ##
@@ -823,6 +1150,26 @@
 # Returns: a list of @MouseInfo for each device
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-mice" }
+# <- { "return": [
+#          {
+#             "name":"QEMU Microsoft Mouse",
+#             "index":0,
+#             "current":false,
+#             "absolute":false
+#          },
+#          {
+#             "name":"QEMU PS/2 Mouse",
+#             "index":1,
+#             "current":true,
+#             "absolute":true
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-mice', 'returns': ['MouseInfo'] }
 
@@ -947,6 +1294,32 @@
 # Returns: a list of @CpuInfo for each virtual CPU
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-cpus" }
+# <- { "return": [
+#          {
+#             "CPU":0,
+#             "current":true,
+#             "halted":false,
+#             "qom_path":"/machine/unattached/device[0]",
+#             "arch":"x86",
+#             "pc":3227107138,
+#             "thread_id":3134
+#          },
+#          {
+#             "CPU":1,
+#             "current":false,
+#             "halted":true,
+#             "qom_path":"/machine/unattached/device[2]",
+#             "arch":"x86",
+#             "pc":7108165,
+#             "thread_id":3135
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-cpus', 'returns': ['CpuInfo'] }
 
@@ -976,6 +1349,22 @@
 # Returns: a list of @IOThreadInfo for each iothread
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-iothreads" }
+# <- { "return": [
+#          {
+#             "id":"iothread0",
+#             "thread-id":3134
+#          },
+#          {
+#             "id":"iothread1",
+#             "thread-id":3135
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-iothreads', 'returns': ['IOThreadInfo'] }
 
@@ -1156,6 +1545,26 @@
 # Returns: @VncInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-vnc" }
+# <- { "return": {
+#          "enabled":true,
+#          "host":"0.0.0.0",
+#          "service":"50402",
+#          "auth":"vnc",
+#          "family":"ipv4",
+#          "clients":[
+#             {
+#                "host":"127.0.0.1",
+#                "service":"50401",
+#                "family":"ipv4"
+#             }
+#          ]
+#       }
+#    }
+#
 ##
 { 'command': 'query-vnc', 'returns': 'VncInfo' }
 
@@ -1253,7 +1662,7 @@
 # @enabled: true if the SPICE server is enabled, false otherwise
 #
 # @migrated: true if the last guest migration completed and spice
-#            migration had completed as well. false otherwise.
+#            migration had completed as well. false otherwise. (since 1.4)
 #
 # @host: #optional The hostname the SPICE server is bound to.  This depends on
 #        the name resolution on the host and may be an IP address.
@@ -1271,9 +1680,7 @@
 #
 # @mouse-mode: The mode in which the mouse cursor is displayed currently. Can
 #              be determined by the client or the server, or unknown if spice
-#              server doesn't provide this information.
-#
-#              Since: 1.1
+#              server doesn't provide this information. (since: 1.1)
 #
 # @channels: a list of @SpiceChannel for each active spice channel
 #
@@ -1292,6 +1699,40 @@
 # Returns: @SpiceInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-spice" }
+# <- { "return": {
+#          "enabled": true,
+#          "auth": "spice",
+#          "port": 5920,
+#          "tls-port": 5921,
+#          "host": "0.0.0.0",
+#          "channels": [
+#             {
+#                "port": "54924",
+#                "family": "ipv4",
+#                "channel-type": 1,
+#                "connection-id": 1804289383,
+#                "host": "127.0.0.1",
+#                "channel-id": 0,
+#                "tls": true
+#             },
+#             {
+#                "port": "36710",
+#                "family": "ipv4",
+#                "channel-type": 4,
+#                "connection-id": 1804289383,
+#                "host": "127.0.0.1",
+#                "channel-id": 0,
+#                "tls": false
+#             },
+#             [ ... more channels follow ... ]
+#          ]
+#       }
+#    }
+#
 ##
 { 'command': 'query-spice', 'returns': 'SpiceInfo' }
 
@@ -1313,11 +1754,22 @@
 # Return information about the balloon device.
 #
 # Returns: @BalloonInfo on success
+#
 #          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
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-balloon" }
+# <- { "return": {
+#          "actual": 1073741824,
+#       }
+#    }
+#
 ##
 { 'command': 'query-balloon', 'returns': 'BalloonInfo' }
 
@@ -1344,6 +1796,8 @@
 # @type: 'io' if the region is a PIO region
 #        'memory' if the region is a MMIO region
 #
+# @size: memory size
+#
 # @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
 #
 # @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
@@ -1477,9 +1931,144 @@
 #
 # Return information about the PCI bus topology of the guest.
 #
-# Returns: a list of @PciInfo for each PCI bus
+# Returns: a list of @PciInfo for each PCI bus. Each bus is
+# represented by a json-object, which has a key with a json-array of
+# all PCI devices attached to it. Each device is represented by a
+# json-object.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-pci" }
+# <- { "return": [
+#          {
+#             "bus": 0,
+#             "devices": [
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 0,
+#                   "class_info": {
+#                      "class": 1536,
+#                      "desc": "Host bridge"
+#                   },
+#                   "id": {
+#                      "device": 32902,
+#                      "vendor": 4663
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 1,
+#                   "class_info": {
+#                      "class": 1537,
+#                      "desc": "ISA bridge"
+#                   },
+#                   "id": {
+#                      "device": 32902,
+#                      "vendor": 28672
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 1,
+#                   "class_info": {
+#                      "class": 257,
+#                      "desc": "IDE controller"
+#                   },
+#                   "id": {
+#                      "device": 32902,
+#                      "vendor": 28688
+#                   },
+#                   "function": 1,
+#                   "regions": [
+#                      {
+#                         "bar": 4,
+#                         "size": 16,
+#                         "address": 49152,
+#                         "type": "io"
+#                      }
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 2,
+#                   "class_info": {
+#                      "class": 768,
+#                      "desc": "VGA controller"
+#                   },
+#                   "id": {
+#                      "device": 4115,
+#                      "vendor": 184
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                      {
+#                         "prefetch": true,
+#                         "mem_type_64": false,
+#                         "bar": 0,
+#                         "size": 33554432,
+#                         "address": 4026531840,
+#                         "type": "memory"
+#                      },
+#                      {
+#                         "prefetch": false,
+#                         "mem_type_64": false,
+#                         "bar": 1,
+#                         "size": 4096,
+#                         "address": 4060086272,
+#                         "type": "memory"
+#                      },
+#                      {
+#                         "prefetch": false,
+#                         "mem_type_64": false,
+#                         "bar": 6,
+#                         "size": 65536,
+#                         "address": -1,
+#                         "type": "memory"
+#                      }
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "irq": 11,
+#                   "slot": 4,
+#                   "class_info": {
+#                      "class": 1280,
+#                      "desc": "RAM controller"
+#                   },
+#                   "id": {
+#                      "device": 6900,
+#                      "vendor": 4098
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                      {
+#                         "bar": 0,
+#                         "size": 32,
+#                         "address": 49280,
+#                         "type": "io"
+#                      }
+#                   ]
+#                }
+#             ]
+#          }
+#       ]
+#    }
+#
+# Note: This example has been shortened as the real response is too long.
+#
 ##
 { 'command': 'query-pci', 'returns': ['PciInfo'] }
 
@@ -1492,6 +2081,11 @@
 # unexpected.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "quit" }
+# <- { "return": {} }
 ##
 { 'command': 'quit' }
 
@@ -1506,6 +2100,12 @@
 #         state.  In "inmigrate" state, it will ensure that the guest
 #         remains paused once migration finishes, as if the -S option was
 #         passed on the command line.
+#
+# Example:
+#
+# -> { "execute": "stop" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'stop' }
 
@@ -1515,6 +2115,12 @@
 # Performs a hard reset of a guest.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "system_reset" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'system_reset' }
 
@@ -1529,6 +2135,11 @@
 #        returning does not indicate that a guest has accepted the request or
 #        that it has shut down.  Many guests will respond to this command by
 #        prompting the user in some way.
+# Example:
+#
+# -> { "execute": "system_powerdown" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'system_powerdown' }
 
@@ -1553,6 +2164,11 @@
 # Returns: Nothing on success
 #
 # Since 1.5
+#
+# Example:
+#
+# -> { "execute": "cpu-add", "arguments": { "id": 2 } }
+# <- { "return": {} }
 ##
 { 'command': 'cpu-add', 'data': {'id': 'int'} }
 
@@ -1575,6 +2191,15 @@
 # Since: 0.14.0
 #
 # Notes: Errors were not reliably returned until 1.1
+#
+# Example:
+#
+# -> { "execute": "memsave",
+#      "arguments": { "val": 10,
+#                     "size": 100,
+#                     "filename": "/tmp/virtual-mem-dump" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'memsave',
   'data': {'val': 'int', 'size': 'int', 'filename': 'str', '*cpu-index': 'int'} }
@@ -1595,6 +2220,15 @@
 # Since: 0.14.0
 #
 # Notes: Errors were not reliably returned until 1.1
+#
+# Example:
+#
+# -> { "execute": "pmemsave",
+#      "arguments": { "val": 10,
+#                     "size": 100,
+#                     "filename": "/tmp/physical-mem-dump" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'pmemsave',
   'data': {'val': 'int', 'size': 'int', 'filename': 'str'} }
@@ -1615,6 +2249,12 @@
 #         this case, the effect of the command is to make sure the guest
 #         starts once migration finishes, removing the effect of the -S
 #         command line option if it was passed.
+#
+# Example:
+#
+# -> { "execute": "cont" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'cont' }
 
@@ -1626,6 +2266,12 @@
 # Since:  1.1
 #
 # Returns:  nothing.
+#
+# Example:
+#
+# -> { "execute": "system_wakeup" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'system_wakeup' }
 
@@ -1633,12 +2279,19 @@
 # @inject-nmi:
 #
 # Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or all CPUs (ppc64).
+# The command fails when the guest doesn't support injecting.
 #
 # Returns:  If successful, nothing
 #
 # Since:  0.14.0
 #
 # Note: prior to 2.1, this command was only supported for x86 and s390 VMs
+#
+# Example:
+#
+# -> { "execute": "inject-nmi" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'inject-nmi' }
 
@@ -1659,6 +2312,13 @@
 # Notes: Not all network adapters support setting link status.  This command
 #        will succeed even if the network adapter does not support link status
 #        notification.
+#
+# Example:
+#
+# -> { "execute": "set_link",
+#      "arguments": { "name": "e1000.0", "up": false } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
 
@@ -1679,6 +2339,12 @@
 #        size independent of this command.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "balloon", "arguments": { "value": 536870912 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'balloon', 'data': {'value': 'int'} }
 
@@ -1764,6 +2430,28 @@
 # operation fails, then the entire set of actions will be abandoned and the
 # appropriate error returned.
 #
+# For external snapshots, the dictionary contains the device, the file to use for
+# the new snapshot, and the format.  The default format, if not specified, is
+# qcow2.
+#
+# Each new snapshot defaults to being created by QEMU (wiping any
+# contents if the file already exists), but it is also possible to reuse
+# an externally-created file.  In the latter case, you should ensure that
+# the new image file has the same contents as the current one; QEMU cannot
+# perform any meaningful check.  Typically this is achieved by using the
+# current image file as the backing file for the new image.
+#
+# On failure, the original disks pre-snapshot attempt will be used.
+#
+# For internal snapshots, the dictionary contains the device and the snapshot's
+# name.  If an internal snapshot matching name already exists, the request will
+# be rejected.  Only some image formats support it, for example, qcow2, rbd,
+# and sheepdog.
+#
+# On failure, qemu will try delete the newly created internal snapshot in the
+# transaction.  When an I/O error occurs during deletion, the user needs to fix
+# it later with qemu-img or other command.
+#
 # @actions: List of @TransactionAction;
 #           information needed for the respective operations.
 #
@@ -1772,6 +2460,7 @@
 #              for additional detail.
 #
 # Returns: nothing on success
+#
 #          Errors depend on the operations of the transaction
 #
 # Note: The transaction aborts on the first failure.  Therefore, there will be
@@ -1779,6 +2468,28 @@
 # subsequent actions will not have been attempted.
 #
 # Since 1.1
+#
+# Example:
+#
+# -> { "execute": "transaction",
+#      "arguments": { "actions": [
+#          { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd0",
+#                                      "snapshot-file": "/some/place/my-image",
+#                                      "format": "qcow2" } },
+#          { "type": "blockdev-snapshot-sync", "data" : { "node-name": "myfile",
+#                                      "snapshot-file": "/some/place/my-image2",
+#                                      "snapshot-node-name": "node3432",
+#                                      "mode": "existing",
+#                                      "format": "qcow2" } },
+#          { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd1",
+#                                      "snapshot-file": "/some/place/my-image2",
+#                                      "mode": "existing",
+#                                      "format": "qcow2" } },
+#          { "type": "blockdev-snapshot-internal-sync", "data" : {
+#                                      "device": "ide-hd2",
+#                                      "name": "snapshot0" } } ] } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'transaction',
   'data': { 'actions': [ 'TransactionAction' ],
@@ -1800,15 +2511,26 @@
 # Since: 0.14.0
 #
 # Notes: This command only exists as a stop-gap.  Its use is highly
-#        discouraged.  The semantics of this command are not guaranteed.
+#        discouraged.  The semantics of this command are not
+#        guaranteed: this means that command names, arguments and
+#        responses can change or be removed at ANY time.  Applications
+#        that rely on long term stability guarantees should NOT
+#        use this command.
 #
 #        Known limitations:
 #
 #        o This command is stateless, this means that commands that depend
 #          on state information (such as getfd) might not work
 #
-#       o Commands that prompt the user for data (eg. 'cont' when the block
-#         device is encrypted) don't currently work
+#        o Commands that prompt the user for data (eg. 'cont' when the block
+#          device is encrypted) don't currently work
+#
+# Example:
+#
+# -> { "execute": "human-monitor-command",
+#      "arguments": { "command-line": "info kvm" } }
+# <- { "return": "kvm support: enabled\r\n" }
+#
 ##
 { 'command': 'human-monitor-command',
   'data': {'command-line': 'str', '*cpu-index': 'int'},
@@ -1824,6 +2546,12 @@
 # Notes: This command succeeds even if there is no migration process running.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "migrate_cancel" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate_cancel' }
 
@@ -1837,6 +2565,12 @@
 # Returns: nothing on success
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate_set_downtime', 'data': {'value': 'number'} }
 
@@ -1845,20 +2579,26 @@
 #
 # Set maximum speed for migration.
 #
-# @value: maximum speed in bytes.
+# @value: maximum speed in bytes per second.
 #
 # Returns: nothing on success
 #
 # Notes: A value lesser than zero will be automatically round up to zero.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
 
 ##
 # @migrate-set-cache-size
 #
-# Set XBZRLE cache size
+# Set cache size to be used by XBZRLE migration
 #
 # @value: cache size in bytes
 #
@@ -1868,17 +2608,30 @@
 # Returns: nothing on success
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "migrate-set-cache-size",
+#      "arguments": { "value": 536870912 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
 
 ##
 # @query-migrate-cache-size
 #
-# query XBZRLE cache size
+# Query migration XBZRLE cache size
 #
 # Returns: XBZRLE cache size in bytes
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "query-migrate-cache-size" }
+# <- { "return": 67108864 }
+#
 ##
 { 'command': 'query-migrate-cache-size', 'returns': 'int' }
 
@@ -1995,6 +2748,13 @@
 #          If Spice is not enabled, DeviceNotFound
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "set_password", "arguments": { "protocol": "vnc",
+#                                                "password": "secret" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'set_password',
   'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} }
@@ -2021,6 +2781,13 @@
 #        coordinate server time with client time.  It is not recommended to
 #        use the absolute time version of the @time parameter unless you're
 #        sure you are on the same machine as the QEMU instance.
+#
+# Example:
+#
+# -> { "execute": "expire_password", "arguments": { "protocol": "vnc",
+#                                                   "time": "+60" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} }
 
@@ -2071,6 +2838,23 @@
 #         change-vnc-password.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# 1. Change a removable medium
+#
+# -> { "execute": "change",
+#      "arguments": { "device": "ide1-cd0",
+#                     "target": "/srv/images/Fedora-12-x86_64-DVD.iso" } }
+# <- { "return": {} }
+#
+# 2. Change VNC password
+#
+# -> { "execute": "change",
+#      "arguments": { "device": "vnc", "target": "password",
+#                     "arg": "foobar1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'change',
   'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
@@ -2153,6 +2937,22 @@
 # Returns: nothing on success
 #
 # Since: 0.14.0
+#
+# Notes:
+#
+# 1. The 'query-migrate' command should be used to check migration's progress
+#    and final result (this information is provided by the 'status' member)
+#
+# 2. All boolean arguments default to false
+#
+# 3. The user Monitor's "detach" argument is invalid in QMP and should not
+#    be used
+#
+# Example:
+#
+# -> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate',
   'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool', '*detach': 'bool' } }
@@ -2169,9 +2969,24 @@
 # Returns: nothing on success
 #
 # Since: 2.3
-# Note: It's a bad idea to use a string for the uri, but it needs to stay
-# compatible with -incoming and the format of the uri is already exposed
-# above libvirt
+#
+# Notes:
+#
+# 1. It's a bad idea to use a string for the uri, but it needs to stay
+#    compatible with -incoming and the format of the uri is already exposed
+#    above libvirt.
+#
+# 2. QEMU must be started with -incoming defer to allow migrate-incoming to
+#    be used.
+#
+# 3. The uri format is the same as for -incoming
+#
+# Example:
+#
+# -> { "execute": "migrate-incoming",
+#      "arguments": { "uri": "tcp::4446" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate-incoming', 'data': {'uri': 'str' } }
 
@@ -2188,6 +3003,13 @@
 # Returns: Nothing on success
 #
 # Since: 1.1
+#
+# Example:
+#
+# -> { "execute": "xen-save-devices-state",
+#      "arguments": { "filename": "/tmp/save" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'xen-save-devices-state', 'data': {'filename': 'str'} }
 
@@ -2201,12 +3023,21 @@
 # Returns: nothing
 #
 # Since: 1.3
+#
+# Example:
+#
+# -> { "execute": "xen-set-global-dirty-log",
+#      "arguments": { "enable": true } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'xen-set-global-dirty-log', 'data': { 'enable': 'bool' } }
 
 ##
 # @device_add:
 #
+# Add a device.
+#
 # @driver: the name of the new device's driver
 #
 # @bus: #optional the device's parent bus (device tree path)
@@ -2215,8 +3046,6 @@
 #
 # Additional arguments depend on the type.
 #
-# Add a device.
-#
 # Notes:
 # 1. For detailed information about this command, please refer to the
 #    'docs/qdev-device-use.txt' file.
@@ -2249,7 +3078,7 @@
 #
 # Remove a device from a guest
 #
-# @id: the name or QOM path of the device
+# @id: the device's ID or QOM path
 #
 # Returns: Nothing on success
 #          If @id is not a valid device, DeviceNotFound
@@ -2262,6 +3091,17 @@
 #        for all devices.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "device_del",
+#      "arguments": { "id": "net1" } }
+# <- { "return": {} }
+#
+# -> { "execute": "device_del",
+#      "arguments": { "id": "/machine/peripheral-anon/device[0]" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'device_del', 'data': {'id': 'str'} }
 
@@ -2328,9 +3168,18 @@
 #          @length is not allowed to be specified with non-elf @format at the
 #          same time (since 2.0)
 #
+# Note: All boolean arguments default to false
+#
 # Returns: nothing on success
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "dump-guest-memory",
+#      "arguments": { "protocol": "fd:dump" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'dump-guest-memory',
   'data': { 'paging': 'bool', 'protocol': 'str', '*detach': 'bool',
@@ -2381,6 +3230,13 @@
 # Returns: A @DumpStatus object showing the dump status.
 #
 # Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "query-dump" }
+# <- { "return": { "status": "active", "completed": 1024000,
+#                  "total": 2048000 } }
+#
 ##
 { 'command': 'query-dump', 'returns': 'DumpQueryResult' }
 
@@ -2404,6 +3260,13 @@
 #           dump-guest-memory
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-dump-guest-memory-capability" }
+# <- { "return": { "formats":
+#                  ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
+#
 ##
 { 'command': 'query-dump-guest-memory-capability',
   'returns': 'DumpGuestMemoryCapability' }
@@ -2418,6 +3281,13 @@
 # This command is only supported on s390 architecture.
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "dump-skeys",
+#      "arguments": { "filename": "/tmp/skeys" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'dump-skeys',
   'data': { 'filename': 'str' } }
@@ -2443,6 +3313,14 @@
 #
 # Returns: Nothing on success
 #          If @type is not a valid network backend, DeviceNotFound
+#
+# Example:
+#
+# -> { "execute": "netdev_add",
+#      "arguments": { "type": "user", "id": "netdev1",
+#                     "dnssearch": "example.org" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'netdev_add',
   'data': {'type': 'str', 'id': 'str'},
@@ -2459,6 +3337,12 @@
 #          If @id is not a valid network backend, DeviceNotFound
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "netdev_del", "arguments": { "id": "netdev1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'netdev_del', 'data': {'id': 'str'} }
 
@@ -2477,6 +3361,14 @@
 #          Error if @qom-type is not a valid class name
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "object-add",
+#      "arguments": { "qom-type": "rng-random", "id": "rng1",
+#                     "props": { "filename": "/dev/hwrng" } } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'object-add',
   'data': {'qom-type': 'str', 'id': 'str', '*props': 'any'} }
@@ -2492,6 +3384,12 @@
 #          Error if @id is not a valid id for a QOM object
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "object-del", "arguments": { "id": "rng1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'object-del', 'data': {'id': 'str'} }
 
@@ -3044,8 +3942,15 @@
 # Notes: If @fdname already exists, the file descriptor assigned to
 #        it will be closed and replaced by the received file
 #        descriptor.
+#
 #        The 'closefd' command can be used to explicitly close the
 #        file descriptor when it is no longer needed.
+#
+# Example:
+#
+# -> { "execute": "getfd", "arguments": { "fdname": "fd1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'getfd', 'data': {'fdname': 'str'} }
 
@@ -3059,6 +3964,12 @@
 # Returns: Nothing on success
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'closefd', 'data': {'fdname': 'str'} }
 
@@ -3387,7 +4298,9 @@
 # @opaque: #optional A free-form string that can be used to describe the fd.
 #
 # Returns: @AddfdInfo on success
+#
 #          If file descriptor was not received, FdNotSupplied
+#
 #          If @fdset-id is a negative value, InvalidParameterValue
 #
 # Notes: The list of fd sets is shared by all monitor connections.
@@ -3395,6 +4308,12 @@
 #        If @fdset-id is not specified, a new fd set will be created.
 #
 # Since: 1.2.0
+#
+# Example:
+#
+# -> { "execute": "add-fd", "arguments": { "fdset-id": 1 } }
+# <- { "return": { "fdset-id": 1, "fd": 3 } }
+#
 ##
 { 'command': 'add-fd', 'data': {'*fdset-id': 'int', '*opaque': 'str'},
   'returns': 'AddfdInfo' }
@@ -3417,6 +4336,12 @@
 #
 #        If @fd is not specified, all file descriptors in @fdset-id
 #        will be removed.
+#
+# Example:
+#
+# -> { "execute": "remove-fd", "arguments": { "fdset-id": 1, "fd": 3 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'remove-fd', 'data': {'fdset-id': 'int', '*fd': 'int'} }
 
@@ -3459,6 +4384,37 @@
 #
 # Note: The list of fd sets is shared by all monitor connections.
 #
+# Example:
+#
+# -> { "execute": "query-fdsets" }
+# <- { "return": [
+#        {
+#          "fds": [
+#            {
+#              "fd": 30,
+#              "opaque": "rdonly:/path/to/file"
+#            },
+#            {
+#              "fd": 24,
+#              "opaque": "rdwr:/path/to/file"
+#            }
+#          ],
+#          "fdset-id": 1
+#        },
+#        {
+#          "fds": [
+#            {
+#              "fd": 28
+#            },
+#            {
+#              "fd": 29
+#            }
+#          ],
+#          "fdset-id": 0
+#        }
+#      ]
+#    }
+#
 ##
 { 'command': 'query-fdsets', 'returns': ['FdsetInfo'] }
 
@@ -3547,6 +4503,14 @@
 #
 # Since: 1.3.0
 #
+# Example:
+#
+# -> { "execute": "send-key",
+#      "arguments": { "keys": [ { "type": "qcode", "data": "ctrl" },
+#                               { "type": "qcode", "data": "alt" },
+#                               { "type": "qcode", "data": "delete" } ] } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'send-key',
   'data': { 'keys': ['KeyValue'], '*hold-time': 'int' } }
@@ -3561,6 +4525,13 @@
 # Returns: Nothing on success
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "screendump",
+#      "arguments": { "filename": "/tmp/image" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'screendump', 'data': {'filename': 'str'} }
 
@@ -3786,6 +4757,25 @@
 # Returns: ChardevReturn.
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute" : "chardev-add",
+#      "arguments" : { "id" : "foo",
+#                      "backend" : { "type" : "null", "data" : {} } } }
+# <- { "return": {} }
+#
+# -> { "execute" : "chardev-add",
+#      "arguments" : { "id" : "bar",
+#                      "backend" : { "type" : "file",
+#                                    "data" : { "out" : "/tmp/bar.log" } } } }
+# <- { "return": {} }
+#
+# -> { "execute" : "chardev-add",
+#      "arguments" : { "id" : "baz",
+#                      "backend" : { "type" : "pty", "data" : {} } } }
+# <- { "return": { "pty" : "/dev/pty/42" } }
+#
 ##
 { 'command': 'chardev-add', 'data': {'id'      : 'str',
                                      'backend' : 'ChardevBackend' },
@@ -3801,6 +4791,12 @@
 # Returns: Nothing on success
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute": "chardev-remove", "arguments": { "id" : "foo" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'chardev-remove', 'data': {'id': 'str'} }
 
@@ -3823,6 +4819,12 @@
 # Returns: a list of TpmModel
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "query-tpm-models" }
+# <- { "return": [ "tpm-tis" ] }
+#
 ##
 { 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
 
@@ -3845,6 +4847,12 @@
 # Returns: a list of TpmType
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "query-tpm-types" }
+# <- { "return": [ "passthrough" ] }
+#
 ##
 { 'command': 'query-tpm-types', 'returns': ['TpmType'] }
 
@@ -3901,6 +4909,25 @@
 # Returns: @TPMInfo on success
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "query-tpm" }
+# <- { "return":
+#      [
+#        { "model": "tpm-tis",
+#          "options":
+#            { "type": "passthrough",
+#              "data":
+#                { "cancel-path": "/sys/class/misc/tpm0/device/cancel",
+#                  "path": "/dev/tpm0"
+#                }
+#            },
+#          "id": "tpm0"
+#        }
+#      ]
+#    }
+#
 ##
 { 'command': 'query-tpm', 'returns': ['TPMInfo'] }
 
@@ -4027,6 +5054,28 @@
 #          @option).  Returns an error if the given @option doesn't exist.
 #
 # Since 1.5
+#
+# Example:
+#
+# -> { "execute": "query-command-line-options",
+#      "arguments": { "option": "option-rom" } }
+# <- { "return": [
+#         {
+#             "parameters": [
+#                 {
+#                     "name": "romfile",
+#                     "type": "string"
+#                 },
+#                 {
+#                     "name": "bootindex",
+#                     "type": "number"
+#                 }
+#             ],
+#             "option": "option-rom"
+#         }
+#      ]
+#    }
+#
 ##
 {'command': 'query-command-line-options', 'data': { '*option': 'str' },
  'returns': ['CommandLineOptionInfo'] }
@@ -4149,6 +5198,36 @@
 #          isn't a NIC.
 #
 # Since: 1.6
+#
+# Example:
+#
+# -> { "execute": "query-rx-filter", "arguments": { "name": "vnet0" } }
+# <- { "return": [
+#         {
+#             "promiscuous": true,
+#             "name": "vnet0",
+#             "main-mac": "52:54:00:12:34:56",
+#             "unicast": "normal",
+#             "vlan": "normal",
+#             "vlan-table": [
+#                 4,
+#                 0
+#             ],
+#             "unicast-table": [
+#             ],
+#             "multicast": "normal",
+#             "multicast-overflow": false,
+#             "unicast-overflow": false,
+#             "multicast-table": [
+#                 "01:00:5e:00:00:01",
+#                 "33:33:00:00:00:01",
+#                 "33:33:ff:12:34:56"
+#             ],
+#             "broadcast-allowed": false
+#         }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-rx-filter', 'data': { '*name': 'str' },
   'returns': ['RxFilterInfo'] }
@@ -4246,9 +5325,9 @@
 #
 # Returns: Nothing on success.
 #
-# The @display and @head parameters can be used to send the input
-# event to specific input devices in case (a) multiple input devices
-# of the same kind are added to the virtual machine and (b) you have
+# The @device and @head parameters can be used to send the input event
+# to specific input devices in case (a) multiple input devices of the
+# same kind are added to the virtual machine and (b) you have
 # configured input routing (see docs/multiseat.txt) for those input
 # devices.  The parameters work exactly like the device and head
 # properties of input devices.  If @device is missing, only devices
@@ -4258,6 +5337,48 @@
 # precedence.
 #
 # Since: 2.6
+#
+# Note: The consoles are visible in the qom tree, under
+# /backend/console[$index]. They have a device link and head property,
+# so it is possible to map which console belongs to which device and
+# display.
+#
+# Example:
+#
+# 1. Press left mouse button.
+#
+# -> { "execute": "input-send-event",
+#     "arguments": { "device": "video0",
+#                    "events": [ { "type": "btn",
+#                    "data" : { "down": true, "button": "left" } } ] } }
+# <- { "return": {} }
+#
+# -> { "execute": "input-send-event",
+#     "arguments": { "device": "video0",
+#                    "events": [ { "type": "btn",
+#                    "data" : { "down": false, "button": "left" } } ] } }
+# <- { "return": {} }
+#
+# 2. Press ctrl-alt-del.
+#
+# -> { "execute": "input-send-event",
+#      "arguments": { "events": [
+#         { "type": "key", "data" : { "down": true,
+#           "key": {"type": "qcode", "data": "ctrl" } } },
+#         { "type": "key", "data" : { "down": true,
+#           "key": {"type": "qcode", "data": "alt" } } },
+#         { "type": "key", "data" : { "down": true,
+#           "key": {"type": "qcode", "data": "delete" } } } ] } }
+# <- { "return": {} }
+#
+# 3. Move mouse pointer to absolute coordinates (20000, 400).
+#
+# -> { "execute": "input-send-event" ,
+#   "arguments": { "events": [
+#                { "type": "abs", "data" : { "axis": "x", "value" : 20000 } },
+#                { "type": "abs", "data" : { "axis": "y", "value" : 400 } } ] } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'input-send-event',
   'data': { '*device': 'str',
@@ -4358,6 +5479,30 @@
 # Returns: a list of @Memdev.
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-memdev" }
+# <- { "return": [
+#        {
+#          "size": 536870912,
+#          "merge": false,
+#          "dump": true,
+#          "prealloc": false,
+#          "host-nodes": [0, 1],
+#          "policy": "bind"
+#        },
+#        {
+#          "size": 536870912,
+#          "merge": false,
+#          "dump": true,
+#          "prealloc": true,
+#          "host-nodes": [2, 3],
+#          "policy": "preferred"
+#        }
+#      ]
+#    }
+#
 ##
 { 'command': 'query-memdev', 'returns': ['Memdev'] }
 
@@ -4411,6 +5556,22 @@
 # Lists available memory devices and their state
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-memory-devices" }
+# <- { "return": [ { "data":
+#                       { "addr": 5368709120,
+#                         "hotpluggable": true,
+#                         "hotplugged": true,
+#                         "id": "d1",
+#                         "memdev": "/objects/memX",
+#                         "node": 0,
+#                         "size": 1073741824,
+#                         "slot": 0},
+#                    "type": "dimm"
+#                  } ] }
+#
 ##
 { 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
 
@@ -4451,10 +5612,20 @@
 ##
 # @query-acpi-ospm-status
 #
-# Lists ACPI OSPM status of ACPI device objects,
-# which might be reported via _OST method
+# Return a list of ACPIOSTInfo for devices that support status
+# reporting via ACPI _OST method.
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-acpi-ospm-status" }
+# <- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
+#                  { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
+#                  { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
+#                  { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
+#    ]}
+#
 ##
 { 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
 
@@ -4521,6 +5692,12 @@
 # command.
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "rtc-reset-reinjection" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'rtc-reset-reinjection' }
 
@@ -4556,6 +5733,13 @@
 # format.
 #
 # Since: 2.7
+#
+# Example:
+#
+# -> { "execute": "xen-load-devices-state",
+#      "arguments": { "filename": "/tmp/resume" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'xen-load-devices-state', 'data': {'filename': 'str'} }
 
@@ -4592,6 +5776,13 @@
 # Returns: a list of GICCapability objects.
 #
 # Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "query-gic-capabilities" }
+# <- { "return": [{ "version": 2, "emulated": true, "kernel": false },
+#                 { "version": 3, "emulated": false, "kernel": true } ] }
+#
 ##
 { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
 
@@ -4648,5 +5839,33 @@
 # Returns: a list of HotpluggableCPU objects.
 #
 # Since: 2.7
+#
+# Example:
+#
+# For pseries machine type started with -smp 2,cores=2,maxcpus=4 -cpu POWER8:
+#
+# -> { "execute": "query-hotpluggable-cpus" }
+# <- {"return": [
+#      { "props": { "core": 8 }, "type": "POWER8-spapr-cpu-core",
+#        "vcpus-count": 1 },
+#      { "props": { "core": 0 }, "type": "POWER8-spapr-cpu-core",
+#        "vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
+#    ]}'
+#
+# For pc machine type started with -smp 1,maxcpus=2:
+#
+# -> { "execute": "query-hotpluggable-cpus" }
+# <- {"return": [
+#      {
+#         "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
+#         "props": {"core-id": 0, "socket-id": 1, "thread-id": 0}
+#      },
+#      {
+#         "qom-path": "/machine/unattached/device[0]",
+#         "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
+#         "props": {"core-id": 0, "socket-id": 0, "thread-id": 0}
+#      }
+#    ]}
+#
 ##
 { 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 73f4180..06bf1d0 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -471,6 +471,87 @@
 # Returns: a list of @BlockInfo describing each virtual block device
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-block" }
+# <- {
+#       "return":[
+#          {
+#             "io-status": "ok",
+#             "device":"ide0-hd0",
+#             "locked":false,
+#             "removable":false,
+#             "inserted":{
+#                "ro":false,
+#                "drv":"qcow2",
+#                "encrypted":false,
+#                "file":"disks/test.qcow2",
+#                "backing_file_depth":1,
+#                "bps":1000000,
+#                "bps_rd":0,
+#                "bps_wr":0,
+#                "iops":1000000,
+#                "iops_rd":0,
+#                "iops_wr":0,
+#                "bps_max": 8000000,
+#                "bps_rd_max": 0,
+#                "bps_wr_max": 0,
+#                "iops_max": 0,
+#                "iops_rd_max": 0,
+#                "iops_wr_max": 0,
+#                "iops_size": 0,
+#                "detect_zeroes": "on",
+#                "write_threshold": 0,
+#                "image":{
+#                   "filename":"disks/test.qcow2",
+#                   "format":"qcow2",
+#                   "virtual-size":2048000,
+#                   "backing_file":"base.qcow2",
+#                   "full-backing-filename":"disks/base.qcow2",
+#                   "backing-filename-format":"qcow2",
+#                   "snapshots":[
+#                      {
+#                         "id": "1",
+#                         "name": "snapshot1",
+#                         "vm-state-size": 0,
+#                         "date-sec": 10000200,
+#                         "date-nsec": 12,
+#                         "vm-clock-sec": 206,
+#                         "vm-clock-nsec": 30
+#                      }
+#                   ],
+#                   "backing-image":{
+#                       "filename":"disks/base.qcow2",
+#                       "format":"qcow2",
+#                       "virtual-size":2048000
+#                   }
+#                }
+#             },
+#             "type":"unknown"
+#          },
+#          {
+#             "io-status": "ok",
+#             "device":"ide1-cd0",
+#             "locked":false,
+#             "removable":true,
+#             "type":"unknown"
+#          },
+#          {
+#             "device":"floppy0",
+#             "locked":false,
+#             "removable":true,
+#             "type":"unknown"
+#          },
+#          {
+#             "device":"sd0",
+#             "locked":false,
+#             "removable":true,
+#             "type":"unknown"
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-block', 'returns': ['BlockInfo'] }
 
@@ -619,6 +700,9 @@
 # @stats:  A @BlockDeviceStats for the device.
 #
 # @parent: #optional This describes the file block device if it has one.
+#          Contains recursively the statistics of the underlying
+#          protocol (e.g. the host file for a qcow2 image). If there is
+#          no underlying protocol, this field is omitted
 #
 # @backing: #optional This describes the backing block device if it has one.
 #           (Since 2.0)
@@ -646,6 +730,106 @@
 # Returns: A list of @BlockStats for each virtual block devices.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-blockstats" }
+# <- {
+#       "return":[
+#          {
+#             "device":"ide0-hd0",
+#             "parent":{
+#                "stats":{
+#                   "wr_highest_offset":3686448128,
+#                   "wr_bytes":9786368,
+#                   "wr_operations":751,
+#                   "rd_bytes":122567168,
+#                   "rd_operations":36772
+#                   "wr_total_times_ns":313253456
+#                   "rd_total_times_ns":3465673657
+#                   "flush_total_times_ns":49653
+#                   "flush_operations":61,
+#                   "rd_merged":0,
+#                   "wr_merged":0,
+#                   "idle_time_ns":2953431879,
+#                   "account_invalid":true,
+#                   "account_failed":false
+#                }
+#             },
+#             "stats":{
+#                "wr_highest_offset":2821110784,
+#                "wr_bytes":9786368,
+#                "wr_operations":692,
+#                "rd_bytes":122739200,
+#                "rd_operations":36604
+#                "flush_operations":51,
+#                "wr_total_times_ns":313253456
+#                "rd_total_times_ns":3465673657
+#                "flush_total_times_ns":49653,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "idle_time_ns":2953431879,
+#                "account_invalid":true,
+#                "account_failed":false
+#             }
+#          },
+#          {
+#             "device":"ide1-cd0",
+#             "stats":{
+#                "wr_highest_offset":0,
+#                "wr_bytes":0,
+#                "wr_operations":0,
+#                "rd_bytes":0,
+#                "rd_operations":0
+#                "flush_operations":0,
+#                "wr_total_times_ns":0
+#                "rd_total_times_ns":0
+#                "flush_total_times_ns":0,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "account_invalid":false,
+#                "account_failed":false
+#             }
+#          },
+#          {
+#             "device":"floppy0",
+#             "stats":{
+#                "wr_highest_offset":0,
+#                "wr_bytes":0,
+#                "wr_operations":0,
+#                "rd_bytes":0,
+#                "rd_operations":0
+#                "flush_operations":0,
+#                "wr_total_times_ns":0
+#                "rd_total_times_ns":0
+#                "flush_total_times_ns":0,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "account_invalid":false,
+#                "account_failed":false
+#             }
+#          },
+#          {
+#             "device":"sd0",
+#             "stats":{
+#                "wr_highest_offset":0,
+#                "wr_bytes":0,
+#                "wr_operations":0,
+#                "rd_bytes":0,
+#                "rd_operations":0
+#                "flush_operations":0,
+#                "wr_total_times_ns":0
+#                "rd_total_times_ns":0
+#                "flush_total_times_ns":0,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "account_invalid":false,
+#                "account_failed":false
+#             }
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-blockstats',
   'data': { '*query-nodes': 'bool' },
@@ -790,6 +974,13 @@
 #         occur if an invalid password is specified.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0",
+#                                                "password": "12345" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block_passwd', 'data': {'*device': 'str',
                                       '*node-name': 'str', 'password': 'str'} }
@@ -811,6 +1002,13 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "block_resize",
+#      "arguments": { "device": "scratch", "size": 1073741824 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block_resize', 'data': { '*device': 'str',
                                        '*node-name': 'str',
@@ -842,7 +1040,9 @@
 #
 # @node-name: #optional graph node name to generate the snapshot from (Since 2.0)
 #
-# @snapshot-file: the target of the new image. A new file will be created.
+# @snapshot-file: the target of the new image. If the file exists, or
+# if it is a device, the snapshot will be created in the existing
+# file/device. Otherwise, a new file will be created.
 #
 # @snapshot-node-name: #optional the graph node name of the new image (Since 2.0)
 #
@@ -976,6 +1176,16 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since 0.14.0
+#
+# Example:
+#
+# -> { "execute": "blockdev-snapshot-sync",
+#      "arguments": { "device": "ide-hd0",
+#                     "snapshot-file":
+#                     "/some/place/my-image",
+#                     "format": "qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-snapshot-sync',
   'data': 'BlockdevSnapshotSync' }
@@ -986,9 +1196,31 @@
 #
 # Generates a snapshot of a block device.
 #
+# Create a snapshot, by installing 'node' as the backing image of
+# 'overlay'. Additionally, if 'node' is associated with a block
+# device, the block device changes to using 'overlay' as its new active
+# image.
+#
 # For the arguments, see the documentation of BlockdevSnapshot.
 #
 # Since 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-add",
+#      "arguments": { "options": { "driver": "qcow2",
+#                                  "node-name": "node1534",
+#                                  "file": { "driver": "file",
+#                                            "filename": "hd1.qcow2" },
+#                                  "backing": "" } } }
+#
+# <- { "return": {} }
+#
+# -> { "execute": "blockdev-snapshot",
+#      "arguments": { "node": "ide-hd0",
+#                     "overlay": "node1534" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-snapshot',
   'data': 'BlockdevSnapshot' }
@@ -1004,7 +1236,9 @@
 # updated.
 #
 # @image-node-name: The name of the block driver state node of the
-#                   image to modify.
+#                   image to modify. The "device" argument is used
+#                   to verify "image-node-name" is in the chain
+#                   described by "device".
 #
 # @device:          The device name or node-name of the root node that owns
 #                   image-node-name.
@@ -1014,6 +1248,10 @@
 #                   when specifying the string or the image chain may
 #                   not be able to be reopened again.
 #
+# Returns: Nothing on success
+#
+#          If "device" does not exist or cannot be determined, DeviceNotFound
+#
 # Since: 2.1
 ##
 { 'command': 'change-backing-file',
@@ -1032,7 +1270,7 @@
 # @device:  the device name or node-name of a root node
 #
 # @base:   #optional The file name of the backing image to write data into.
-#                    If not specified, this is the deepest backing image
+#                    If not specified, this is the deepest backing image.
 #
 # @top:    #optional The file name of the backing image within the image chain,
 #                    which contains the topmost data to be committed down. If
@@ -1078,6 +1316,13 @@
 #
 # Since: 1.3
 #
+# Example:
+#
+# -> { "execute": "block-commit",
+#      "arguments": { "device": "virtio0",
+#                     "top": "/tmp/snap1.qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-commit',
   'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', '*top': 'str',
@@ -1098,6 +1343,15 @@
 #          If @device is not a valid block device, GenericError
 #
 # Since 1.6
+#
+# Example:
+#
+# -> { "execute": "drive-backup",
+#      "arguments": { "device": "drive0",
+#                     "sync": "full",
+#                     "target": "backup.img" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'drive-backup', 'boxed': true,
   'data': 'DriveBackup' }
@@ -1117,6 +1371,14 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since 2.3
+#
+# Example:
+# -> { "execute": "blockdev-backup",
+#      "arguments": { "device": "src-id",
+#                     "sync": "full",
+#                     "target": "tgt-id" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-backup', 'boxed': true,
   'data': 'BlockdevBackup' }
@@ -1130,13 +1392,67 @@
 # Returns: the list of BlockDeviceInfo
 #
 # Since 2.0
+#
+# Example:
+#
+# -> { "execute": "query-named-block-nodes" }
+# <- { "return": [ { "ro":false,
+#                    "drv":"qcow2",
+#                    "encrypted":false,
+#                    "file":"disks/test.qcow2",
+#                    "node-name": "my-node",
+#                    "backing_file_depth":1,
+#                    "bps":1000000,
+#                    "bps_rd":0,
+#                    "bps_wr":0,
+#                    "iops":1000000,
+#                    "iops_rd":0,
+#                    "iops_wr":0,
+#                    "bps_max": 8000000,
+#                    "bps_rd_max": 0,
+#                    "bps_wr_max": 0,
+#                    "iops_max": 0,
+#                    "iops_rd_max": 0,
+#                    "iops_wr_max": 0,
+#                    "iops_size": 0,
+#                    "write_threshold": 0,
+#                    "image":{
+#                       "filename":"disks/test.qcow2",
+#                       "format":"qcow2",
+#                       "virtual-size":2048000,
+#                       "backing_file":"base.qcow2",
+#                       "full-backing-filename":"disks/base.qcow2",
+#                       "backing-filename-format":"qcow2",
+#                       "snapshots":[
+#                          {
+#                             "id": "1",
+#                             "name": "snapshot1",
+#                             "vm-state-size": 0,
+#                             "date-sec": 10000200,
+#                             "date-nsec": 12,
+#                             "vm-clock-sec": 206,
+#                             "vm-clock-nsec": 30
+#                          }
+#                       ],
+#                       "backing-image":{
+#                           "filename":"disks/base.qcow2",
+#                           "format":"qcow2",
+#                           "virtual-size":2048000
+#                       }
+#                    } } ] }
+#
 ##
 { 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] }
 
 ##
 # @drive-mirror
 #
-# Start mirroring a block device's writes to a new destination.
+# Start mirroring a block device's writes to a new destination. target
+# specifies the target of the new image. If the file exists, or if it
+# is a device, it will be used as the new destination for writes. If
+# it does not exist, a new file will be created. format specifies the
+# format of the mirror image, default is to probe if mode='existing',
+# else the format of the source.
 #
 # See DriveMirror for parameter descriptions
 #
@@ -1144,6 +1460,16 @@
 #          If @device is not a valid block device, GenericError
 #
 # Since 1.3
+#
+# Example:
+#
+# -> { "execute": "drive-mirror",
+#      "arguments": { "device": "ide-hd0",
+#                     "target": "/some/place/my-image",
+#                     "sync": "full",
+#                     "format": "qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'drive-mirror', 'boxed': true,
   'data': 'DriveMirror' }
@@ -1244,13 +1570,20 @@
 ##
 # @block-dirty-bitmap-add
 #
-# Create a dirty bitmap with a name on the node
+# Create a dirty bitmap with a name on the node, and start tracking the writes.
 #
 # Returns: nothing on success
 #          If @node is not a valid block device or node, DeviceNotFound
 #          If @name is already taken, GenericError with an explanation
 #
 # Since 2.4
+#
+# Example:
+#
+# -> { "execute": "block-dirty-bitmap-add",
+#      "arguments": { "node": "drive0", "name": "bitmap0" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-dirty-bitmap-add',
   'data': 'BlockDirtyBitmapAdd' }
@@ -1258,7 +1591,8 @@
 ##
 # @block-dirty-bitmap-remove
 #
-# Remove a dirty bitmap on the node
+# Stop write tracking and remove the dirty bitmap that was created
+# with block-dirty-bitmap-add.
 #
 # Returns: nothing on success
 #          If @node is not a valid block device or node, DeviceNotFound
@@ -1266,6 +1600,13 @@
 #          if @name is frozen by an operation, GenericError
 #
 # Since 2.4
+#
+# Example:
+#
+# -> { "execute": "block-dirty-bitmap-remove",
+#      "arguments": { "node": "drive0", "name": "bitmap0" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-dirty-bitmap-remove',
   'data': 'BlockDirtyBitmap' }
@@ -1273,13 +1614,22 @@
 ##
 # @block-dirty-bitmap-clear
 #
-# Clear (reset) a dirty bitmap on the device
+# Clear (reset) a dirty bitmap on the device, so that an incremental
+# backup from this point in time forward will only backup clusters
+# modified after this clear operation.
 #
 # Returns: nothing on success
 #          If @node is not a valid block device, DeviceNotFound
 #          If @name is not found, GenericError with an explanation
 #
 # Since 2.4
+#
+# Example:
+#
+# -> { "execute": "block-dirty-bitmap-clear",
+#      "arguments": { "node": "drive0", "name": "bitmap0" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-dirty-bitmap-clear',
   'data': 'BlockDirtyBitmap' }
@@ -1327,6 +1677,15 @@
 # Returns: nothing on success.
 #
 # Since 2.6
+#
+# Example:
+#
+# -> { "execute": "blockdev-mirror",
+#      "arguments": { "device": "ide-hd0",
+#                     "target": "target0",
+#                     "sync": "full" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-mirror',
   'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
@@ -1368,6 +1727,26 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since: 1.1
+#
+# Example:
+#
+# -> { "execute": "block_set_io_throttle",
+#      "arguments": { "id": "ide0-1-0",
+#                     "bps": 1000000,
+#                     "bps_rd": 0,
+#                     "bps_wr": 0,
+#                     "iops": 0,
+#                     "iops_rd": 0,
+#                     "iops_wr": 0,
+#                     "bps_max": 8000000,
+#                     "bps_rd_max": 0,
+#                     "bps_wr_max": 0,
+#                     "iops_max": 0,
+#                     "iops_rd_max": 0,
+#                     "iops_wr_max": 0,
+#                     "bps_max_length": 60,
+#                     "iops_size": 0 } }
+# <- { "return": {} }
 ##
 { 'command': 'block_set_io_throttle', 'boxed': true,
   'data': 'BlockIOThrottle' }
@@ -1505,7 +1884,17 @@
 #            'stop' and 'enospc' can only be used if the block device
 #            supports io-status (see BlockInfo).  Since 1.3.
 #
+# Returns: Nothing on success. If @device does not exist, DeviceNotFound.
+#
 # Since: 1.1
+#
+# Example:
+#
+# -> { "execute": "block-stream",
+#      "arguments": { "device": "virtio0",
+#                     "base": "/tmp/master.qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-stream',
   'data': { '*job-id': 'str', 'device': 'str', '*base': 'str',
@@ -2302,13 +2691,52 @@
 # BlockBackend will be created; otherwise, @node-name is mandatory at the top
 # level and no BlockBackend will be created.
 #
-# This command is still a work in progress.  It doesn't support all
+# Note: This command is still a work in progress.  It doesn't support all
 # block drivers among other things.  Stay away from it unless you want
 # to help with its development.
 #
 # @options: block device options for the new device
 #
 # Since: 1.7
+#
+# Example:
+#
+# 1.
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options" : { "driver": "qcow2",
+#                        "file": { "driver": "file",
+#                                  "filename": "test.qcow2" } } } }
+# <- { "return": {} }
+#
+# 2.
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": {
+#            "driver": "qcow2",
+#            "node-name": "node0",
+#            "discard": "unmap",
+#            "cache": {
+#                "direct": true,
+#                "writeback": true
+#            },
+#            "file": {
+#                "driver": "file",
+#                "filename": "/tmp/test.qcow2"
+#            },
+#            "backing": {
+#                "driver": "raw",
+#                "file": {
+#                    "driver": "file",
+#                    "filename": "/dev/fdset/4"
+#                }
+#            }
+#          }
+#        }
+#      }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
 
@@ -2326,6 +2754,28 @@
 # @node-name: Name of the graph node to delete.
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": {
+#              "driver": "qcow2",
+#              "node-name": "node0",
+#              "file": {
+#                  "driver": "file",
+#                  "filename": "test.qcow2"
+#              }
+#          }
+#      }
+#    }
+# <- { "return": {} }
+#
+# -> { "execute": "x-blockdev-del",
+#      "arguments": { "node-name": "node0" }
+#    }
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-del', 'data': { 'node-name': 'str' } }
 
@@ -2357,6 +2807,20 @@
 #          it is locked
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-open-tray",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "timestamp": { "seconds": 1418751016,
+#                     "microseconds": 716996 },
+#      "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "tray-open": true } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-open-tray',
   'data': { '*device': 'str',
@@ -2377,6 +2841,20 @@
 # @id:      #optional The name or QOM path of the guest device (since: 2.8)
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-close-tray",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "timestamp": { "seconds": 1418751345,
+#                     "microseconds": 272147 },
+#      "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "tray-open": false } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-close-tray',
   'data': { '*device': 'str',
@@ -2399,6 +2877,31 @@
 # @id:     #optional The name or QOM path of the guest device (since: 2.8)
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "x-blockdev-remove-medium",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "error": { "class": "GenericError",
+#                 "desc": "Tray of device 'ide0-1-0' is not open" } }
+#
+# -> { "execute": "blockdev-open-tray",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "timestamp": { "seconds": 1418751627,
+#                     "microseconds": 549958 },
+#      "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "tray-open": true } }
+#
+# <- { "return": {} }
+#
+# -> { "execute": "x-blockdev-remove-medium",
+#      "arguments": { "device": "ide0-1-0" } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-remove-medium',
   'data': { '*device': 'str',
@@ -2421,6 +2924,23 @@
 # @node-name: name of a node in the block driver state graph
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": { "node-name": "node0",
+#                       "driver": "raw",
+#                       "file": { "driver": "file",
+#                                 "filename": "fedora.iso" } } } }
+# <- { "return": {} }
+#
+# -> { "execute": "x-blockdev-insert-medium",
+#      "arguments": { "id": "ide0-1-0",
+#                     "node-name": "node0" } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-insert-medium',
   'data': { '*device': 'str',
@@ -2441,6 +2961,7 @@
 # @read-write:  Makes the device writable
 #
 # Since: 2.3
+#
 ##
 { 'enum': 'BlockdevChangeReadOnlyMode',
   'data': ['retain', 'read-only', 'read-write'] }
@@ -2468,6 +2989,37 @@
 #                   to 'retain'
 #
 # Since: 2.5
+#
+# Examples:
+#
+# 1. Change a removable medium
+#
+# -> { "execute": "blockdev-change-medium",
+#      "arguments": { "id": "ide0-1-0",
+#                     "filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
+#                     "format": "raw" } }
+# <- { "return": {} }
+#
+# 2. Load a read-only medium into a writable drive
+#
+# -> { "execute": "blockdev-change-medium",
+#      "arguments": { "id": "floppyA",
+#                     "filename": "/srv/images/ro.img",
+#                     "format": "raw",
+#                     "read-only-mode": "retain" } }
+#
+# <- { "error":
+#      { "class": "GenericError",
+#        "desc": "Could not open '/srv/images/ro.img': Permission denied" } }
+#
+# -> { "execute": "blockdev-change-medium",
+#      "arguments": { "id": "floppyA",
+#                     "filename": "/srv/images/ro.img",
+#                     "format": "raw",
+#                     "read-only-mode": "read-only" } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-change-medium',
   'data': { '*device': 'str',
@@ -2497,7 +3049,10 @@
 ##
 # @BLOCK_IMAGE_CORRUPTED
 #
-# Emitted when a corruption has been detected in a disk image
+# Emitted when a disk image is being marked corrupt. The image can be
+# identified by its device or node name. The 'device' field is always
+# present for compatibility reasons, but it can be empty ("") if the
+# image does not have a device name associated.
 #
 # @device: device name. This is always present for compatibility
 #          reasons, but it can be empty ("") if the image does not
@@ -2515,10 +3070,18 @@
 # @size: #optional, if the corruption resulted from an image access, this is
 #        the access size
 #
-# fatal: if set, the image is marked corrupt and therefore unusable after this
+# @fatal: if set, the image is marked corrupt and therefore unusable after this
 #        event and must be repaired (Since 2.2; before, every
 #        BLOCK_IMAGE_CORRUPTED event was fatal)
 #
+# Example:
+#
+# <- { "event": "BLOCK_IMAGE_CORRUPTED",
+#      "data": { "device": "ide0-hd0", "node-name": "node0",
+#                "msg": "Prevented active L1 table overwrite", "offset": 196608,
+#                "size": 65536 },
+#      "timestamp": { "seconds": 1378126126, "microseconds": 966463 } }
+#
 # Since: 1.7
 ##
 { 'event': 'BLOCK_IMAGE_CORRUPTED',
@@ -2553,6 +3116,15 @@
 # BLOCK_IO_ERROR event
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "BLOCK_IO_ERROR",
+#      "data": { "device": "ide0-hd1",
+#                "operation": "write",
+#                "action": "stop" },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'BLOCK_IO_ERROR',
   'data': { 'device': 'str', 'operation': 'IoOperationType',
@@ -2582,6 +3154,15 @@
 #         interpret the error string
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_COMPLETED",
+#      "data": { "type": "stream", "device": "virtio-disk0",
+#                "len": 10737418240, "offset": 10737418240,
+#                "speed": 0 },
+#      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+#
 ##
 { 'event': 'BLOCK_JOB_COMPLETED',
   'data': { 'type'  : 'BlockJobType',
@@ -2609,6 +3190,15 @@
 # @speed: rate limit, bytes per second
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_CANCELLED",
+#      "data": { "type": "stream", "device": "virtio-disk0",
+#                "len": 10737418240, "offset": 134217728,
+#                "speed": 0 },
+#      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+#
 ##
 { 'event': 'BLOCK_JOB_CANCELLED',
   'data': { 'type'  : 'BlockJobType',
@@ -2630,6 +3220,15 @@
 # @action: action that has been taken
 #
 # Since: 1.3
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_ERROR",
+#      "data": { "device": "ide0-hd1",
+#                "operation": "write",
+#                "action": "stop" },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'BLOCK_JOB_ERROR',
   'data': { 'device'   : 'str',
@@ -2657,6 +3256,14 @@
 # event
 #
 # Since: 1.3
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_READY",
+#      "data": { "device": "drive0", "type": "mirror", "speed": 0,
+#                "len": 2097152, "offset": 2097152 }
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'BLOCK_JOB_READY',
   'data': { 'type'  : 'BlockJobType',
@@ -2709,8 +3316,12 @@
 ##
 # @block-set-write-threshold
 #
-# Change the write threshold for a block drive. An event will be delivered
-# if a write to this block drive crosses the configured threshold.
+# Change the write threshold for a block drive. An event will be
+# delivered if a write to this block drive crosses the configured
+# threshold.  The threshold is an offset, thus must be
+# non-negative. Default is no write threshold. Setting the threshold
+# to zero disables it.
+#
 # This is useful to transparently resize thin-provisioned drives without
 # the guest OS noticing.
 #
@@ -2720,6 +3331,14 @@
 #                   Use 0 to disable the threshold.
 #
 # Since: 2.3
+#
+# Example:
+#
+# -> { "execute": "block-set-write-threshold",
+#      "arguments": { "node-name": "mydev",
+#                     "write-threshold": 17179869184 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-set-write-threshold',
   'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
@@ -2750,6 +3369,28 @@
 # the rest of the array.
 #
 # Since: 2.7
+#
+# Example:
+#
+# 1. Add a new node to a quorum
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": { "driver": "raw",
+#                       "node-name": "new_node",
+#                        "file": { "driver": "file",
+#                                  "filename": "test.raw" } } } }
+# <- { "return": {} }
+# -> { "execute": "x-blockdev-change",
+#      "arguments": { "parent": "disk1",
+#                     "node": "new_node" } }
+# <- { "return": {} }
+#
+# 2. Delete a quorum's node
+# -> { "execute": "x-blockdev-change",
+#      "arguments": { "parent": "disk1",
+#                     "child": "children.1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-change',
   'data' : { 'parent': 'str',
diff --git a/qapi/block.json b/qapi/block.json
index c896bd1..b88ab3c 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -75,19 +75,33 @@
 ##
 # @blockdev-snapshot-internal-sync
 #
-# Synchronously take an internal snapshot of a block device, when the format
-# of the image used supports it.
+# Synchronously take an internal snapshot of a block device, when the
+# format of the image used supports it. If the name is an empty
+# string, or a snapshot with name already exists, the operation will
+# fail.
 #
 # For the arguments, see the documentation of BlockdevSnapshotInternal.
 #
 # Returns: nothing on success
+#
 #          If @device is not a valid block device, GenericError
+#
 #          If any snapshot matching @name exists, or @name is empty,
 #          GenericError
+#
 #          If the format of the image used does not support it,
 #          BlockFormatFeatureNotSupported
 #
 # Since 1.7
+#
+# Example:
+#
+# -> { "execute": "blockdev-snapshot-internal-sync",
+#      "arguments": { "device": "ide-hd0",
+#                     "name": "snapshot0" }
+#    }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-snapshot-internal-sync',
   'data': 'BlockdevSnapshotInternal' }
@@ -115,6 +129,24 @@
 #          If @id and @name are both not specified, GenericError
 #
 # Since 1.7
+#
+# Example:
+#
+# -> { "execute": "blockdev-snapshot-delete-internal-sync",
+#      "arguments": { "device": "ide-hd0",
+#                     "name": "snapshot0" }
+#    }
+# <- { "return": {
+#                    "id": "1",
+#                    "name": "snapshot0",
+#                    "vm-state-size": 0,
+#                    "date-sec": 1000012,
+#                    "date-nsec": 10,
+#                    "vm-clock-sec": 100,
+#                    "vm-clock-nsec": 20
+#      }
+#    }
+#
 ##
 { 'command': 'blockdev-snapshot-delete-internal-sync',
   'data': { 'device': 'str', '*id': 'str', '*name': 'str'},
@@ -129,15 +161,21 @@
 #
 # @id:      #optional The name or QOM path of the guest device (since: 2.8)
 #
-# @force:   @optional If true, eject regardless of whether the drive is locked.
+# @force:   #optional If true, eject regardless of whether the drive is locked.
 #           If not specified, the default value is false.
 #
 # Returns:  Nothing on success
+#
 #           If @device is not a valid block device, DeviceNotFound
 #
-# Notes:    Ejecting a device will no media results in success
+# Notes:    Ejecting a device with no media results in success
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "eject", "arguments": { "device": "ide1-0-1" } }
+# <- { "return": {} }
 ##
 { 'command': 'eject',
   'data': { '*device': 'str',
@@ -200,6 +238,15 @@
 # @tray-open: true if the tray has been opened or false if it has been closed
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "tray-open": true
+#      },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'DEVICE_TRAY_MOVED',
   'data': { 'device': 'str', 'tray-open': 'bool' } }
diff --git a/qapi/common.json b/qapi/common.json
index 9353a7b..927d621 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -34,11 +34,11 @@
 #
 # A three-part version number.
 #
-# @qemu.major:  The major version number.
+# @major:  The major version number.
 #
-# @qemu.minor:  The minor version number.
+# @minor:  The minor version number.
 #
-# @qemu.micro:  The micro version number.
+# @micro:  The micro version number.
 #
 # Since: 2.4
 ##
@@ -75,6 +75,21 @@
 # Returns:  A @VersionInfo object describing the current version of QEMU.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-version" }
+# <- {
+#       "return":{
+#          "qemu":{
+#             "major":0,
+#             "minor":11,
+#             "micro":5
+#          },
+#          "package":""
+#       }
+#    }
+#
 ##
 { 'command': 'query-version', 'returns': 'VersionInfo' }
 
@@ -97,6 +112,23 @@
 # Returns: A list of @CommandInfo for all supported commands
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-commands" }
+# <- {
+#      "return":[
+#         {
+#            "name":"query-balloon"
+#         },
+#         {
+#            "name":"system_powerdown"
+#         }
+#      ]
+#    }
+#
+# Note: This example has been shortened as the real response is too long.
+#
 ##
 { 'command': 'query-commands', 'returns': ['CommandInfo'] }
 
diff --git a/qapi/event.json b/qapi/event.json
index 8642052..51205b8 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -8,6 +8,12 @@
 # not exit, and a STOP event will eventually follow the SHUTDOWN event
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "SHUTDOWN",
+#      "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
+#
 ##
 { 'event': 'SHUTDOWN' }
 
@@ -18,6 +24,12 @@
 # system, such as via ACPI.
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "POWERDOWN",
+#      "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
+#
 ##
 { 'event': 'POWERDOWN' }
 
@@ -27,6 +39,12 @@
 # Emitted when the virtual machine is reset
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "RESET",
+#      "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
+#
 ##
 { 'event': 'RESET' }
 
@@ -36,6 +54,12 @@
 # Emitted when the virtual machine is stopped
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "STOP",
+#      "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
+#
 ##
 { 'event': 'STOP' }
 
@@ -45,6 +69,12 @@
 # Emitted when the virtual machine resumes execution
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "RESUME",
+#      "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
+#
 ##
 { 'event': 'RESUME' }
 
@@ -55,6 +85,12 @@
 # which is sometimes called standby state
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "SUSPEND",
+#      "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+#
 ##
 { 'event': 'SUSPEND' }
 
@@ -67,6 +103,12 @@
 # Note: QEMU shuts down (similar to event @SHUTDOWN) when entering this state
 #
 # Since: 1.2
+#
+# Example:
+#
+# <-   { "event": "SUSPEND_DISK",
+#        "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+#
 ##
 { 'event': 'SUSPEND_DISK' }
 
@@ -76,6 +118,12 @@
 # Emitted when the guest has woken up from suspend state and is running
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "WAKEUP",
+#      "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+#
 ##
 { 'event': 'WAKEUP' }
 
@@ -87,7 +135,16 @@
 # @offset: offset between base RTC clock (as specified by -rtc base), and
 #          new RTC clock value
 #
+# Note: This event is rate-limited.
+#
 # Since: 0.13.0
+#
+# Example:
+#
+# <-   { "event": "RTC_CHANGE",
+#        "data": { "offset": 78 },
+#        "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+#
 ##
 { 'event': 'RTC_CHANGE',
   'data': { 'offset': 'int' } }
@@ -102,7 +159,16 @@
 # Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
 # followed respectively by the RESET, SHUTDOWN, or STOP events
 #
+# Note: This event is rate-limited.
+#
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "WATCHDOG",
+#      "data": { "action": "reset" },
+#      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+#
 ##
 { 'event': 'WATCHDOG',
   'data': { 'action': 'WatchdogExpirationAction' } }
@@ -119,6 +185,14 @@
 # @path: device path
 #
 # Since: 1.5
+#
+# Example:
+#
+# <- { "event": "DEVICE_DELETED",
+#      "data": { "device": "virtio-net-pci-0",
+#                "path": "/machine/peripheral/virtio-net-pci-0" },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'DEVICE_DELETED',
   'data': { '*device': 'str', 'path': 'str' } }
@@ -134,6 +208,15 @@
 # @path: device path
 #
 # Since: 1.6
+#
+# Example:
+#
+# <- { "event": "NIC_RX_FILTER_CHANGED",
+#      "data": { "name": "vnet0",
+#                "path": "/machine/peripheral/vnet0/virtio-backend" },
+#      "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
+#    }
+#
 ##
 { 'event': 'NIC_RX_FILTER_CHANGED',
   'data': { '*name': 'str', 'path': 'str' } }
@@ -151,6 +234,17 @@
 # the authentication ID is not provided
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "VNC_CONNECTED",
+#      "data": {
+#            "server": { "auth": "sasl", "family": "ipv4",
+#                        "service": "5901", "host": "0.0.0.0" },
+#            "client": { "family": "ipv4", "service": "58425",
+#                        "host": "127.0.0.1" } },
+#      "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+#
 ##
 { 'event': 'VNC_CONNECTED',
   'data': { 'server': 'VncServerInfo',
@@ -167,6 +261,17 @@
 # @client: client information
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <-  { "event": "VNC_INITIALIZED",
+#       "data": {
+#            "server": { "auth": "sasl", "family": "ipv4",
+#                        "service": "5901", "host": "0.0.0.0"},
+#            "client": { "family": "ipv4", "service": "46089",
+#                        "host": "127.0.0.1", "sasl_username": "luiz" } },
+#       "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
+#
 ##
 { 'event': 'VNC_INITIALIZED',
   'data': { 'server': 'VncServerInfo',
@@ -182,6 +287,17 @@
 # @client: client information
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "VNC_DISCONNECTED",
+#      "data": {
+#            "server": { "auth": "sasl", "family": "ipv4",
+#                        "service": "5901", "host": "0.0.0.0" },
+#            "client": { "family": "ipv4", "service": "58425",
+#                        "host": "127.0.0.1", "sasl_username": "luiz" } },
+#      "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+#
 ##
 { 'event': 'VNC_DISCONNECTED',
   'data': { 'server': 'VncServerInfo',
@@ -197,6 +313,16 @@
 # @client: client information
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+#      "event": "SPICE_CONNECTED",
+#      "data": {
+#        "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+#        "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+#    }}
+#
 ##
 { 'event': 'SPICE_CONNECTED',
   'data': { 'server': 'SpiceBasicInfo',
@@ -213,6 +339,18 @@
 # @client: client information
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+#      "event": "SPICE_INITIALIZED",
+#      "data": {"server": {"auth": "spice", "port": "5921",
+#                          "family": "ipv4", "host": "127.0.0.1"},
+#               "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
+#                          "connection-id": 1804289383, "host": "127.0.0.1",
+#                          "channel-id": 0, "tls": true}
+#    }}
+#
 ##
 { 'event': 'SPICE_INITIALIZED',
   'data': { 'server': 'SpiceServerInfo',
@@ -228,6 +366,16 @@
 # @client: client information
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+#      "event": "SPICE_DISCONNECTED",
+#      "data": {
+#        "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+#        "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+#    }}
+#
 ##
 { 'event': 'SPICE_DISCONNECTED',
   'data': { 'server': 'SpiceBasicInfo',
@@ -239,6 +387,12 @@
 # Emitted when SPICE migration has completed
 #
 # Since: 1.3
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+#      "event": "SPICE_MIGRATE_COMPLETED" }
+#
 ##
 { 'event': 'SPICE_MIGRATE_COMPLETED' }
 
@@ -250,6 +404,13 @@
 # @status: @MigrationStatus describing the current migration status.
 #
 # Since: 2.4
+#
+# Example:
+#
+# <- {"timestamp": {"seconds": 1432121972, "microseconds": 744001},
+#     "event": "MIGRATION",
+#     "data": {"status": "completed"} }
+#
 ##
 { 'event': 'MIGRATION',
   'data': {'status': 'MigrationStatus'}}
@@ -263,6 +424,12 @@
 # @pass: An incrementing count (starting at 1 on the first pass)
 #
 # Since: 2.6
+#
+# Example:
+#
+# { "timestamp": {"seconds": 1449669631, "microseconds": 239225},
+#   "event": "MIGRATION_PASS", "data": {"pass": 2} }
+#
 ##
 { 'event': 'MIGRATION_PASS',
   'data': { 'pass': 'int' } }
@@ -275,6 +442,13 @@
 # Since: 2.1
 #
 # @info: ACPIOSTInfo type as described in qapi-schema.json
+#
+# Example:
+#
+# <- { "event": "ACPI_DEVICE_OST",
+#      "data": { "device": "d1", "slot": "0",
+#                "slot-type": "DIMM", "source": 1, "status": 0 } }
+#
 ##
 { 'event': 'ACPI_DEVICE_OST',
      'data': { 'info': 'ACPIOSTInfo' } }
@@ -287,7 +461,16 @@
 #
 # @actual: actual level of the guest memory balloon in bytes
 #
+# Note: this event is rate-limited.
+#
 # Since: 1.2
+#
+# Example:
+#
+# <- { "event": "BALLOON_CHANGE",
+#      "data": { "actual": 944766976 },
+#      "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+#
 ##
 { 'event': 'BALLOON_CHANGE',
   'data': { 'actual': 'int' } }
@@ -300,6 +483,12 @@
 # @action: action that has been taken, currently always "pause"
 #
 # Since: 1.5
+#
+# Example:
+#
+# <- { "event": "GUEST_PANICKED",
+#      "data": { "action": "pause" } }
+#
 ##
 { 'event': 'GUEST_PANICKED',
   'data': { 'action': 'GuestPanicAction' } }
@@ -315,7 +504,16 @@
 #
 # @sectors-count: failed read operation sector count
 #
+# Note: This event is rate-limited.
+#
 # Since: 2.0
+#
+# Example:
+#
+# <- { "event": "QUORUM_FAILURE",
+#      "data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 },
+#      "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+#
 ##
 { 'event': 'QUORUM_FAILURE',
   'data': { 'reference': 'str', 'sector-num': 'int', 'sectors-count': 'int' } }
@@ -338,7 +536,26 @@
 #
 # @sectors-count: failed read operation sector count
 #
+# Note: This event is rate-limited.
+#
 # Since: 2.0
+#
+# Example:
+#
+# 1. Read operation
+#
+# { "event": "QUORUM_REPORT_BAD",
+#      "data": { "node-name": "node0", "sector-num": 345435, "sectors-count": 5,
+#                "type": "read" },
+#      "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+#
+# 2. Flush operation
+#
+# { "event": "QUORUM_REPORT_BAD",
+#      "data": { "node-name": "node0", "sector-num": 0, "sectors-count": 2097120,
+#                "type": "flush", "error": "Broken pipe" },
+#      "timestamp": { "seconds": 1456406829, "microseconds": 291763 } }
+#
 ##
 { 'event': 'QUORUM_REPORT_BAD',
   'data': { 'type': 'QuorumOpType', '*error': 'str', 'node-name': 'str',
@@ -354,6 +571,13 @@
 # @open: true if the guest has opened the virtio-serial port
 #
 # Since: 2.1
+#
+# Example:
+#
+# <- { "event": "VSERPORT_CHANGE",
+#      "data": { "id": "channel0", "open": true },
+#      "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
+#
 ##
 { 'event': 'VSERPORT_CHANGE',
   'data': { 'id': 'str', 'open': 'bool' } }
@@ -368,6 +592,15 @@
 # @msg: Informative message
 #
 # Since: 2.4
+#
+# Example:
+#
+# <- { "event": "MEM_UNPLUG_ERROR"
+#      "data": { "device": "dimm1",
+#                "msg": "acpi: device unplug for unsupported device"
+#      },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'MEM_UNPLUG_ERROR',
   'data': { 'device': 'str', 'msg': 'str' } }
@@ -384,6 +617,13 @@
 #         user should not try to interpret the error string.
 #
 # Since: 2.6
+#
+# Example:
+#
+# { "event": "DUMP_COMPLETED",
+#   "data": {"result": {"total": 1090650112, "status": "completed",
+#                       "completed": 1090650112} } }
+#
 ##
 { 'event': 'DUMP_COMPLETED' ,
   'data': { 'result': 'DumpQueryResult', '*error': 'str' } }
diff --git a/qapi/rocker.json b/qapi/rocker.json
index 2fe7fdf..9ed233c 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -22,6 +22,12 @@
 # Returns: @Rocker information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker", "arguments": { "name": "sw1" } }
+# <- { "return": {"name": "sw1", "ports": 2, "id": 1327446905938}}
+#
 ##
 { 'command': 'query-rocker',
   'data': { 'name': 'str' },
@@ -80,11 +86,21 @@
 ##
 # @query-rocker-ports:
 #
-# Return rocker switch information.
+# Return rocker switch port information.
 #
-# Returns: @Rocker information
+# Returns: a list of @RockerPort information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker-ports", "arguments": { "name": "sw1" } }
+# <- { "return": [ {"duplex": "full", "enabled": true, "name": "sw1.1",
+#                   "autoneg": "off", "link-up": true, "speed": 10000},
+#                  {"duplex": "full", "enabled": true, "name": "sw1.2",
+#                   "autoneg": "off", "link-up": true, "speed": 10000}
+#    ]}
+#
 ##
 { 'command': 'query-rocker-ports',
   'data': { 'name': 'str' },
@@ -215,9 +231,23 @@
 # @tbl-id: #optional flow table ID.  If tbl-id is not specified, returns
 # flow information for all tables.
 #
-# Returns: @Rocker OF-DPA flow information
+# Returns: rocker OF-DPA flow information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker-of-dpa-flows",
+#      "arguments": { "name": "sw1" } }
+# <- { "return": [ {"key": {"in-pport": 0, "priority": 1, "tbl-id": 0},
+#                   "hits": 138,
+#                   "cookie": 0,
+#                   "action": {"goto-tbl": 10},
+#                   "mask": {"in-pport": 4294901760}
+#                  },
+#                  {...more...},
+#    ]}
+#
 ##
 { 'command': 'query-rocker-of-dpa-flows',
   'data': { 'name': 'str', '*tbl-id': 'uint32' },
@@ -277,9 +307,28 @@
 # @type: #optional group type.  If type is not specified, returns
 # group information for all group types.
 #
-# Returns: @Rocker OF-DPA group information
+# Returns: rocker OF-DPA group information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker-of-dpa-groups",
+#      "arguments": { "name": "sw1" } }
+# <- { "return": [ {"type": 0, "out-pport": 2,
+#                   "pport": 2, "vlan-id": 3841,
+#                   "pop-vlan": 1, "id": 251723778},
+#                  {"type": 0, "out-pport": 0,
+#                   "pport": 0, "vlan-id": 3841,
+#                   "pop-vlan": 1, "id": 251723776},
+#                  {"type": 0, "out-pport": 1,
+#                   "pport": 1, "vlan-id": 3840,
+#                   "pop-vlan": 1, "id": 251658241},
+#                  {"type": 0, "out-pport": 0,
+#                   "pport": 0, "vlan-id": 3840,
+#                   "pop-vlan": 1, "id": 251658240}
+#    ]}
+#
 ##
 { 'command': 'query-rocker-of-dpa-groups',
   'data': { 'name': 'str', '*type': 'uint8' },
diff --git a/qapi/trace.json b/qapi/trace.json
index e872146..63410f8 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -59,6 +59,13 @@
 # an error is returned.
 #
 # Since 2.2
+#
+# Example:
+#
+# -> { "execute": "trace-event-get-state",
+#      "arguments": { "name": "qemu_memalign" } }
+# <- { "return": [ { "name": "qemu_memalign", "state": "disabled" } ] }
+#
 ##
 { 'command': 'trace-event-get-state',
   'data': {'name': 'str', '*vcpu': 'int'},
@@ -84,6 +91,13 @@
 # error is returned.
 #
 # Since 2.2
+#
+# Example:
+#
+# -> { "execute": "trace-event-set-state",
+#      "arguments": { "name": "qemu_memalign", "enable": "true" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'trace-event-set-state',
   'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool',
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 08/11] qapi: add some sections in docs and fix
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (6 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 07/11] (SQUASHED) qmp-commands docs move to schema Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 09/11] qga: fix guest-get-memory-block-info doc Marc-André Lureau
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Add some more section title, and misc fixes.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     | 3 +++
 qapi/block-core.json | 5 +++--
 qapi/block.json      | 5 +++--
 qapi/common.json     | 5 +++--
 qapi/crypto.json     | 4 +++-
 qapi/event.json      | 5 +++++
 qapi/rocker.json     | 3 +++
 qapi/trace.json      | 2 ++
 8 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 250baee..9d9d410 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -66,6 +66,9 @@
 # QAPI introspection
 { 'include': 'qapi/introspect.json' }
 
+##
+# = QMP commands
+
 ##
 # @qmp_capabilities:
 #
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 06bf1d0..d69a678 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1,6 +1,7 @@
 # -*- Mode: Python -*-
-#
-# QAPI block core definitions (vm unrelated)
+
+##
+# == QAPI block core definitions (vm unrelated)
 
 # QAPI common definitions
 { 'include': 'common.json' }
diff --git a/qapi/block.json b/qapi/block.json
index b88ab3c..c26c82f 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -1,6 +1,7 @@
 # -*- Mode: Python -*-
-#
-# QAPI block definitions (vm related)
+
+##
+# = QAPI block definitions (vm related)
 
 # QAPI block core definitions
 { 'include': 'block-core.json' }
diff --git a/qapi/common.json b/qapi/common.json
index 927d621..4887430 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -1,6 +1,7 @@
 # -*- Mode: Python -*-
-#
-# QAPI common definitions
+
+##
+# = QAPI common definitions
 
 ##
 # @QapiErrorClass
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 4ac3034..a22a9dc 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -1,6 +1,8 @@
 # -*- Mode: Python -*-
 #
-# QAPI crypto definitions
+
+##
+# = QAPI crypto definitions
 
 ##
 # @QCryptoTLSCredsEndpoint:
diff --git a/qapi/event.json b/qapi/event.json
index 51205b8..55b9d06 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -1,3 +1,8 @@
+# -*- Mode: Python -*-
+
+##
+# = Events
+
 ##
 # @SHUTDOWN
 #
diff --git a/qapi/rocker.json b/qapi/rocker.json
index 9ed233c..e986486 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -1,4 +1,7 @@
 ##
+# = Rocker API
+
+##
 # @Rocker:
 #
 # Rocker switch information.
diff --git a/qapi/trace.json b/qapi/trace.json
index 63410f8..770fef5 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -5,6 +5,8 @@
 # This work is licensed under the terms of the GNU GPL, version 2 or later.
 # See the COPYING file in the top-level directory.
 
+##
+# = Tracing commands
 
 ##
 # @TraceEventState:
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 09/11] qga: fix guest-get-memory-block-info doc
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (7 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 08/11] qapi: add some sections in docs and fix Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-27 16:58   ` Markus Armbruster
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 10/11] texi2pod: learn quotation, deftp and deftypefn Marc-André Lureau
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qga/qapi-schema.json | 1 -
 1 file changed, 1 deletion(-)

diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 09c9728..7a35267 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -954,7 +954,6 @@
 #
 # Get information relating to guest memory blocks.
 #
-# Returns: memory block size in bytes.
 # Returns: @GuestMemoryBlockInfo
 #
 # Since 2.3
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 10/11] texi2pod: learn quotation, deftp and deftypefn
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (8 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 09/11] qga: fix guest-get-memory-block-info doc Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 11/11] build-sys: make and install the generated schema docs Marc-André Lureau
  2016-10-26  9:36 ` [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Markus Armbruster
  11 siblings, 0 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Learn a few more markups used for API documentation.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/texi2pod.pl | 44 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl
index 8767662..5df4b5f 100755
--- a/scripts/texi2pod.pl
+++ b/scripts/texi2pod.pl
@@ -37,6 +37,7 @@ $inf = "";
 $ibase = "";
 @ipath = ();
 $encoding = undef;
+@args = ();
 
 while ($_ = shift) {
     if (/^-D(.*)$/) {
@@ -162,7 +163,8 @@ while(<$inf>) {
 	if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
 	    $skipping = pop @skstack;
 	    next;
-	} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
+	} elsif ($ended =~ /^(?:example|smallexample|display
+                            |quotation|deftp|deftypefn)$/x) {
 	    $shift = "";
 	    $_ = "";	# need a paragraph break
 	} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
@@ -323,6 +325,46 @@ while(<$inf>) {
 	$_ = "\n=item ".join (" : ", @columns)."\n";
     };
 
+    /^\@(quotation)\s*(.+)?$/ and do {
+        push @endwstack, $endw;
+        $endw = $1;
+        $_ = "\n$2:"
+    };
+
+    /^{(.*)}$|^(.*)$/ and $#args > 0 and do {
+        $kind = $args[0];
+        $arguments = $1 // "";
+        if ($endw eq "deftypefn") {
+            $ret = $args[1];
+            $fname = "B<$args[2]>";
+            $_ = $ret ? "$ret " : "";
+            $_ .= "$fname $arguments ($kind)";
+        } else {
+            $_ = "B<$args[1]> ($kind)\n\n$arguments";
+        }
+        @args = ();
+    };
+
+    /^\@(deftp)\s*(.+)?$/ and do {
+        push @endwstack, $endw;
+        $endw = $1;
+        $arg = $2;
+        $arg =~ s/{([^}]*)}/$1/g;
+        $arg =~ s/\@$//;
+        @args = split (/ /, $arg);
+        $_ = "";
+    };
+
+    /^\@(deftypefn)\s*(.+)?$/ and do {
+        push @endwstack, $endw;
+        $endw = $1;
+        $arg = $2;
+        $arg =~ s/{([^}]*)}/$1/g;
+        $arg =~ s/\@$//;
+        @args = split (/ /, $arg);
+        $_ = "";
+    };
+
     /^\@itemx?\s*(.+)?$/ and do {
 	if (defined $1) {
 	    # Entity escapes prevent munging by the <> processing below.
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH v2 11/11] build-sys: make and install the generated schema docs
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (9 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 10/11] texi2pod: learn quotation, deftp and deftypefn Marc-André Lureau
@ 2016-09-25 18:18 ` Marc-André Lureau
  2016-10-26  9:36 ` [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Markus Armbruster
  11 siblings, 0 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-09-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 Makefile | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 6e00559..5d8d0c3 100644
--- a/Makefile
+++ b/Makefile
@@ -94,6 +94,9 @@ HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
 
 ifdef BUILD_DOCS
 DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
+DOCS+=docs/qemu-qapi.txt qemu-qapi.7
+DOCS+=docs/qemu-ga-qapi.txt qemu-ga-qapi.7
+DOCS+=qemu-qapi.pdf qemu-ga-qapi.pdf
 ifdef CONFIG_VIRTFS
 DOCS+=fsdev/virtfs-proxy-helper.1
 endif
@@ -400,6 +403,9 @@ distclean: clean
 	rm -f config.log
 	rm -f linux-headers/asm
 	rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
+	rm -f qemu-qapi.info qemu-qapi.aux qemu-qapi.cp qemu-qapi.dvi qemu-qapi.fn qemu-qapi.info qemu-qapi.ky qemu-qapi.log qemu-qapi.pdf qemu-qapi.pg qemu-qapi.toc qemu-qapi.tp qemu-qapi.vr qemu-ga-qapi.info qemu-ga-qapi.aux qemu-ga-qapi.cp qemu-ga-qapi.dvi qemu-ga-qapi.fn qemu-ga-qapi.info qemu-ga-qapi.ky qemu-ga-qapi.log qemu-ga-qapi.pdf qemu-ga-qapi.pg qemu-ga-qapi.toc qemu-ga-qapi.tp qemu-ga-qapi.vr
+	rm -f qemu-qapi.7 qemu-ga-qapi.7
+	rm -f docs/qemu-qapi.txt
 	for d in $(TARGET_DIRS); do \
 	rm -rf $$d || exit 1 ; \
         done
@@ -436,10 +442,12 @@ endif
 install-doc: $(DOCS)
 	$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
 	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
-	$(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
+	$(INSTALL_DATA) docs/qemu-qapi.txt "$(DESTDIR)$(qemu_docdir)"
 ifdef CONFIG_POSIX
 	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 	$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
+	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7"
+	$(INSTALL_DATA) qemu-qapi.7 "$(DESTDIR)$(mandir)/man7"
 ifneq ($(TOOLS),)
 	$(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1"
 	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
@@ -447,6 +455,8 @@ ifneq ($(TOOLS),)
 endif
 ifneq (,$(findstring qemu-ga,$(TOOLS)))
 	$(INSTALL_DATA) qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
+	$(INSTALL_DATA) docs/qemu-ga-qapi.txt "$(DESTDIR)$(qemu_docdir)"
+	$(INSTALL_DATA) qemu-ga-qapi.7 "$(DESTDIR)$(mandir)/man7"
 endif
 endif
 ifdef CONFIG_VIRTFS
@@ -559,7 +569,7 @@ qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
 qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
 
-qemu-qapi.txt: qemu-qapi.texi
+docs/%-qapi.txt: %-qapi.texi
 	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --plaintext $< -o $@,\
 	"  GEN   $@")
 
@@ -607,10 +617,22 @@ qemu-ga.8: qemu-ga.texi
 	  $(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \
 	  "  GEN   $@")
 
-dvi: qemu-doc.dvi qemu-tech.dvi
-html: qemu-doc.html qemu-tech.html
-info: qemu-doc.info qemu-tech.info
-pdf: qemu-doc.pdf qemu-tech.pdf
+qemu-qapi.7: qemu-qapi.texi
+	$(call quiet-command, \
+	 perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-qapi.pod && \
+	 $(POD2MAN) --section=7 --center=" " --release=" " qemu-qapi.pod > $@, \
+	 "  GEN   $@")
+
+qemu-ga-qapi.7: qemu-ga-qapi.texi
+	$(call quiet-command, \
+	 perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-ga-qapi.pod && \
+	 $(POD2MAN) --section=7 --center=" " --release=" " qemu-ga-qapi.pod > $@, \
+	 "  GEN   $@")
+
+dvi: qemu-doc.dvi qemu-tech.dvi qemu-qapi.dvi qemu-ga-qapi.dvi
+html: qemu-doc.html qemu-tech.html qemu-qapi.html qemu-ga-qapi.html
+info: qemu-doc.info qemu-tech.info qemu-qapi.info qemu-ga-qapi.info
+pdf: qemu-doc.pdf qemu-tech.pdf qemu-qapi.pdf qemu-ga-qapi.pdf
 
 qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
 	qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed)
  2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (10 preceding siblings ...)
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 11/11] build-sys: make and install the generated schema docs Marc-André Lureau
@ 2016-10-26  9:36 ` Markus Armbruster
  2016-11-02 12:11   ` Markus Armbruster
  11 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2016-10-26  9:36 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Hi,
>
> Add a qapi2texi script to generate the documentation from the qapi
> schemas. Build various new documentation targets for it: pdf, man,
> txt. The 7th patch in this series is a squashed version of the
> documentation move from qmp-commands.txt to the schemas. The whole
> version (not sent on the ML to avoid spamming) is in the following git
> branch: https://github.com/elmarco/qemu/commits/qapi-doc

I apologize for the delay in review, in particular since parts of this
series rot rather quickly.

You already rebased your git branch to commit 4387f56 on master.  The
branch has PATCH 07 split.  The branch doesn't rebase cleanly to current
master, but the conflicts are all in the shards of PATCH 07.

For review, I applied the patches as sent to current master (commit
ede0cbe).  Two patches conflict.  PATCH 07 "(SQUASHED) qmp-commands docs
move to schema" I simply skipped.  PATCH 11 "build-sys: make and install
the generated schema docs" conflicts with commit 78e8779 "qemu-doc:
merge qemu-tech and qemu-doc", but it's easy enough to resolve, and you
already did it in your git branch.

Next: actual review the patches.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/11] qapi: fix schema symbol sections
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 02/11] qapi: fix schema symbol sections Marc-André Lureau
@ 2016-10-26 13:30   ` Markus Armbruster
  2016-11-04 12:11     ` Marc-André Lureau
  0 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2016-10-26 13:30 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> According to documentation, there needs to be '##' to start a symbol

Suggest to be explicit, and say "According to docs/qapi-code-gen.txt".

> section, that's also what the documentation parser expects.

Does the doc parser complain when its expectation isn't met?  I haven't
reviewed it, yet...

In my opinion, qapi-code-gen.txt should demand everything the doc parser
needs (it may demand more), and the doc parser should complain about
everything qapi-code-gen.txt demands and the schema doesn't provide.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

The patch fixes all missing '##' at the beginning of definition comment
blocks.  Good.

qapi-code-gen.txt also demands '##' at the end.  Does the parser rely on
it?  Offenders:

diff --git a/qapi-schema.json b/qapi-schema.json
index fc732cb..0cc9ee6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -780,6 +780,7 @@
 # command.
 #
 # Since: 2.5
+##
 { 'command': 'migrate-start-postcopy' }
 
 ##
@@ -4429,7 +4430,7 @@
 #
 # @DIMM: memory slot
 # @CPU: logical CPU slot (since 2.7)
-#
+##
 { 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
 
 ##

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/11] qapi: fix missing symbol @prefix
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 03/11] qapi: fix missing symbol @prefix Marc-André Lureau
@ 2016-10-26 13:37   ` Markus Armbruster
  2016-11-04 12:05     ` Marc-André Lureau
  0 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2016-10-26 13:37 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json     |  4 ++--
>  qapi/block-core.json |  4 ++--
>  qapi/crypto.json     | 36 ++++++++++++++++++------------------
>  3 files changed, 22 insertions(+), 22 deletions(-)
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index f07ffd7..3091993 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -4526,7 +4526,7 @@
>  { 'include': 'qapi/rocker.json' }
>  
>  ##
> -# ReplayMode:
> +# @ReplayMode:
>  #
>  # Mode of the replay subsystem.
>  #
> @@ -4594,7 +4594,7 @@
>  { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
>  
>  ##
> -# CpuInstanceProperties
> +# @CpuInstanceProperties
>  #
>  # List of properties to be used for hotplugging a CPU instance,
>  # it should be passed by management with device_add command when

The example in qapi-code-gen.txt has a colon after the symbol name:

    ##
    # @BlockStats:

The text doesn't mention it.  Tne schema uses colons inconsistently, as
visible above.  Let's enforce colons.  

> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index cf8e980..73f4180 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -1149,7 +1149,7 @@
>    'data': 'DriveMirror' }
>  
>  ##
> -# DriveMirror
> +# @DriveMirror
>  #
>  # A set of parameters describing drive mirror setup.
>  #
> @@ -1373,7 +1373,7 @@
>    'data': 'BlockIOThrottle' }
>  
>  ##
> -# BlockIOThrottle
> +# @BlockIOThrottle
>  #
>  # A set of parameters describing block throttling.
>  #
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 6933b13..4ac3034 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -3,7 +3,7 @@
>  # QAPI crypto definitions
>  
>  ##
> -# QCryptoTLSCredsEndpoint:
> +# @QCryptoTLSCredsEndpoint:
>  #
>  # The type of network endpoint that will be using the credentials.
>  # Most types of credential require different setup / structures
> @@ -22,7 +22,7 @@
>  
>  
>  ##
> -# QCryptoSecretFormat:
> +# @QCryptoSecretFormat:
>  #
>  # The data format that the secret is provided in
>  #
> @@ -36,7 +36,7 @@
>  
>  
>  ##
> -# QCryptoHashAlgorithm:
> +# @QCryptoHashAlgorithm:
>  #
>  # The supported algorithms for computing content digests
>  #
> @@ -55,7 +55,7 @@
>  
>  
>  ##
> -# QCryptoCipherAlgorithm:
> +# @QCryptoCipherAlgorithm:
>  #
>  # The supported algorithms for content encryption ciphers
>  #
> @@ -82,7 +82,7 @@
>  
>  
>  ##
> -# QCryptoCipherMode:
> +# @QCryptoCipherMode:
>  #
>  # The supported modes for content encryption ciphers
>  #
> @@ -97,7 +97,7 @@
>  
>  
>  ##
> -# QCryptoIVGenAlgorithm:
> +# @QCryptoIVGenAlgorithm:
>  #
>  # The supported algorithms for generating initialization
>  # vectors for full disk encryption. The 'plain' generator
> @@ -115,7 +115,7 @@
>    'data': ['plain', 'plain64', 'essiv']}
>  
>  ##
> -# QCryptoBlockFormat:
> +# @QCryptoBlockFormat:
>  #
>  # The supported full disk encryption formats
>  #
> @@ -130,7 +130,7 @@
>    'data': ['qcow', 'luks']}
>  
>  ##
> -# QCryptoBlockOptionsBase:
> +# @QCryptoBlockOptionsBase:
>  #
>  # The common options that apply to all full disk
>  # encryption formats
> @@ -143,7 +143,7 @@
>    'data': { 'format': 'QCryptoBlockFormat' }}
>  
>  ##
> -# QCryptoBlockOptionsQCow:
> +# @QCryptoBlockOptionsQCow:
>  #
>  # The options that apply to QCow/QCow2 AES-CBC encryption format
>  #
> @@ -157,7 +157,7 @@
>    'data': { '*key-secret': 'str' }}
>  
>  ##
> -# QCryptoBlockOptionsLUKS:
> +# @QCryptoBlockOptionsLUKS:
>  #
>  # The options that apply to LUKS encryption format
>  #
> @@ -171,7 +171,7 @@
>  
>  
>  ##
> -# QCryptoBlockCreateOptionsLUKS:
> +# @QCryptoBlockCreateOptionsLUKS:
>  #
>  # The options that apply to LUKS encryption format initialization
>  #
> @@ -201,7 +201,7 @@
>  
>  
>  ##
> -# QCryptoBlockOpenOptions:
> +# @QCryptoBlockOpenOptions:
>  #
>  # The options that are available for all encryption formats
>  # when opening an existing volume
> @@ -216,7 +216,7 @@
>  
>  
>  ##
> -# QCryptoBlockCreateOptions:
> +# @QCryptoBlockCreateOptions:
>  #
>  # The options that are available for all encryption formats
>  # when initializing a new volume
> @@ -231,7 +231,7 @@
>  
>  
>  ##
> -# QCryptoBlockInfoBase:
> +# @QCryptoBlockInfoBase:
>  #
>  # The common information that applies to all full disk
>  # encryption formats
> @@ -245,7 +245,7 @@
>  
>  
>  ##
> -# QCryptoBlockInfoLUKSSlot:
> +# @QCryptoBlockInfoLUKSSlot:
>  #
>  # Information about the LUKS block encryption key
>  # slot options
> @@ -265,7 +265,7 @@
>  
>  
>  ##
> -# QCryptoBlockInfoLUKS:
> +# @QCryptoBlockInfoLUKS:
>  #
>  # Information about the LUKS block encryption options
>  #
> @@ -293,7 +293,7 @@
>             'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
>  
>  ##
> -# QCryptoBlockInfoQCow:
> +# @QCryptoBlockInfoQCow:
>  #
>  # Information about the QCow block encryption options
>  #
> @@ -304,7 +304,7 @@
>  
>  
>  ##
> -# QCryptoBlockInfo:
> +# @QCryptoBlockInfo:
>  #
>  # Information about the block encryption options
>  #

Additionally, there are a few lines that don't match the symbol the
symbol being defined:

   diff --git a/qapi-schema.json b/qapi-schema.json
   index 0cc9ee6..104cc62 100644
   --- a/qapi-schema.json
   +++ b/qapi-schema.json
   @@ -1079,7 +1079,7 @@
               '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }

    ##
   -# @VncPriAuth:
   +# @VncPrimaryAuth:
    #
    # vnc primary authentication method.
    #
   @@ -3889,7 +3889,7 @@
       'data': { 'passthrough' : 'TPMPassthroughOptions' } }

    ##
   -# @TpmInfo:
   +# @TPMInfo:
    #
    # Information about the TPM
    #
   diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
   index 09c9728..07a449b 100644
   --- a/qga/qapi-schema.json
   +++ b/qga/qapi-schema.json
   @@ -378,7 +378,7 @@
      'data': { 'handle': 'int' } }

    ##
   -# @GuestFsFreezeStatus
   +# @GuestFsfreezeStatus
    #
    # An enumeration of filesystem freeze states
    #

The parser should flag such nonsense.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/11] qapi: fix @ACPI sections
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 04/11] qapi: fix @ACPI sections Marc-André Lureau
@ 2016-10-26 13:38   ` Markus Armbruster
  0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2016-10-26 13:38 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> This helps the doc parser.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 3091993..3ac8637 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -4414,14 +4414,16 @@
>  ##
>  { 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
>  
> -## @ACPISlotType
> +##
> +# @ACPISlotType
>  #
>  # @DIMM: memory slot
>  # @CPU: logical CPU slot (since 2.7)
>  #
>  { 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
>  
> -## @ACPIOSTInfo
> +##
> +# @ACPIOSTInfo
>  #
>  # OSPM Status Indication for a device
>  # For description of possible values of @source and @status fields

Could be squashed into PATCH 02.

Another, unrelated thing to clean up while you're at it: { 'include':
'qapi/rocker.json' } is in the middle of qapi-schema.json for no obvious
reason.  Let's move it next to the other includes, in a separate patch.

There's also inconsistent whitespace use, but I think that's best left
for another day.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template Marc-André Lureau
@ 2016-10-27 14:55   ` Markus Armbruster
  2016-11-04 13:27     ` Marc-André Lureau
  0 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2016-10-27 14:55 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The qapi2texi scripts uses a template for the texi file. Since we are
> going to generate the documentation in multiple formats, move qmp-intro
> to qemu-qapi template. (it would be nice to write something similar for
> qemu-ga, but this is left for a future patch)
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

I'm not exactly a Texinfo expert, but I can compare to the Texinfo
manual.

Lots of comments below.  Please don't let them discourage you!  Your two
manuals are pretty slick already, and a most welcome step forward.

> ---
>  docs/qemu-ga-qapi.template.texi |  58 ++++++++++++++++
>  docs/qemu-qapi.template.texi    | 148 ++++++++++++++++++++++++++++++++++++++++
>  docs/qmp-intro.txt              |  87 -----------------------
>  3 files changed, 206 insertions(+), 87 deletions(-)
>  create mode 100644 docs/qemu-ga-qapi.template.texi
>  create mode 100644 docs/qemu-qapi.template.texi
>  delete mode 100644 docs/qmp-intro.txt
>
> diff --git a/docs/qemu-ga-qapi.template.texi b/docs/qemu-ga-qapi.template.texi
> new file mode 100644
> index 0000000..3ddbf56
> --- /dev/null
> +++ b/docs/qemu-ga-qapi.template.texi
> @@ -0,0 +1,58 @@
> +\input texinfo

The Texinfo manual uses

   \input texinfo   @c -*-texinfo-*-

but my version of Emacs seems to be fine without this.

> +@setfilename qemu-ga-qapi

Not wrong, but the Texinfo manual recommends to replace the extension
(here: .texi) with .info, so let's do that:

   @setfilename qemu-ga-qapi.info

> +@documentlanguage en

This overrides the default en_US to just en.  Is that what we want?

> +@exampleindent 0
> +@paragraphindent 0
> +
> +@settitle QEMU-GA QAPI Reference Manual

What is "QAPI", and why would the reader care?  I think the manual is
about the QEMU Guest Agent Protocol.  The fact that its implementation
relies on QAPI is immaterial here.  What about:

   @settitle QEMU Guest Agent Protocol Reference

But then the filenames are off.  Rename to qemu-ga-ref.*.

> +

I think we need a copyright note.  Something like:

   @copying
   This is the QEMU Guest Agent QAPI reference manual.

   Copyright @copyright{} 2016 The QEMU Project developers

   @quotation
   Permission is granted to ...
   @end quotation
   @end copying

> +@ifinfo

   @dircategory QEMU

Should be added to qemu-doc.texi as well.

> +@direntry
> +* QEMU-GA-QAPI: (qemu-doc).    QEMU-GA QAPI Reference Manual

Pasto: (qemu-doc)

The description should start at column 32, not 31.

If we retitle and rename as suggested, this becomes:

   * QEMU-GA-Ref: (qemu-ga-ref):   QEMU Guest Agent Protocol Reference

> +@end direntry
> +@end ifinfo

Are you sure we need @ifinfo?

> +
> +@iftex
> +@titlepage
> +@sp 7
> +@center @titlefont{{QEMU Guest Agent {version}}}

{version} seems to get replaced by qapi2texi.py.  Worth a comment.

> +@sp 1
> +@center @titlefont{{QAPI Reference Manual}}

Protocol Reference Manual

> +@sp 3

Isn't @sp right before @end titlepage redundant?

We need to include the copyright notice:

   @page
   @vskip 0pt plus 1filll
   @insertcopying

> +@end titlepage
> +@end iftex

Are you sure we need @iftex?

We can also let Texinfo do the spacing, like this:

   @titlepage
   @title QEMU Guest Agent {version}
   @subtitle Protocol Reference Manual
   @page
   @vskip 0pt plus 1filll
   @insertcopying
   @end titlepage

The @title isn't really the title, though.  Could reshuffle things a
bit, e.g.

   @title QEMU Guest Agent Protocol Reference Manual
   @subtitle for QEMU {version}

Your choice.

The examples in Texinfo manual Appendix C "Sample Texinfo Files" have
@contents right here, after the title page.

> +
> +@ifnottex
> +@node Top
> +@top

   @top QEMU Guest Agent QAPI reference

> +
> +This is the QEMU Guest Agent QAPI reference for QEMU {version}.

"protocol reference manual for"

According to the Texinfo manual's examples, the @end ifnottex goes
here...

> +
> +@menu
> +* API Reference::
> +* Commands and Events Index::
> +* Data Types Index::
> +@end menu
> +
> +@end ifnottex

... and not here.

> +
> +@contents

Suggest to move this up, as mentioned above.

> +
> +@node API Reference
> +@chapter API Reference
> +
> +@c man begin DESCRIPTION

What does this @c man magic do?  Suggest to explain in a comment.

> +{qapi}

This seems to get replaced with the generated reference documentation by
qapi2texi.py.  Worth a comment.

> +@c man end
> +
> +@c man begin SEEALSO
> +The HTML documentation of QEMU for more precise information.
> +@c man end

More @c man magic.

> +
> +@node Commands and Events Index
> +@unnumbered Commands and Events Index
> +@printindex fn

Blank line here, please.

> +@node Data Types Index
> +@unnumbered Data Types Index
> +@printindex tp

And here.

> +@bye
> diff --git a/docs/qemu-qapi.template.texi b/docs/qemu-qapi.template.texi
> new file mode 100644
> index 0000000..102c8d9
> --- /dev/null
> +++ b/docs/qemu-qapi.template.texi

The comments above largely apply; I won't repeat them.

> @@ -0,0 +1,148 @@
> +\input texinfo
> +@setfilename qemu-qapi
> +@documentlanguage en
> +@exampleindent 0
> +@paragraphindent 0
> +
> +@settitle QEMU QAPI Reference Manual

Again, QAPI is detail; it's the QEMU QMP reference manual.  Except it
has more than just QMP, because we choose to use qapi-schema.json for
purely internal types in addition to QMP.

Options:

* Claim this is the QMP reference manual, include the internal types
  anyway.

* Filter out the internal types automatically, similar to
  qmp-introspect.py.

* Filter out the internal types manually, by annotating them in the
  schema.  Feels error-prone.

* Split the QAPI schema.

* Reflect the curious mix of QMP protocol and internal data type
  reference in the title.

We don't need a perfect solution to commit this, but an understanding of
what we want to do would be nice.

> +
> +@ifinfo
> +@direntry
> +* QEMU: (qemu-doc).    QEMU QAPI Reference Manual
> +@end direntry
> +@end ifinfo
> +
> +@iftex
> +@titlepage
> +@sp 7
> +@center @titlefont{{QEMU Emulator {version}}}
> +@sp 1
> +@center @titlefont{{QAPI Reference Manual}}
> +@sp 3
> +@end titlepage
> +@end iftex
> +
> +@ifnottex
> +@node Top
> +@top
> +
> +This is the QMP QAPI reference for QEMU {version}.
> +
> +@menu
> +* Introduction::
> +* API Reference::
> +* Commands and Events Index::
> +* Data Types Index::
> +@end menu
> +
> +@end ifnottex
> +
> +@contents
> +
> +@node Introduction
> +@chapter Introduction
> +
> +The QEMU Machine Protocol (@acronym{{QMP}}) allows applications to
> +operate a QEMU instance.
> +
> +QMP is @uref{{http://www.json.org, JSON}} based and features the
> +following:
> +
> +@itemize @minus

@bullet is more common.  Matter of taste.

> +@item
> +Lightweight, text-based, easy to parse data format

Suggest "plain text" instead of "text-based".

JSON is "easy to parse" until you hit the potholes in its specification.
See "Parsing JSON is a Minefield" <http://seriot.ch/parsing_json.html>.

   QMP provides the following features:

   @itemize @bullet
   @item
   Simple @uref{{http://www.json.org, JSON}} syntax

> +@item
> +Asynchronous messages support (ie. events)

i.e.

But I'd say

   @item
   Synchronous commands and replies
   @item
   Asynchronous messages ("events")

> +@item
> +Capabilities Negotiation

I'd add

   @item
   Introspection

> +@end itemize
> +
> +For detailed information on QEMU Machine Protocol, the specification
> +is in @file{{qmp-spec.txt}}.
> +
> +@section Usage
> +
> +You can use the @option{{-qmp}} option to enable QMP. For example, the
> +following makes QMP available on localhost port 4444:
> +
> +@example
> +$ qemu [...] -qmp tcp:localhost:4444,server,nowait
> +@end example
> +
> +However, for more flexibility and to make use of more options, the
> +@option{{-mon}} command-line option should be used. For instance, the
> +following example creates one HMP instance (human monitor) on stdio
> +and one QMP instance on localhost port 4444:

This sounds a bit like we don't want people to use -qmp.  What about

   However, for more flexibility and to make use of more options, the
   @option{{-mon}} command-line option should be used. For instance, the
   following example creates one HMP instance (human monitor) on stdio
   and one QMP instance on localhost port 4444:
   

> +
> +@example
> +$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
> +             -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
> +             -mon chardev=mon1,mode=control,pretty=on
> +@end example

Not sure we want to drag in HMP here.

> +
> +Please, refer to QEMU's manpage for more information.

Drop the comma.

Hrmmm, I just realized this is merely moved from qmp-intro.txt.  I guess
I should read your commit message before your patch %-)

I'm not sure a *reference* manual is a good home for an *introduction*
to use.  It's certainly not where I'd look first.

We can decide this isn't a reference manual after all, and change title,
file name and so forth accordingly.

Or we can stick to the reference manual idea, and include qmp-intro.txt
by reference.

> +
> +@section Simple testing
> +
> +To manually test QMP one can connect with telnet and issue commands by
> +hand:
> +
> +@example
> +$ telnet localhost 4444
> +Trying 127.0.0.1...
> +Connected to localhost.
> +Escape character is '^]'.
> +@{{
> +    "QMP": @{{
> +        "version": @{{
> +            "qemu": @{{
> +                "micro": 50,
> +                "minor": 6,
> +                "major": 1
> +            @}},
> +            "package": ""
> +        @}},
> +        "capabilities": [
> +        ]
> +    @}}
> +@}}
> +
> +@{{ "execute": "qmp_capabilities" @}}
> +@{{
> +    "return": @{{
> +    @}}
> +@}}
> +
> +@{{ "execute": "query-status" @}}
> +@{{
> +    "return": @{{
> +        "status": "prelaunch",
> +        "singlestep": false,
> +        "running": false
> +    @}}
> +@}}
> +@end example
> +
> +@section Wiki
> +
> +Please refer to the @uref{{http://wiki.qemu-project.org/QMP, QMP QEMU
> + wiki page}} for more details on QMP.
> +
> +@node API Reference
> +@chapter API Reference
> +
> +@c man begin DESCRIPTION
> +{qapi}
> +@c man end
> +
> +@c man begin SEEALSO
> +The HTML documentation of QEMU for more precise information.
> +@c man end
> +
> +@node Commands and Events Index
> +@unnumbered Commands and Events Index
> +@printindex fn
> +@node Data Types Index
> +@unnumbered Data Types Index
> +@printindex tp
> +@bye
> diff --git a/docs/qmp-intro.txt b/docs/qmp-intro.txt
> deleted file mode 100644
> index f6a3a03..0000000
> --- a/docs/qmp-intro.txt
> +++ /dev/null
> @@ -1,87 +0,0 @@
> -                          QEMU Machine Protocol
> -                          =====================
> -
> -Introduction
> -------------
> -
> -The QEMU Machine Protocol (QMP) allows applications to operate a
> -QEMU instance.
> -
> -QMP is JSON[1] based and features the following:
> -
> -- Lightweight, text-based, easy to parse data format
> -- Asynchronous messages support (ie. events)
> -- Capabilities Negotiation
> -
> -For detailed information on QMP's usage, please, refer to the following files:
> -
> -o qmp-spec.txt      QEMU Machine Protocol current specification
> -o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
> -o qmp-events.txt    List of available asynchronous events
> -
> -[1] http://www.json.org
> -
> -Usage
> ------
> -
> -You can use the -qmp option to enable QMP. For example, the following
> -makes QMP available on localhost port 4444:
> -
> -$ qemu [...] -qmp tcp:localhost:4444,server,nowait
> -
> -However, for more flexibility and to make use of more options, the -mon
> -command-line option should be used. For instance, the following example
> -creates one HMP instance (human monitor) on stdio and one QMP instance
> -on localhost port 4444:
> -
> -$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
> -             -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
> -             -mon chardev=mon1,mode=control,pretty=on
> -
> -Please, refer to QEMU's manpage for more information.
> -
> -Simple Testing
> ---------------
> -
> -To manually test QMP one can connect with telnet and issue commands by hand:
> -
> -$ telnet localhost 4444
> -Trying 127.0.0.1...
> -Connected to localhost.
> -Escape character is '^]'.
> -{
> -    "QMP": {
> -        "version": {
> -            "qemu": {
> -                "micro": 50, 
> -                "minor": 6, 
> -                "major": 1
> -            }, 
> -            "package": ""
> -        }, 
> -        "capabilities": [
> -        ]
> -    }
> -}
> -
> -{ "execute": "qmp_capabilities" }
> -{
> -    "return": {
> -    }
> -}
> -
> -{ "execute": "query-status" }
> -{
> -    "return": {
> -        "status": "prelaunch", 
> -        "singlestep": false, 
> -        "running": false
> -    }
> -}
> -
> -Please, refer to the qapi-schema.json file for a complete command reference.
> -
> -QMP wiki page
> --------------
> -
> -http://wiki.qemu-project.org/QMP

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 06/11] build-sys: add qapi doc generation targets
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 06/11] build-sys: add qapi doc generation targets Marc-André Lureau
@ 2016-10-27 16:16   ` Markus Armbruster
  0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2016-10-27 16:16 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add qapi doc generation targets, qemu-qapi.texi, qemu-ga-qapi.texi
> (implicit pdf works too) and qemu-qapi.txt. The generated
> documentation isn't complete yet, so don't bother to build it by
> default or install it yet.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  Makefile | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
>
> diff --git a/Makefile b/Makefile
> index f103616..6e00559 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -269,6 +269,7 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
>  gen-out-type = $(subst .,-,$(suffix $@))
>  
>  qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
> +qapi-py += $(SRC_PATH)/scripts/qapi2texi.py
>  
>  qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
>  $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
> @@ -558,9 +559,23 @@ qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
>  qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
>  	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
>  
> +qemu-qapi.txt: qemu-qapi.texi
> +	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --plaintext $< -o $@,\
> +	"  GEN   $@")

Do it with a pattern rule?  Next to the %.info: %.texi rule:

   %.txt: %.texi
    	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --plaintext $< -o $@,\
   	"  GEN   $@")

> +
>  qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
>  	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN   $@")
>  
> +qemu-qapi.texi: $(qapi-modules) $(qapi-py) \
> +	$(SRC_PATH)/docs/qemu-qapi.template.texi
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py \
> +	$(SRC_PATH)/docs/qemu-qapi.template.texi $(VERSION) $< > $@,"  GEN   $@")

Confusing indentation.  Elsewhere in this file, we indent like this:

   qemu-qapi.texi: $(qapi-modules) $(qapi-py) \
   $(SRC_PATH)/docs/qemu-qapi.template.texi
   	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py \
   	$(SRC_PATH)/docs/qemu-qapi.template.texi $(VERSION) $< > $@,"  GEN   $@")

> +
> +qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py) \
> +	$(SRC_PATH)/docs/qemu-ga-qapi.template.texi
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py \
> +	$(SRC_PATH)/docs/qemu-ga-qapi.template.texi $(VERSION) $< > $@,"  GEN   $@")

Likewise.

> +
>  qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
>  	$(call quiet-command, \
>  	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \

Shouldn't you add the two generated .texi to .gitignore?

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 09/11] qga: fix guest-get-memory-block-info doc
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 09/11] qga: fix guest-get-memory-block-info doc Marc-André Lureau
@ 2016-10-27 16:58   ` Markus Armbruster
  0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2016-10-27 16:58 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qga/qapi-schema.json | 1 -
>  1 file changed, 1 deletion(-)
>
> diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> index 09c9728..7a35267 100644
> --- a/qga/qapi-schema.json
> +++ b/qga/qapi-schema.json
> @@ -954,7 +954,6 @@
>  #
>  # Get information relating to guest memory blocks.
>  #
> -# Returns: memory block size in bytes.
>  # Returns: @GuestMemoryBlockInfo
>  #
>  # Since 2.3

This is an instance of the general "doc comment doesn't match the actual
definition" doc bug pattern.

Does your doc generator (which I still haven't reviewed) check doc
comments against the definition?

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script
  2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script Marc-André Lureau
@ 2016-10-28 16:44   ` Markus Armbruster
  2016-10-28 19:56     ` Eric Blake
  2016-11-02  9:25     ` Marc-André Lureau
  0 siblings, 2 replies; 29+ messages in thread
From: Markus Armbruster @ 2016-10-28 16:44 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> As the name suggests, the qapi2texi script converts JSON QAPI
> description into a standalone texi file suitable for different target
> formats.
>
> It parses the following kind of blocks with some little variations:
>
>   ##
>   # = Section
>   # == Subsection
>   #
>   # Some text foo with *emphasis*
>   # 1. with a list
>   # 2. like that
>   #
>   # And some code:
>   # | $ echo foo
>   # | <- do this
>   # | -> get that
>   #
>   ##
>
>   ##
>   # @symbol
>   #
>   # Symbol body ditto ergo sum. Foo bar
>   # baz ding.
>   #
>   # @arg: foo
>   # @arg: #optional foo
>   #
>   # Returns: returns bla bla
>   #
>   #          Or bla blah
>   #
>   # Since: version
>   # Notes: notes, comments can have
>   #        - itemized list
>   #        - like this
>   #
>   #        and continue...
>   #
>   # Example:
>   #
>   # <- { "execute": "quit" }
>   # -> { "return": {} }
>   #
>   ##
>
> Thanks to the json declaration, it's able to give extra information
> about the type of arguments and return value expected.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py        | 100 +++++++++++++++-
>  scripts/qapi2texi.py   | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
>  docs/qapi-code-gen.txt |  44 +++++--
>  3 files changed, 446 insertions(+), 12 deletions(-)
>  create mode 100755 scripts/qapi2texi.py

My review will be easier to follow if you skip ahead qapi-code-gen.txt,
then go to class QAPISchemaParser, then come back here.

> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 21bc32f..4efc7e7 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -122,6 +122,79 @@ class QAPIExprError(Exception):
>              "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
>  
>  
> +class QAPIDoc:

Old-style class.  Make this

   class QAPIDoc(object):

> +    def __init__(self, comment):
> +        self.symbol = None
> +        self.comment = "" # the main symbol comment

PEP8 wants at least two spaces before #, and I prefer the # in colum 32.

> +        self.args = OrderedDict()
> +        # meta is for Since:, Notes:, Examples:, Returns:...
> +        self.meta = OrderedDict()
> +        # the current section to populate, array of [dict, key, comment...]
> +        self.section = None
> +
> +        for line in comment.split('\n'):

Makes me wonder whether the caller should pass a list of lines instead
of a string that needs to be split into lines.

> +            # remove multiple spaces
> +            sline = ' '.join(line.split())

Actually, this doesn't "remove multiple spaces", it squeezes sequences
of whitespace into a single space character.  Rather inefficiently, I
suspect, but let's not worry about that now.

> +            # take the first word out
> +            split = sline.split(' ', 1)
> +            key = split[0]
> +
> +            if key.startswith("@"):
> +                key = key[1:].rstrip(':')

Treats the colon as optional.  I understand you're trying to be
unintrusive, but since we're parsing comments already, we can make the
parser do double duty and enforce consistent comment formatting.  But
this isn't the place to discuss the format we want, review of
qapi-code-gen.txt is.

> +                sline = split[1] if len(split) > 1 else ""
> +                if self.symbol is None:
> +                    # the first is the section symbol
> +                    self.symbol = key

Let's not say "the section symbol".  It's the symbol this APIDoc object
documents.  The APIDoc object has sections.

> +                else:
> +                    # else an arg
> +                    self.start_section(self.args, key)
> +            elif self.symbol and \
> +                    key in ("Returns:",
> +                            # special case for Since often used without:
> +                            "Since:", "Since",
> +                            # those are often singular or plural
> +                            "Note:", "Notes:",
> +                            "Example:", "Examples:"):
> +                sline = split[1] if len(split) > 1 else ""
> +                line = None
> +                # new "meta" section
> +                self.start_section(self.meta, key.rstrip(':'))
> +
> +            if self.section and self.section[1].startswith("Example"):
> +                # example is verbatim
> +                self.append_comment(line)
> +            else:
> +                self.append_comment(sline)

Sections other than "Example" and "Examples" have whitespace squeezed.
I believe this is the true reason for the squeezing.  There are a few
other places that rely on it, but they could do just as well without.

> +
> +        self.end_section()
> +
> +    def append_comment(self, line):
> +        """Adds a comment to the current section, or the symbol comment"""
> +        if line is None:
> +            return
> +        if self.section is not None:
> +            if self.section[-1] == "" and line == "":
> +                self.end_section()
> +            else:
> +                self.section.append(line)
> +        elif self.comment == "":
> +            self.comment = line
> +        else:
> +            self.comment += "\n" + line

Accumulating a list and joining at the end might be easier.

> +
> +    def end_section(self):
> +        if self.section is not None:
> +            dic = self.section[0]

Calling a dictionary "dic" could be considered a dick move ;-P

> +            key = self.section[1]
> +            doc = "\n".join(self.section[2:])
> +            dic[key] = doc

Silently trashes previous value of dic[key].

> +            self.section = None
> +
> +    def start_section(self, dic, key):
> +        self.end_section()
> +        self.section = [dic, key]  # .. remaining elems will be the doc

Taken together:

* The QAPI parser is hacked to accumulate and exfiltrate some comments
  to the QAPIDoc parser.

* A QAPIDoc can have a symbol, a symbol comment, and sections.

* Certain patterns in the comment text start and end sections.

  Text within a section belongs to the section.  Text outside sections
  belongs to the symbol comment.  Unlikely to work unless the symbol
  comment is entirely before the first section.

* Two kinds of sections, argument and meta:

  - An argument section is uniquely identified by the argument's name

    Multiple argument sections with the same name make no sense.  The
    code silently ignores all but the last one.

  - A meta section is uniqely identified by a keyword

    The keywords are: "Returns", "Since", "Note", "Notes", "Example",
    "Examples".

    Multiple meta sections with the same key make sense for some keys
    ("Note") but not for others ("Returns", "Since").  Nevertheless, the
    code silently ignores all but the last one.  You can't have two
    "Example" sections, but you can have an "Example" and an "Examples"
    section.  I'm afraid the data structure isn't quite right here.

* No comment is ever rejected.  Comments adhering to the format we have
  in mind generate correct documentation.  Mistakes may produce correct
  documentation, subtly incorrect documentation, or obvious garbage.
  When you get garbage (obvious or not), you have to guess what's wrong
  with your comment.  "Fortunately", developers generally won't have to
  do that, because they generally don't read the generated
  documentation.

General remarks:

* I feel the only way to keep the API documentation in order as we
  develop is to have the parser reject malformed API comments.

* The only way to create a robust and maintainable parser is to specify
  the language *first* and *rigorously*.

* Stacking parsers is not a good idea.  Figuring out one parser's
  accepted language is hard enough.

* For me, the parsing part of this patch is a prototype.  Possibly even
  good enough to commit, with some work.  But it'll have to be redone
  from first principles regardless.

> +
> +
>  class QAPISchemaParser(object):
>  
>      def __init__(self, fp, previously_included=[], incl_info=None):
> @@ -137,11 +210,14 @@ class QAPISchemaParser(object):
>          self.line = 1
>          self.line_pos = 0
>          self.exprs = []
> +        self.comment = None
> +        self.apidoc = incl_info['doc'] if incl_info else []
>          self.accept()
>  
>          while self.tok is not None:
>              expr_info = {'file': fname, 'line': self.line,
> -                         'parent': self.incl_info}
> +                         'parent': self.incl_info, 'doc': self.apidoc}
> +            self.apidoc = []
>              expr = self.get_expr(False)
>              if isinstance(expr, dict) and "include" in expr:
>                  if len(expr) != 1:

Before your patch, expr_info holds the (top-level) expression's location
plus the list of include directive locations that led to the expression.

You extend it by key 'doc'.  Let's see what it's good for.

At every (sub-)expression, we capture the current state of self.apidoc
in expr_info['doc'], then reset self.apidoc to [].  Odd; I would expect
API documentation to attach only to top-level expressions.

Looks like expr_info['doc'] and self.apidoc are lists, and self.apidoc
accumulates documentation until we move it to the next expression's
expr_info['doc'].  In other words, self.apidoc accumulates documentation
for the next expression.

I don't quite understand why you initialize self.apidoc the way you do:
if this file is included, self.apidoc is initialized to the include
directive's expr_info['doc'], else to the empty list.  What are you
trying to accomplish by that?

> @@ -162,6 +238,8 @@ class QAPISchemaParser(object):
>                      inf = inf['parent']
>                  # skip multiple include of the same file
>                  if incl_abs_fname in previously_included:
> +                    expr_info['doc'].extend(self.apidoc)
> +                    self.apidoc = expr_info['doc']
>                      continue
>                  try:
>                      fobj = open(incl_abs_fname, 'r')

Before your patch, we indeed skip, as the comment says.  After your
patch, we do something that's not yet obvious to me, then skip.  The
comment isn't quite right anymore.

Let's see what we do when we include a file a second time:

1. We append self.apidoc to expr_info['doc'].  But self.apidoc is []
here, isn't it?

2. We assign the result back to self.apidoc.

I think this is effectively

                       self.apidoc = expr_info['doc']

What are you trying to accomplish?

> @@ -176,6 +254,12 @@ class QAPISchemaParser(object):
>                               'info': expr_info}
>                  self.exprs.append(expr_elem)
>  
> +    def append_doc(self):
> +        if self.comment:
> +            apidoc = QAPIDoc(self.comment)
> +            self.apidoc.append(apidoc)
> +            self.comment = None
> +

Too many things called apidoc.  I'd elide the local variable:

               self.apidoc.append(QAPIDoc(self.comment))

Neither the role of self.comment nor self.apidoc are obvious just yet.

>      def accept(self):
>          while True:
>              self.tok = self.src[self.cursor]
> @@ -184,8 +268,20 @@ class QAPISchemaParser(object):
>              self.val = None
>  
>              if self.tok == '#':
> -                self.cursor = self.src.find('\n', self.cursor)
> +                end = self.src.find('\n', self.cursor)
> +                line = self.src[self.cursor:end+1]

                   self.cursor = self.src.find('\n', self.cursor)
                   line = self.src[self.pos:self.cursor+1]

and drop the self.cursor = end below.

@line isn't actually the source line, it's the source line with the
initial '#' chopped off.  Hmm.

Note that .find() can't fail, because we made sure self.src ends with
'\n'.

> +                # start a comment section after ##
> +                if line[0] == "#":
> +                    if self.comment is None:
> +                        self.comment = ""
> +                # skip modeline
> +                elif line.find("-*") == -1 and self.comment is not None:
> +                    self.comment += line

Aha: self.comment is either None or a string.  When it's a string, we're
accumulating a (multi-line) comment there.  We start accumulating when a
comment starts with '##'.  We stop by calling self.append_doc(), which
processes the accumulated comment, and appends the result to the list
self.apidoc.

If a comment starting with '##' occurs while we're already accumulating,
we silently ignore it.  I don't think that's a good idea.

Likewise, we silently ignore any comment lines containing '-*'.  That's
definitely not a good idea; your pattern is far too loose.  Why do we
need to ignore such lines?

> +                if self.src[end] == "\n" and self.src[end+1] == "\n":

If this is the last line, self.src[end+1] is out of bounds, I'm afraid.

> +                    self.append_doc()

We stop accumulating when a comment line is followed by a blank line,
and ...

> +                self.cursor = end
>              elif self.tok in "{}:,[]":
> +                self.append_doc()

... when we recognize one of the tokens '{', '}', ':', ',' '[', ']'.

This isn't a parser, it's a hack :)

In this contrieved example, your code joins the two comments into one:

    { 'command: 'contrived-example-1', 'gen':
    ## lorem ipsum
      false
    # dolor sit amet
    }

In this one, it doesn't:

    { 'command: 'contrived-example-2', 'gen':
    ## lorem ipsum
      false }
    # dolor sit amet

In my opinion, this needs a healthy dose of rigor.  Make API comments a
proper *syntactical* construct: starts with a comment token whose text
is exactly '##', extends until the first non-comment token.

Two ways to parse this:

* Lexically, i.e. gobble up the whole comment block as a single token.
  Drawback: tokens spanning lines defeat the elegant treatment of
  newline in one place.  Meh.

* Treat it as an expression: have a method get_api_comment() that keeps
  calling self.accept() until it sees a non-comment token.  To ease
  getting the comment text, we can make self.accept() store it in
  self.val.

This also reduces modifiable state: self.comment goes away.  Non-local
modifiable state is evil.

Now let me try to summarize how this works with parsing details ignored:

0. We accumulate the next expression's API documentation in self.apidoc,
a list of QAPIDoc.

1. We accumulate the current API comment in self.comment.

2. When it's complete, we call self.append_doc().  append_doc()
processes self.comment into a QAPIDoc, which it appends to self.apidoc,
then resets self.comment.

3. When we recognize the start of an expression, we move self.apidoc to
the expressions expr_info['doc'].

Taken together: each (sub-)expression has a list of QAPIDoc objects that
got recognized since the last start of a (sub-)expression.

Now go back to class QAPIDoc.

>                  return
>              elif self.tok == "'":
>                  string = ''
> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> new file mode 100755
> index 0000000..2706b16
> --- /dev/null
> +++ b/scripts/qapi2texi.py
[Skipping the generator for now]
> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> index 5d4c2cd..e51ae4c 100644
> --- a/docs/qapi-code-gen.txt
> +++ b/docs/qapi-code-gen.txt
> @@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no place where a QAPI
>  schema requires the use of JSON numbers or null.
>  
>  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 members 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
> +newline is ignored.  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 members 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:
>  
>      ##
> @@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
>      #           (Since 2.0)
>      #
>      # Since: 0.14.0
> +    #
> +    # Notes: You can also make a list:
> +    #        - with items
> +    #        - like this
> +    #
> +    # Example:
> +    #
> +    # <- { "execute": ... }
> +    # -> { "return": ... }
> +    #
>      ##
>      { 'struct': 'BlockStats',
>        'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
>                 '*parent': 'BlockStats',
>                 '*backing': 'BlockStats'} }
>  
> +It's also possible to create documentation sections, such as:
> +
> +    ##
> +    # = Section
> +    # == Subsection
> +    #
> +    # Some text foo with *emphasis*
> +    # 1. with a list
> +    # 2. like that
> +    #
> +    # And some code:
> +    # | $ echo foo
> +    # | <- do this
> +    # | -> get that
> +    #
> +    ##
> +
>  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

This may be good enough to guide users, but it's not rigorous enough to
actually implement a parser.  The API doc language needs to be specified
as a grammar.  If not here, then elsewhere.

Now go back to QAPISchemaParser.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script
  2016-10-28 16:44   ` Markus Armbruster
@ 2016-10-28 19:56     ` Eric Blake
  2016-11-02  9:25     ` Marc-André Lureau
  1 sibling, 0 replies; 29+ messages in thread
From: Eric Blake @ 2016-10-28 19:56 UTC (permalink / raw)
  To: Markus Armbruster, Marc-André Lureau; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 8888 bytes --]

On 10/28/2016 11:44 AM, Markus Armbruster wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> 
>> As the name suggests, the qapi2texi script converts JSON QAPI
>> description into a standalone texi file suitable for different target
>> formats.
>>
>> It parses the following kind of blocks with some little variations:
>>
>>   ##
>>   # = Section
>>   # == Subsection
>>   #
>>   # Some text foo with *emphasis*
>>   # 1. with a list
>>   # 2. like that
>>   #
>>   # And some code:
>>   # | $ echo foo
>>   # | <- do this
>>   # | -> get that

Backwards.  Pre-patch, qmp-commands.txt states:

> Also, the following notation is used to denote data flow:
> 
> -> data issued by the Client
> <- Server data response

so you want

-> do this
<- get that

>>   #
>>   ##

How much effort is it to get rid of the "little variations" and flag
documentation that does not match consistent patterns?  A tighter parser
that requires specific format, but also diagnoses where comments don't
meet that format, is probably going to be easier to maintain in the long
run (fewer special cases) even if it is more painful up front (more
tweaks to bring things into a consistent layout).


>>
>>   ##
>>   # @symbol
>>   #
>>   # Symbol body ditto ergo sum. Foo bar
>>   # baz ding.
>>   #
>>   # @arg: foo
>>   # @arg: #optional foo
>>   #
>>   # Returns: returns bla bla
>>   #
>>   #          Or bla blah
>>   #
>>   # Since: version
>>   # Notes: notes, comments can have
>>   #        - itemized list
>>   #        - like this
>>   #
>>   #        and continue...
>>   #
>>   # Example:
>>   #
>>   # <- { "execute": "quit" }
>>   # -> { "return": {} }

Again, backwards.

>>   #
>>   ##
>>
>> Thanks to the json declaration, it's able to give extra information
>> about the type of arguments and return value expected.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi.py        | 100 +++++++++++++++-
>>  scripts/qapi2texi.py   | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  docs/qapi-code-gen.txt |  44 +++++--
>>  3 files changed, 446 insertions(+), 12 deletions(-)
>>  create mode 100755 scripts/qapi2texi.py
> 
> My review will be easier to follow if you skip ahead qapi-code-gen.txt,
> then go to class QAPISchemaParser, then come back here.

Commenting on just a few points:

>> +            if key.startswith("@"):
>> +                key = key[1:].rstrip(':')
> 
> Treats the colon as optional.  I understand you're trying to be
> unintrusive, but since we're parsing comments already, we can make the
> parser do double duty and enforce consistent comment formatting.  But
> this isn't the place to discuss the format we want, review of
> qapi-code-gen.txt is.

Makes sense - since we are writing a parser, we can make it be strict
and pick one approved format, rather than allowing two separate formats;
the parser will point out what needs to be fixed, and we actually make
those fixes then rearrange the series so the fixes come first.

> 
> Taken together:
> 
> * The QAPI parser is hacked to accumulate and exfiltrate some comments
>   to the QAPIDoc parser.

I haven't closely looked at the code yet, just the review comments at
this point.  During the QAPI parse of the .json file, are we passing the
entire ##...## comment (of which there should be at most one per
top-level element of the .json file), and then letting QAPIDoc further
parse that comment block?  Or are you trying to combine both levels of
parsing into the same parser object?


> General remarks:
> 
> * I feel the only way to keep the API documentation in order as we
>   develop is to have the parser reject malformed API comments.

Agreed. Forcing docs to be well-written up front will pay benefits in
ease of maintenance and uniformity of style (it's a lot easier to
copy-and-paste a working style if that is the only style to copy from),
once we have converted existing documentation to be well-formed.

> 
> * The only way to create a robust and maintainable parser is to specify
>   the language *first* and *rigorously*.
> 
> * Stacking parsers is not a good idea.  Figuring out one parser's
>   accepted language is hard enough.

We do have the nice aspect that there is (should be) at most one ##...##
comment body per QAPI (pseudo-JSON) object, so the QAPI parse just needs
to find that comment block and associate it with everything else it
parsed.  Further parsing the documentation comment into sections for
output, as well as double-checking sanity aspects (such as no missing or
extra parameters) may require more coordination between the parsed QAPI
object and the code that parses the comments.


>> +++ b/docs/qapi-code-gen.txt
>> @@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no place where a QAPI
>>  schema requires the use of JSON numbers or null.
>>  
>>  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 members 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
>> +newline is ignored.  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 members 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:

Okay, so you ARE requiring the grammar to pull out all lines between two
## markers, as well as looking for specific features to delineate
sections with the lines.  This text doesn't mention Return or Example,
so maybe it's worth further spelling it out, something like:


api_comment ::= double_hash expr_name [overviews] [members] \
                 [return] since [note] [examples] double_hash

along with semantic constraints.  For example, expr_name ::= name ':',
with the constraint that name matches the JSON description; members
would be a list of productions matching the JSON description, where each
member ::= '@' name ':' [#optional] freeform [member_since].

>>  
>>      ##
>> @@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
>>      #           (Since 2.0)
>>      #
>>      # Since: 0.14.0
>> +    #
>> +    # Notes: You can also make a list:
>> +    #        - with items
>> +    #        - like this
>> +    #
>> +    # Example:
>> +    #
>> +    # <- { "execute": ... }
>> +    # -> { "return": ... }

Again, backwards (looks like copy and paste between the
qapi-code-gen.txt and the commit message).

>> +    #
>>      ##
>>      { 'struct': 'BlockStats',
>>        'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
>>                 '*parent': 'BlockStats',
>>                 '*backing': 'BlockStats'} }
>>  
>> +It's also possible to create documentation sections, such as:
>> +
>> +    ##
>> +    # = Section
>> +    # == Subsection
>> +    #
>> +    # Some text foo with *emphasis*
>> +    # 1. with a list
>> +    # 2. like that
>> +    #
>> +    # And some code:
>> +    # | $ echo foo
>> +    # | <- do this
>> +    # | -> get that
>> +    #
>> +    ##
>> +
>>  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
> 
> This may be good enough to guide users, but it's not rigorous enough to
> actually implement a parser.  The API doc language needs to be specified
> as a grammar.  If not here, then elsewhere.

I agree with the sentiment - a tighter description on exactly what is
valid vs. required, and where some of the validity is semantics based
(the comments must match the JSON description), can help us write a
parser that enforces those rules.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script
  2016-10-28 16:44   ` Markus Armbruster
  2016-10-28 19:56     ` Eric Blake
@ 2016-11-02  9:25     ` Marc-André Lureau
  2016-11-03 13:46       ` Markus Armbruster
  1 sibling, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-11-02  9:25 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

Hi

On Fri, Oct 28, 2016 at 7:45 PM Markus Armbruster <armbru@redhat.com> wrote:

> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
> > As the name suggests, the qapi2texi script converts JSON QAPI
> > description into a standalone texi file suitable for different target
> > formats.
> >
> > It parses the following kind of blocks with some little variations:
> >
> >   ##
> >   # = Section
> >   # == Subsection
> >   #
> >   # Some text foo with *emphasis*
> >   # 1. with a list
> >   # 2. like that
> >   #
> >   # And some code:
> >   # | $ echo foo
> >   # | <- do this
> >   # | -> get that
> >   #
> >   ##
> >
> >   ##
> >   # @symbol
> >   #
> >   # Symbol body ditto ergo sum. Foo bar
> >   # baz ding.
> >   #
> >   # @arg: foo
> >   # @arg: #optional foo
> >   #
> >   # Returns: returns bla bla
> >   #
> >   #          Or bla blah
> >   #
> >   # Since: version
> >   # Notes: notes, comments can have
> >   #        - itemized list
> >   #        - like this
> >   #
> >   #        and continue...
> >   #
> >   # Example:
> >   #
> >   # <- { "execute": "quit" }
> >   # -> { "return": {} }
> >   #
> >   ##
> >
> > Thanks to the json declaration, it's able to give extra information
> > about the type of arguments and return value expected.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  scripts/qapi.py        | 100 +++++++++++++++-
> >  scripts/qapi2texi.py   | 314
> +++++++++++++++++++++++++++++++++++++++++++++++++
> >  docs/qapi-code-gen.txt |  44 +++++--
> >  3 files changed, 446 insertions(+), 12 deletions(-)
> >  create mode 100755 scripts/qapi2texi.py
>
> My review will be easier to follow if you skip ahead qapi-code-gen.txt,
> then go to class QAPISchemaParser, then come back here.
>
> > diff --git a/scripts/qapi.py b/scripts/qapi.py
> > index 21bc32f..4efc7e7 100644
> > --- a/scripts/qapi.py
> > +++ b/scripts/qapi.py
> > @@ -122,6 +122,79 @@ class QAPIExprError(Exception):
> >              "%s:%d: %s" % (self.info['file'], self.info['line'],
> self.msg)
> >
> >
> > +class QAPIDoc:
>
> Old-style class.  Make this
>
>    class QAPIDoc(object):
>

ok


>
> > +    def __init__(self, comment):
> > +        self.symbol = None
> > +        self.comment = "" # the main symbol comment
>
> PEP8 wants at least two spaces before #, and I prefer the # in colum 32.
>

let's just remove that comment


>
> > +        self.args = OrderedDict()
> > +        # meta is for Since:, Notes:, Examples:, Returns:...
> > +        self.meta = OrderedDict()
> > +        # the current section to populate, array of [dict, key,
> comment...]
> > +        self.section = None
> > +
> > +        for line in comment.split('\n'):
>
> Makes me wonder whether the caller should pass a list of lines instead
> of a string that needs to be split into lines.
>
> > +            # remove multiple spaces
> > +            sline = ' '.join(line.split())
>
> Actually, this doesn't "remove multiple spaces", it squeezes sequences
> of whitespace into a single space character.  Rather inefficiently, I
> suspect, but let's not worry about that now.
>
> > +            # take the first word out
> > +            split = sline.split(' ', 1)
> > +            key = split[0]
> > +
> > +            if key.startswith("@"):
> > +                key = key[1:].rstrip(':')
>
> Treats the colon as optional.  I understand you're trying to be
> unintrusive, but since we're parsing comments already, we can make the
> parser do double duty and enforce consistent comment formatting.  But
> this isn't the place to discuss the format we want, review of
> qapi-code-gen.txt is.
>

Indeed, I was being permissive: my initial plan was rather to have
something quickly last year. It's simply comments, it does not have to be
rigorous as code to me. Now that we are taking >1.5y to get it in, we may
as well enforce more stuff from the start. Obviously that kind of feedback
would have been nice earlier.  (needless to say my motivation is lower than
when I started)

>
> > +                sline = split[1] if len(split) > 1 else ""
> > +                if self.symbol is None:
> > +                    # the first is the section symbol
> > +                    self.symbol = key
>
> Let's not say "the section symbol".  It's the symbol this APIDoc object
> documents.  The APIDoc object has sections.
>

ok


>
> > +                else:
> > +                    # else an arg
> > +                    self.start_section(self.args, key)
> > +            elif self.symbol and \
> > +                    key in ("Returns:",
> > +                            # special case for Since often used without:
> > +                            "Since:", "Since",
> > +                            # those are often singular or plural
> > +                            "Note:", "Notes:",
> > +                            "Example:", "Examples:"):
> > +                sline = split[1] if len(split) > 1 else ""
> > +                line = None
> > +                # new "meta" section
> > +                self.start_section(self.meta, key.rstrip(':'))
> > +
> > +            if self.section and self.section[1].startswith("Example"):
> > +                # example is verbatim
> > +                self.append_comment(line)
> > +            else:
> > +                self.append_comment(sline)
>
> Sections other than "Example" and "Examples" have whitespace squeezed.
> I believe this is the true reason for the squeezing.  There are a few
> other places that rely on it, but they could do just as well without.
>

Overall, it should help produce a more homogeneous output. Any issue with
that, or should I try to remove the whitespace squeeze?

>
> > +
> > +        self.end_section()
> > +
> > +    def append_comment(self, line):
> > +        """Adds a comment to the current section, or the symbol
> comment"""
> > +        if line is None:
> > +            return
> > +        if self.section is not None:
> > +            if self.section[-1] == "" and line == "":
> > +                self.end_section()
> > +            else:
> > +                self.section.append(line)
> > +        elif self.comment == "":
> > +            self.comment = line
> > +        else:
> > +            self.comment += "\n" + line
>
> Accumulating a list and joining at the end might be easier.
>

Yes, I am not trying to be the fastest python doc parser ;) I'll try to
improve it.


>
> > +
> > +    def end_section(self):
> > +        if self.section is not None:
> > +            dic = self.section[0]
>
> Calling a dictionary "dic" could be considered a dick move ;-P
>

 dict is built-in, let's call it "target"


> > +            key = self.section[1]
> > +            doc = "\n".join(self.section[2:])
> > +            dic[key] = doc
>
> Silently trashes previous value of dic[key].
>

As this is a loosy parser, it was by design ;). But if we want to enforce
things, it could as well throw an error.


>
> > +            self.section = None
> > +
> > +    def start_section(self, dic, key):
> > +        self.end_section()
> > +        self.section = [dic, key]  # .. remaining elems will be the doc
>
> Taken together:
>
> * The QAPI parser is hacked to accumulate and exfiltrate some comments
>   to the QAPIDoc parser.
>
> * A QAPIDoc can have a symbol, a symbol comment, and sections.
>
> * Certain patterns in the comment text start and end sections.
>
>   Text within a section belongs to the section.  Text outside sections
>   belongs to the symbol comment.  Unlikely to work unless the symbol
>   comment is entirely before the first section.
>
> * Two kinds of sections, argument and meta:
>
>   - An argument section is uniquely identified by the argument's name
>
>     Multiple argument sections with the same name make no sense.  The
>     code silently ignores all but the last one.
>
>   - A meta section is uniqely identified by a keyword
>
>     The keywords are: "Returns", "Since", "Note", "Notes", "Example",
>     "Examples".
>
>     Multiple meta sections with the same key make sense for some keys
>     ("Note") but not for others ("Returns", "Since").  Nevertheless, the
>     code silently ignores all but the last one.  You can't have two
>     "Example" sections, but you can have an "Example" and an "Examples"
>     section.  I'm afraid the data structure isn't quite right here.
>

> * No comment is ever rejected.  Comments adhering to the format we have
>   in mind generate correct documentation.  Mistakes may produce correct
>   documentation, subtly incorrect documentation, or obvious garbage.
>   When you get garbage (obvious or not), you have to guess what's wrong
>   with your comment.  "Fortunately", developers generally won't have to
>   do that, because they generally don't read the generated
>   documentation.
>
> General remarks:
>
> * I feel the only way to keep the API documentation in order as we
>   develop is to have the parser reject malformed API comments.
>
> ok


> * The only way to create a robust and maintainable parser is to specify
>   the language *first* and *rigorously*.
>

I am not convinced rigorous is necessary here. After all, plenty of
successful doc/markup languauges are not that rigorous.

>
> * Stacking parsers is not a good idea.  Figuring out one parser's
>   accepted language is hard enough.
>

Does that mean you would prefer to have the doc parsing inside
QAPISchemaParser? I can go in that direction if that's correct, but I fear
it will interfere with the json parsing...


>
> * For me, the parsing part of this patch is a prototype.  Possibly even
>   good enough to commit, with some work.  But it'll have to be redone
>   from first principles regardless.
>

While I agree with you that having a strict parser would be an improvement,
I don't feel it's necessary as a first approach. Since qapi & doc is
internal to qemu, it's easy enough to evolve without risking to break
outside-qemu users.


>
> > +
> > +
> >  class QAPISchemaParser(object):
> >
> >      def __init__(self, fp, previously_included=[], incl_info=None):
> > @@ -137,11 +210,14 @@ class QAPISchemaParser(object):
> >          self.line = 1
> >          self.line_pos = 0
> >          self.exprs = []
> > +        self.comment = None
> > +        self.apidoc = incl_info['doc'] if incl_info else []
> >          self.accept()
> >
> >          while self.tok is not None:
> >              expr_info = {'file': fname, 'line': self.line,
> > -                         'parent': self.incl_info}
> > +                         'parent': self.incl_info, 'doc': self.apidoc}
> > +            self.apidoc = []
> >              expr = self.get_expr(False)
> >              if isinstance(expr, dict) and "include" in expr:
> >                  if len(expr) != 1:
>
> Before your patch, expr_info holds the (top-level) expression's location
> plus the list of include directive locations that led to the expression.
>
> You extend it by key 'doc'.  Let's see what it's good for.
>
> At every (sub-)expression, we capture the current state of self.apidoc
> in expr_info['doc'], then reset self.apidoc to [].  Odd; I would expect
> API documentation to attach only to top-level expressions.
>
>
Isn't  QAPISchemaParser __init__ loop only for top-level exprs?

Looks like expr_info['doc'] and self.apidoc are lists, and self.apidoc
> accumulates documentation until we move it to the next expression's
> expr_info['doc'].  In other words, self.apidoc accumulates documentation
> for the next expression.
>
> yes


> I don't quite understand why you initialize self.apidoc the way you do:
> if this file is included, self.apidoc is initialized to the include
> directive's expr_info['doc'], else to the empty list.  What are you
> trying to accomplish by that?
>

We have comments associated only to expressions. Changing that would be
another major change. It accumulates previous comments across files
boundaries, so you can have:

##
# = Introduction
# blah blah

include foo.json (with exprs)

##
# @sym:
#...
##


The "Introduction" would be attached to the following foo.json expr. That
way it keeps read order.

>
> > @@ -162,6 +238,8 @@ class QAPISchemaParser(object):
> >                      inf = inf['parent']
> >                  # skip multiple include of the same file
> >                  if incl_abs_fname in previously_included:
> > +                    expr_info['doc'].extend(self.apidoc)
> > +                    self.apidoc = expr_info['doc']
> >                      continue
> >                  try:
> >                      fobj = open(incl_abs_fname, 'r')
>
> Before your patch, we indeed skip, as the comment says.  After your
> patch, we do something that's not yet obvious to me, then skip.  The
> comment isn't quite right anymore.
>
> Let's see what we do when we include a file a second time:
>
> 1. We append self.apidoc to expr_info['doc'].  But self.apidoc is []
> here, isn't it?
>
> 2. We assign the result back to self.apidoc.
>
> I think this is effectively
>
>                        self.apidoc = expr_info['doc']
>
> What are you trying to accomplish?
>

It should restore self.apidoc as if nothing happened, so the apidoc is
accumulated for the next expr in the current file. self.apidoc could have
accumulated since we call self.get_expr() (there is a small output diff I
remove remove the extend)


> > @@ -176,6 +254,12 @@ class QAPISchemaParser(object):
> >                               'info': expr_info}
> >                  self.exprs.append(expr_elem)
> >
> > +    def append_doc(self):
> > +        if self.comment:
> > +            apidoc = QAPIDoc(self.comment)
> > +            self.apidoc.append(apidoc)
> > +            self.comment = None
> > +
>
> Too many things called apidoc.  I'd elide the local variable:
>
>                self.apidoc.append(QAPIDoc(self.comment))
>
> Neither the role of self.comment nor self.apidoc are obvious just yet.
>
> self.apidoc is the accumulated QAPIDoc list (made from self.comment on
append_doc())
self.comment is the accumulated comment string since last append_doc(),

>      def accept(self):
> >          while True:
> >              self.tok = self.src[self.cursor]
> > @@ -184,8 +268,20 @@ class QAPISchemaParser(object):
> >              self.val = None
> >
> >              if self.tok == '#':
> > -                self.cursor = self.src.find('\n', self.cursor)
> > +                end = self.src.find('\n', self.cursor)
> > +                line = self.src[self.cursor:end+1]
>
>                    self.cursor = self.src.find('\n', self.cursor)
>                    line = self.src[self.pos:self.cursor+1]
>
> and drop the self.cursor = end below.
>
> @line isn't actually the source line, it's the source line with the
> initial '#' chopped off.  Hmm.
>
> Note that .find() can't fail, because we made sure self.src ends with
> '\n'.
>
>
ok


> > +                # start a comment section after ##
> > +                if line[0] == "#":
> > +                    if self.comment is None:
> > +                        self.comment = ""
> > +                # skip modeline
> > +                elif line.find("-*") == -1 and self.comment is not None:
> > +                    self.comment += line
>
> Aha: self.comment is either None or a string.  When it's a string, we're
> accumulating a (multi-line) comment there.  We start accumulating when a
> comment starts with '##'.  We stop by calling self.append_doc(), which
> processes the accumulated comment, and appends the result to the list
> self.apidoc.
>
> If a comment starting with '##' occurs while we're already accumulating,
> we silently ignore it.  I don't think that's a good idea.
>
>
It allows to write things like:

##
# = Intro

##
# == Foo
#
# blah
#

##
# @expr:
##
expr

Acceptable, unacceptable? It's not my main concern.

Likewise, we silently ignore any comment lines containing '-*'.  That's
> definitely not a good idea; your pattern is far too loose.  Why do we
> need to ignore such lines?
>

we have modelines:
 # -*- Mode: Python -*-

Again we could be stricter here, that wasn't my goal


> > +                if self.src[end] == "\n" and self.src[end+1] == "\n":
>
> If this is the last line, self.src[end+1] is out of bounds, I'm afraid.
>

Right, that could eventually happen, it didn't reach it though.


> > +                    self.append_doc()
>
> We stop accumulating when a comment line is followed by a blank line,
> and ...
>
> > +                self.cursor = end
> >              elif self.tok in "{}:,[]":
> > +                self.append_doc()
>
> ... when we recognize one of the tokens '{', '}', ':', ',' '[', ']'.
>
> This isn't a parser, it's a hack :)


> In this contrieved example, your code joins the two comments into one:
>
>     { 'command: 'contrived-example-1', 'gen':
>     ## lorem ipsum
>       false
>     # dolor sit amet
>     }
>
> In this one, it doesn't:
>
>     { 'command: 'contrived-example-2', 'gen':
>     ## lorem ipsum
>       false }
>     # dolor sit amet
>
> In my opinion, this needs a healthy dose of rigor.  Make API comments a
> proper *syntactical* construct: starts with a comment token whose text
> is exactly '##', extends until the first non-comment token.
>
> Two ways to parse this:
>
> * Lexically, i.e. gobble up the whole comment block as a single token.
>   Drawback: tokens spanning lines defeat the elegant treatment of
>   newline in one place.  Meh.
>
> * Treat it as an expression: have a method get_api_comment() that keeps
>   calling self.accept() until it sees a non-comment token.  To ease
>   getting the comment text, we can make self.accept() store it in
>   self.val.
>
> This also reduces modifiable state: self.comment goes away.  Non-local
> modifiable state is evil.
>

 Ok I'll try to treat it as an expression.


> Now let me try to summarize how this works with parsing details ignored:
>
> 0. We accumulate the next expression's API documentation in self.apidoc,
> a list of QAPIDoc.
>
> 1. We accumulate the current API comment in self.comment.
>
> 2. When it's complete, we call self.append_doc().  append_doc()
> processes self.comment into a QAPIDoc, which it appends to self.apidoc,
> then resets self.comment.
>
> 3. When we recognize the start of an expression, we move self.apidoc to
> the expressions expr_info['doc'].
>
> Taken together: each (sub-)expression has a list of QAPIDoc objects that
> got recognized since the last start of a (sub-)expression.
>
> Now go back to class QAPIDoc.
>
> >                  return
> >              elif self.tok == "'":
> >                  string = ''
> > diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> > new file mode 100755
> > index 0000000..2706b16
> > --- /dev/null
> > +++ b/scripts/qapi2texi.py
> [Skipping the generator for now]
> > diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> > index 5d4c2cd..e51ae4c 100644
> > --- a/docs/qapi-code-gen.txt
> > +++ b/docs/qapi-code-gen.txt
> > @@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no
> place where a QAPI
> >  schema requires the use of JSON numbers or null.
> >
> >  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 members 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
> > +newline is ignored.  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 members 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:
> >
> >      ##
> > @@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
> >      #           (Since 2.0)
> >      #
> >      # Since: 0.14.0
> > +    #
> > +    # Notes: You can also make a list:
> > +    #        - with items
> > +    #        - like this
> > +    #
> > +    # Example:
> > +    #
> > +    # <- { "execute": ... }
> > +    # -> { "return": ... }
> > +    #
> >      ##
> >      { 'struct': 'BlockStats',
> >        'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
> >                 '*parent': 'BlockStats',
> >                 '*backing': 'BlockStats'} }
> >
> > +It's also possible to create documentation sections, such as:
> > +
> > +    ##
> > +    # = Section
> > +    # == Subsection
> > +    #
> > +    # Some text foo with *emphasis*
> > +    # 1. with a list
> > +    # 2. like that
> > +    #
> > +    # And some code:
> > +    # | $ echo foo
> > +    # | <- do this
> > +    # | -> get that
> > +    #
> > +    ##
> > +
> >  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
>
> This may be good enough to guide users, but it's not rigorous enough to
> actually implement a parser.  The API doc language needs to be specified
> as a grammar.  If not here, then elsewhere.
>
>
api_comment = "##\n" comment "##\n"
comment = freeform_comment | symbol_comment
freeform_comment = { "#" text "\n" }
symbol_comment = "#" "@" name ":\n" { freeform | member | meta }
member = "#" '@' name ':' [ text ] freeform_comment
meta = "#" ( "Returns:", "Since:", "Note:", "Notes:", "Example:",
"Examples:" ) [ text ] freeform_comment

text = free-text markdown-like, "#optional" for members

The grammar gives a lot of free-form, and it's hard to describe in
details.  It's already barely readable imho and it's missing many details.
Do you think people will actually care and read it? Or they would just look
at example, copy, fix, and iterate. I would simply make the doc parser a
bit more robust to report anomalies.

If we want to have a very strict grammar, there is even more work needed to
cleanup the documentation. I don't fancy doing that work, it gives only low
benefits.

Now go back to QAPISchemaParser.
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed)
  2016-10-26  9:36 ` [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Markus Armbruster
@ 2016-11-02 12:11   ` Markus Armbruster
  0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2016-11-02 12:11 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Markus Armbruster <armbru@redhat.com> writes:

> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Hi,
>>
>> Add a qapi2texi script to generate the documentation from the qapi
>> schemas. Build various new documentation targets for it: pdf, man,
>> txt. The 7th patch in this series is a squashed version of the
>> documentation move from qmp-commands.txt to the schemas. The whole
>> version (not sent on the ML to avoid spamming) is in the following git
>> branch: https://github.com/elmarco/qemu/commits/qapi-doc
>
> I apologize for the delay in review, in particular since parts of this
> series rot rather quickly.
>
> You already rebased your git branch to commit 4387f56 on master.  The
> branch has PATCH 07 split.  The branch doesn't rebase cleanly to current
> master, but the conflicts are all in the shards of PATCH 07.
>
> For review, I applied the patches as sent to current master (commit
> ede0cbe).  Two patches conflict.  PATCH 07 "(SQUASHED) qmp-commands docs
> move to schema" I simply skipped.  PATCH 11 "build-sys: make and install
> the generated schema docs" conflicts with commit 78e8779 "qemu-doc:
> merge qemu-tech and qemu-doc", but it's easy enough to resolve, and you
> already did it in your git branch.

Actually, needs a conflict resolution fix:

diff --git a/Makefile b/Makefile
index 8cf1e38..24d5fb8 100644
--- a/Makefile
+++ b/Makefile
@@ -627,8 +627,8 @@ qemu-ga-qapi.7: qemu-ga-qapi.texi
 
 dvi: qemu-doc.dvi qemu-qapi.dvi qemu-ga-qapi.dvi
 html: qemu-doc.html qemu-qapi.html qemu-ga-qapi.html
-info: qemu-doc.info qemu-tech.info qemu-qapi.info qemu-ga-qapi.info
-pdf: qemu-doc.pdf qemu-tech.pdf qemu-qapi.pdf qemu-ga-qapi.pdf
+info: qemu-doc.info qemu-qapi.info qemu-ga-qapi.info
+pdf: qemu-doc.pdf qemu-qapi.pdf qemu-ga-qapi.pdf
 
 qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
        qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \


> Next: actual review the patches.

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script
  2016-11-02  9:25     ` Marc-André Lureau
@ 2016-11-03 13:46       ` Markus Armbruster
  2016-11-03 16:24         ` Marc-André Lureau
  0 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2016-11-03 13:46 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Fri, Oct 28, 2016 at 7:45 PM Markus Armbruster <armbru@redhat.com> wrote:
>
>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>
>> > As the name suggests, the qapi2texi script converts JSON QAPI
>> > description into a standalone texi file suitable for different target
>> > formats.
>> >
>> > It parses the following kind of blocks with some little variations:
>> >
>> >   ##
>> >   # = Section
>> >   # == Subsection
>> >   #
>> >   # Some text foo with *emphasis*
>> >   # 1. with a list
>> >   # 2. like that
>> >   #
>> >   # And some code:
>> >   # | $ echo foo
>> >   # | <- do this
>> >   # | -> get that
>> >   #
>> >   ##
>> >
>> >   ##
>> >   # @symbol
>> >   #
>> >   # Symbol body ditto ergo sum. Foo bar
>> >   # baz ding.
>> >   #
>> >   # @arg: foo
>> >   # @arg: #optional foo
>> >   #
>> >   # Returns: returns bla bla
>> >   #
>> >   #          Or bla blah
>> >   #
>> >   # Since: version
>> >   # Notes: notes, comments can have
>> >   #        - itemized list
>> >   #        - like this
>> >   #
>> >   #        and continue...
>> >   #
>> >   # Example:
>> >   #
>> >   # <- { "execute": "quit" }
>> >   # -> { "return": {} }
>> >   #
>> >   ##
>> >
>> > Thanks to the json declaration, it's able to give extra information
>> > about the type of arguments and return value expected.
>> >
>> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> > ---
>> >  scripts/qapi.py        | 100 +++++++++++++++-
>> >  scripts/qapi2texi.py   | 314
>> +++++++++++++++++++++++++++++++++++++++++++++++++
>> >  docs/qapi-code-gen.txt |  44 +++++--
>> >  3 files changed, 446 insertions(+), 12 deletions(-)
>> >  create mode 100755 scripts/qapi2texi.py
>>
>> My review will be easier to follow if you skip ahead qapi-code-gen.txt,
>> then go to class QAPISchemaParser, then come back here.
>>
>> > diff --git a/scripts/qapi.py b/scripts/qapi.py
>> > index 21bc32f..4efc7e7 100644
>> > --- a/scripts/qapi.py
>> > +++ b/scripts/qapi.py
>> > @@ -122,6 +122,79 @@ class QAPIExprError(Exception):
>> >              "%s:%d: %s" % (self.info['file'], self.info['line'],
>> self.msg)
>> >
>> >
>> > +class QAPIDoc:
>>
>> Old-style class.  Make this
>>
>>    class QAPIDoc(object):
>>
>
> ok
>
>
>>
>> > +    def __init__(self, comment):
>> > +        self.symbol = None
>> > +        self.comment = "" # the main symbol comment
>>
>> PEP8 wants at least two spaces before #, and I prefer the # in colum 32.
>>
>
> let's just remove that comment
>
>
>>
>> > +        self.args = OrderedDict()
>> > +        # meta is for Since:, Notes:, Examples:, Returns:...
>> > +        self.meta = OrderedDict()
>> > +        # the current section to populate, array of [dict, key, comment...]
>> > +        self.section = None
>> > +
>> > +        for line in comment.split('\n'):
>>
>> Makes me wonder whether the caller should pass a list of lines instead
>> of a string that needs to be split into lines.
>>
>> > +            # remove multiple spaces
>> > +            sline = ' '.join(line.split())
>>
>> Actually, this doesn't "remove multiple spaces", it squeezes sequences
>> of whitespace into a single space character.  Rather inefficiently, I
>> suspect, but let's not worry about that now.
>>
>> > +            # take the first word out
>> > +            split = sline.split(' ', 1)
>> > +            key = split[0]
>> > +
>> > +            if key.startswith("@"):
>> > +                key = key[1:].rstrip(':')
>>
>> Treats the colon as optional.  I understand you're trying to be
>> unintrusive, but since we're parsing comments already, we can make the
>> parser do double duty and enforce consistent comment formatting.  But
>> this isn't the place to discuss the format we want, review of
>> qapi-code-gen.txt is.
>>
>
> Indeed, I was being permissive: my initial plan was rather to have
> something quickly last year. It's simply comments, it does not have to be
> rigorous as code to me. Now that we are taking >1.5y to get it in, we may
> as well enforce more stuff from the start.

My aim is to avoid silent garbage-in, garbage out in the long run, where
"garbage" input looks innocent at least to casual reviewers, and to
assist developers in writing non-garbage input.

A quick solution that doesn't accomplish that may still get us closer.
Or it may be an avoidable detour.  Depends.

>                                            Obviously that kind of feedback
> would have been nice earlier.

You're absolutely right.

>                                (needless to say my motivation is lower than
> when I started)

Who wouldn't be frustrated by such delays!

You're the victim of unlucky timing and perhaps questionable judgement
calls.  Your work arrived in the middle of the huge effort to merge
Eric's work.  For better or worse, we decided to stay focused on the
task that was in progress.  Maybe we should've paused at least for some
high level review, and to see whether we could pick at least some
cherries from your work.

However, the only way I knew to keep me from despairing over the state
of the QAPI review backlog back then was to doggedly do one patch after
the other, without looking ahead.

>> > +                sline = split[1] if len(split) > 1 else ""
>> > +                if self.symbol is None:
>> > +                    # the first is the section symbol
>> > +                    self.symbol = key
>>
>> Let's not say "the section symbol".  It's the symbol this APIDoc object
>> documents.  The APIDoc object has sections.
>>
>
> ok
>
>
>>
>> > +                else:
>> > +                    # else an arg
>> > +                    self.start_section(self.args, key)
>> > +            elif self.symbol and \
>> > +                    key in ("Returns:",
>> > +                            # special case for Since often used without:
>> > +                            "Since:", "Since",
>> > +                            # those are often singular or plural
>> > +                            "Note:", "Notes:",
>> > +                            "Example:", "Examples:"):
>> > +                sline = split[1] if len(split) > 1 else ""
>> > +                line = None
>> > +                # new "meta" section
>> > +                self.start_section(self.meta, key.rstrip(':'))
>> > +
>> > +            if self.section and self.section[1].startswith("Example"):
>> > +                # example is verbatim
>> > +                self.append_comment(line)
>> > +            else:
>> > +                self.append_comment(sline)
>>
>> Sections other than "Example" and "Examples" have whitespace squeezed.
>> I believe this is the true reason for the squeezing.  There are a few
>> other places that rely on it, but they could do just as well without.
>>
>
> Overall, it should help produce a more homogeneous output. Any issue with
> that, or should I try to remove the whitespace squeeze?

Does it really affect the final output?  Texinfo normally collapses
multiple whitespace characters...

>> > +
>> > +        self.end_section()
>> > +
>> > +    def append_comment(self, line):
>> > +        """Adds a comment to the current section, or the symbol comment"""
>> > +        if line is None:
>> > +            return
>> > +        if self.section is not None:
>> > +            if self.section[-1] == "" and line == "":
>> > +                self.end_section()
>> > +            else:
>> > +                self.section.append(line)
>> > +        elif self.comment == "":
>> > +            self.comment = line
>> > +        else:
>> > +            self.comment += "\n" + line
>>
>> Accumulating a list and joining at the end might be easier.
>>
>
> Yes, I am not trying to be the fastest python doc parser ;) I'll try to
> improve it.

Note I said "easier" not "faster" :)

>> > +
>> > +    def end_section(self):
>> > +        if self.section is not None:
>> > +            dic = self.section[0]
>>
>> Calling a dictionary "dic" could be considered a dick move ;-P
>>
>
>  dict is built-in, let's call it "target"
>
>
>> > +            key = self.section[1]
>> > +            doc = "\n".join(self.section[2:])
>> > +            dic[key] = doc
>>
>> Silently trashes previous value of dic[key].
>>
>
> As this is a loosy parser, it was by design ;). But if we want to enforce
> things, it could as well throw an error.
>
>
>>
>> > +            self.section = None
>> > +
>> > +    def start_section(self, dic, key):
>> > +        self.end_section()
>> > +        self.section = [dic, key]  # .. remaining elems will be the doc
>>
>> Taken together:
>>
>> * The QAPI parser is hacked to accumulate and exfiltrate some comments
>>   to the QAPIDoc parser.
>>
>> * A QAPIDoc can have a symbol, a symbol comment, and sections.
>>
>> * Certain patterns in the comment text start and end sections.
>>
>>   Text within a section belongs to the section.  Text outside sections
>>   belongs to the symbol comment.  Unlikely to work unless the symbol
>>   comment is entirely before the first section.
>>
>> * Two kinds of sections, argument and meta:
>>
>>   - An argument section is uniquely identified by the argument's name
>>
>>     Multiple argument sections with the same name make no sense.  The
>>     code silently ignores all but the last one.
>>
>>   - A meta section is uniqely identified by a keyword
>>
>>     The keywords are: "Returns", "Since", "Note", "Notes", "Example",
>>     "Examples".
>>
>>     Multiple meta sections with the same key make sense for some keys
>>     ("Note") but not for others ("Returns", "Since").  Nevertheless, the
>>     code silently ignores all but the last one.  You can't have two
>>     "Example" sections, but you can have an "Example" and an "Examples"
>>     section.  I'm afraid the data structure isn't quite right here.
>>
>
>> * No comment is ever rejected.  Comments adhering to the format we have
>>   in mind generate correct documentation.  Mistakes may produce correct
>>   documentation, subtly incorrect documentation, or obvious garbage.
>>   When you get garbage (obvious or not), you have to guess what's wrong
>>   with your comment.  "Fortunately", developers generally won't have to
>>   do that, because they generally don't read the generated
>>   documentation.
>>
>> General remarks:
>>
>> * I feel the only way to keep the API documentation in order as we
>>   develop is to have the parser reject malformed API comments.
>
> ok
>
>
>> * The only way to create a robust and maintainable parser is to specify
>>   the language *first* and *rigorously*.
>>
>
> I am not convinced rigorous is necessary here. After all, plenty of
> successful doc/markup languauges are not that rigorous.

"Rigorous" applies to the way the language is defined and implemented.
Whether the language is strict or permissive is orthogonal.

>> * Stacking parsers is not a good idea.  Figuring out one parser's
>>   accepted language is hard enough.
>
> Does that mean you would prefer to have the doc parsing inside
> QAPISchemaParser? I can go in that direction if that's correct, but I fear
> it will interfere with the json parsing...

Yes, I'd like us to try that.

However, the boundary between syntax and semantics is a fuzzy one.  Not
everything that can be done in syntax must be done in syntax.

>> * For me, the parsing part of this patch is a prototype.  Possibly even
>>   good enough to commit, with some work.  But it'll have to be redone
>>   from first principles regardless.
>>
>
> While I agree with you that having a strict parser would be an improvement,
> I don't feel it's necessary as a first approach. Since qapi & doc is
> internal to qemu, it's easy enough to evolve without risking to break
> outside-qemu users.

That's true.  Still, it pays to stop and think about the general
structure both of code and data.  Particularly data.  Less rewriting
down the road.

I already had to rewrite the QAPI parser (commit 55d5d04..f1a145e, in
particular commit c7a3f25), I'm not keen on adding more parsers that'll
need a rewrite.

>> > +
>> > +
>> >  class QAPISchemaParser(object):
>> >
>> >      def __init__(self, fp, previously_included=[], incl_info=None):
>> > @@ -137,11 +210,14 @@ class QAPISchemaParser(object):
>> >          self.line = 1
>> >          self.line_pos = 0
>> >          self.exprs = []
>> > +        self.comment = None
>> > +        self.apidoc = incl_info['doc'] if incl_info else []
>> >          self.accept()
>> >
>> >          while self.tok is not None:
>> >              expr_info = {'file': fname, 'line': self.line,
>> > -                         'parent': self.incl_info}
>> > +                         'parent': self.incl_info, 'doc': self.apidoc}
>> > +            self.apidoc = []
>> >              expr = self.get_expr(False)
>> >              if isinstance(expr, dict) and "include" in expr:
>> >                  if len(expr) != 1:
>>
>> Before your patch, expr_info holds the (top-level) expression's location
>> plus the list of include directive locations that led to the expression.
>>
>> You extend it by key 'doc'.  Let's see what it's good for.
>>
>> At every (sub-)expression, we capture the current state of self.apidoc
>> in expr_info['doc'], then reset self.apidoc to [].  Odd; I would expect
>> API documentation to attach only to top-level expressions.
>>
>>
> Isn't  QAPISchemaParser __init__ loop only for top-level exprs?

You're right, I got confused.

>> Looks like expr_info['doc'] and self.apidoc are lists, and self.apidoc
>> accumulates documentation until we move it to the next expression's
>> expr_info['doc'].  In other words, self.apidoc accumulates documentation
>> for the next expression.
>
> yes
>
>
>> I don't quite understand why you initialize self.apidoc the way you do:
>> if this file is included, self.apidoc is initialized to the include
>> directive's expr_info['doc'], else to the empty list.  What are you
>> trying to accomplish by that?
>>
>
> We have comments associated only to expressions. Changing that would be
> another major change. It accumulates previous comments across files
> boundaries, so you can have:
>
> ##
> # = Introduction
> # blah blah
>
> include foo.json (with exprs)
>
> ##
> # @sym:
> #...
> ##
>
>
> The "Introduction" would be attached to the following foo.json expr. That
> way it keeps read order.

I suspect collecting the doc comments in a single list would be easier
than attaching a variable number of comments to the next expression.

I'd treat the "a symbol doc comment precedes the definition" and "there
are no stray symbol doc comments" aspects as syntax, to be taken care of
by the parser.  Once that's out of the way, a symbol-defining
expression's doc comment is always the last doc comment.  The parser can
store a reference to it with the expression for later semantic analysis.
A separate dictionary mapping symbol names to their doc comments might
be easier.

>> > @@ -162,6 +238,8 @@ class QAPISchemaParser(object):
>> >                      inf = inf['parent']
>> >                  # skip multiple include of the same file
>> >                  if incl_abs_fname in previously_included:
>> > +                    expr_info['doc'].extend(self.apidoc)
>> > +                    self.apidoc = expr_info['doc']
>> >                      continue
>> >                  try:
>> >                      fobj = open(incl_abs_fname, 'r')
>>
>> Before your patch, we indeed skip, as the comment says.  After your
>> patch, we do something that's not yet obvious to me, then skip.  The
>> comment isn't quite right anymore.
>>
>> Let's see what we do when we include a file a second time:
>>
>> 1. We append self.apidoc to expr_info['doc'].  But self.apidoc is []
>> here, isn't it?
>>
>> 2. We assign the result back to self.apidoc.
>>
>> I think this is effectively
>>
>>                        self.apidoc = expr_info['doc']
>>
>> What are you trying to accomplish?
>>
>
> It should restore self.apidoc as if nothing happened, so the apidoc is
> accumulated for the next expr in the current file. self.apidoc could have
> accumulated since we call self.get_expr() (there is a small output diff I
> remove remove the extend)

Not sure I fully understand that already, but don't worry about it, I
guess I can figure itout with the explanation you gave.

>> > @@ -176,6 +254,12 @@ class QAPISchemaParser(object):
>> >                               'info': expr_info}
>> >                  self.exprs.append(expr_elem)
>> >
>> > +    def append_doc(self):
>> > +        if self.comment:
>> > +            apidoc = QAPIDoc(self.comment)
>> > +            self.apidoc.append(apidoc)
>> > +            self.comment = None
>> > +
>>
>> Too many things called apidoc.  I'd elide the local variable:
>>
>>                self.apidoc.append(QAPIDoc(self.comment))
>>
>> Neither the role of self.comment nor self.apidoc are obvious just yet.
>>
> self.apidoc is the accumulated QAPIDoc list (made from self.comment on
> append_doc())
> self.comment is the accumulated comment string since last append_doc(),
>
>>      def accept(self):
>> >          while True:
>> >              self.tok = self.src[self.cursor]
>> > @@ -184,8 +268,20 @@ class QAPISchemaParser(object):
>> >              self.val = None
>> >
>> >              if self.tok == '#':
>> > -                self.cursor = self.src.find('\n', self.cursor)
>> > +                end = self.src.find('\n', self.cursor)
>> > +                line = self.src[self.cursor:end+1]
>>
>>                    self.cursor = self.src.find('\n', self.cursor)
>>                    line = self.src[self.pos:self.cursor+1]
>>
>> and drop the self.cursor = end below.
>>
>> @line isn't actually the source line, it's the source line with the
>> initial '#' chopped off.  Hmm.
>>
>> Note that .find() can't fail, because we made sure self.src ends with
>> '\n'.
>>
>>
> ok
>
>
>> > +                # start a comment section after ##
>> > +                if line[0] == "#":
>> > +                    if self.comment is None:
>> > +                        self.comment = ""
>> > +                # skip modeline
>> > +                elif line.find("-*") == -1 and self.comment is not None:
>> > +                    self.comment += line
>>
>> Aha: self.comment is either None or a string.  When it's a string, we're
>> accumulating a (multi-line) comment there.  We start accumulating when a
>> comment starts with '##'.  We stop by calling self.append_doc(), which
>> processes the accumulated comment, and appends the result to the list
>> self.apidoc.
>>
>> If a comment starting with '##' occurs while we're already accumulating,
>> we silently ignore it.  I don't think that's a good idea.
>>
>>
> It allows to write things like:
>
> ##
> # = Intro
>
> ##
> # == Foo
> #
> # blah
> #
>
> ##
> # @expr:
> ##
> expr
>
> Acceptable, unacceptable? It's not my main concern.

For me, that's three comment blocks, the first two not connected to a
symbol, the third connected to @expr.

Ignoring a comment starting with '##' breaks when you write things like

##
## I really like #s, the more, the merrier.
##

>> Likewise, we silently ignore any comment lines containing '-*'.  That's
>> definitely not a good idea; your pattern is far too loose.  Why do we
>> need to ignore such lines?
>>
>
> we have modelines:
>  # -*- Mode: Python -*-
>
> Again we could be stricter here, that wasn't my goal

Yes, .json files that make up the schema start with such a line.  If we
need to filter them out, we should filter roughly like Emacs: stuff
between '-*-' and '-*-' in the first line is file variables.

But I doubt we need to filter them.  For me, these lines are non-doc
comments.  Doc comment blocks start with ##.

>> > +                if self.src[end] == "\n" and self.src[end+1] == "\n":
>>
>> If this is the last line, self.src[end+1] is out of bounds, I'm afraid.
>>
>
> Right, that could eventually happen, it didn't reach it though.
>
>
>> > +                    self.append_doc()
>>
>> We stop accumulating when a comment line is followed by a blank line,
>> and ...
>>
>> > +                self.cursor = end
>> >              elif self.tok in "{}:,[]":
>> > +                self.append_doc()
>>
>> ... when we recognize one of the tokens '{', '}', ':', ',' '[', ']'.
>>
>> This isn't a parser, it's a hack :)
>
>
>> In this contrieved example, your code joins the two comments into one:
>>
>>     { 'command: 'contrived-example-1', 'gen':
>>     ## lorem ipsum
>>       false
>>     # dolor sit amet
>>     }
>>
>> In this one, it doesn't:
>>
>>     { 'command: 'contrived-example-2', 'gen':
>>     ## lorem ipsum
>>       false }
>>     # dolor sit amet
>>
>> In my opinion, this needs a healthy dose of rigor.  Make API comments a
>> proper *syntactical* construct: starts with a comment token whose text
>> is exactly '##', extends until the first non-comment token.
>>
>> Two ways to parse this:
>>
>> * Lexically, i.e. gobble up the whole comment block as a single token.
>>   Drawback: tokens spanning lines defeat the elegant treatment of
>>   newline in one place.  Meh.
>>
>> * Treat it as an expression: have a method get_api_comment() that keeps
>>   calling self.accept() until it sees a non-comment token.  To ease
>>   getting the comment text, we can make self.accept() store it in
>>   self.val.
>>
>> This also reduces modifiable state: self.comment goes away.  Non-local
>> modifiable state is evil.
>>
>
>  Ok I'll try to treat it as an expression.
>
>
>> Now let me try to summarize how this works with parsing details ignored:
>>
>> 0. We accumulate the next expression's API documentation in self.apidoc,
>> a list of QAPIDoc.
>>
>> 1. We accumulate the current API comment in self.comment.
>>
>> 2. When it's complete, we call self.append_doc().  append_doc()
>> processes self.comment into a QAPIDoc, which it appends to self.apidoc,
>> then resets self.comment.
>>
>> 3. When we recognize the start of an expression, we move self.apidoc to
>> the expressions expr_info['doc'].
>>
>> Taken together: each (sub-)expression has a list of QAPIDoc objects that
>> got recognized since the last start of a (sub-)expression.
>>
>> Now go back to class QAPIDoc.
>>
>> >                  return
>> >              elif self.tok == "'":
>> >                  string = ''
>> > diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
>> > new file mode 100755
>> > index 0000000..2706b16
>> > --- /dev/null
>> > +++ b/scripts/qapi2texi.py
>> [Skipping the generator for now]
>> > diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
>> > index 5d4c2cd..e51ae4c 100644
>> > --- a/docs/qapi-code-gen.txt
>> > +++ b/docs/qapi-code-gen.txt
>> > @@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no place where a QAPI
>> >  schema requires the use of JSON numbers or null.
>> >
>> >  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 members 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
>> > +newline is ignored.  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 members 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:
>> >
>> >      ##
>> > @@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
>> >      #           (Since 2.0)
>> >      #
>> >      # Since: 0.14.0
>> > +    #
>> > +    # Notes: You can also make a list:
>> > +    #        - with items
>> > +    #        - like this
>> > +    #
>> > +    # Example:
>> > +    #
>> > +    # <- { "execute": ... }
>> > +    # -> { "return": ... }
>> > +    #
>> >      ##
>> >      { 'struct': 'BlockStats',
>> >        'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
>> >                 '*parent': 'BlockStats',
>> >                 '*backing': 'BlockStats'} }
>> >
>> > +It's also possible to create documentation sections, such as:
>> > +
>> > +    ##
>> > +    # = Section
>> > +    # == Subsection
>> > +    #
>> > +    # Some text foo with *emphasis*
>> > +    # 1. with a list
>> > +    # 2. like that
>> > +    #
>> > +    # And some code:
>> > +    # | $ echo foo
>> > +    # | <- do this
>> > +    # | -> get that
>> > +    #
>> > +    ##
>> > +
>> >  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
>>
>> This may be good enough to guide users, but it's not rigorous enough to
>> actually implement a parser.  The API doc language needs to be specified
>> as a grammar.  If not here, then elsewhere.
>>
>>
> api_comment = "##\n" comment "##\n"
> comment = freeform_comment | symbol_comment
> freeform_comment = { "#" text "\n" }
> symbol_comment = "#" "@" name ":\n" { freeform | member | meta }
> member = "#" '@' name ':' [ text ] freeform_comment
> meta = "#" ( "Returns:", "Since:", "Note:", "Notes:", "Example:",
> "Examples:" ) [ text ] freeform_comment
>
> text = free-text markdown-like, "#optional" for members
>
> The grammar gives a lot of free-form, and it's hard to describe in
> details.  It's already barely readable imho and it's missing many details.
> Do you think people will actually care and read it? Or they would just look
> at example, copy, fix, and iterate. I would simply make the doc parser a
> bit more robust to report anomalies.

The only way to get a robust and maintainable parser is to start with a
grammar.

> If we want to have a very strict grammar, there is even more work needed to
> cleanup the documentation. I don't fancy doing that work, it gives only low
> benefits.

Since I have pretty specific ideas on how I want this part of your much
larger work done, I think it's only fair if I give it a try myself:
propose a grammar, create a parser to show it works, clean up existing
comments to comply with it.

>> Now go back to QAPISchemaParser.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script
  2016-11-03 13:46       ` Markus Armbruster
@ 2016-11-03 16:24         ` Marc-André Lureau
  0 siblings, 0 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-11-03 16:24 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

Hi

On Thu, Nov 3, 2016 at 5:46 PM Markus Armbruster <armbru@redhat.com> wrote:

> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>
> > If we want to have a very strict grammar, there is even more work needed
> to
> > cleanup the documentation. I don't fancy doing that work, it gives only
> low
> > benefits.
>
> Since I have pretty specific ideas on how I want this part of your much
> larger work done, I think it's only fair if I give it a try myself:
> propose a grammar, create a parser to show it works, clean up existing
> comments to comply with it.
>
>
Thank you, I gladly accept the help :) However, could you wait until the
next iteration? I am trying to improve the parsing and simplifying a bit
the code (although probably not reaching your goal)

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/11] qapi: fix missing symbol @prefix
  2016-10-26 13:37   ` Markus Armbruster
@ 2016-11-04 12:05     ` Marc-André Lureau
  0 siblings, 0 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-11-04 12:05 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Marc-André Lureau, qemu-devel



----- Original Message -----
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  qapi-schema.json     |  4 ++--
> >  qapi/block-core.json |  4 ++--
> >  qapi/crypto.json     | 36 ++++++++++++++++++------------------
> >  3 files changed, 22 insertions(+), 22 deletions(-)
> >
> > diff --git a/qapi-schema.json b/qapi-schema.json
> > index f07ffd7..3091993 100644
> > --- a/qapi-schema.json
> > +++ b/qapi-schema.json
> > @@ -4526,7 +4526,7 @@
> >  { 'include': 'qapi/rocker.json' }
> >  
> >  ##
> > -# ReplayMode:
> > +# @ReplayMode:
> >  #
> >  # Mode of the replay subsystem.
> >  #
> > @@ -4594,7 +4594,7 @@
> >  { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
> >  
> >  ##
> > -# CpuInstanceProperties
> > +# @CpuInstanceProperties
> >  #
> >  # List of properties to be used for hotplugging a CPU instance,
> >  # it should be passed by management with device_add command when
> 
> The example in qapi-code-gen.txt has a colon after the symbol name:
> 
>     ##
>     # @BlockStats:
> 
> The text doesn't mention it.  Tne schema uses colons inconsistently, as
> visible above.  Let's enforce colons.

Ok, it's a bit more tricky though, because we have documentation that uses @arg inside text to refer to various symbols (args, commands etc). I've fixed all @symbol: (for sections and members), but I don't see an easy way to enforce this without conflicting with the @arg syntax.

> 
> > diff --git a/qapi/block-core.json b/qapi/block-core.json
> > index cf8e980..73f4180 100644
> > --- a/qapi/block-core.json
> > +++ b/qapi/block-core.json
> > @@ -1149,7 +1149,7 @@
> >    'data': 'DriveMirror' }
> >  
> >  ##
> > -# DriveMirror
> > +# @DriveMirror
> >  #
> >  # A set of parameters describing drive mirror setup.
> >  #
> > @@ -1373,7 +1373,7 @@
> >    'data': 'BlockIOThrottle' }
> >  
> >  ##
> > -# BlockIOThrottle
> > +# @BlockIOThrottle
> >  #
> >  # A set of parameters describing block throttling.
> >  #
> > diff --git a/qapi/crypto.json b/qapi/crypto.json
> > index 6933b13..4ac3034 100644
> > --- a/qapi/crypto.json
> > +++ b/qapi/crypto.json
> > @@ -3,7 +3,7 @@
> >  # QAPI crypto definitions
> >  
> >  ##
> > -# QCryptoTLSCredsEndpoint:
> > +# @QCryptoTLSCredsEndpoint:
> >  #
> >  # The type of network endpoint that will be using the credentials.
> >  # Most types of credential require different setup / structures
> > @@ -22,7 +22,7 @@
> >  
> >  
> >  ##
> > -# QCryptoSecretFormat:
> > +# @QCryptoSecretFormat:
> >  #
> >  # The data format that the secret is provided in
> >  #
> > @@ -36,7 +36,7 @@
> >  
> >  
> >  ##
> > -# QCryptoHashAlgorithm:
> > +# @QCryptoHashAlgorithm:
> >  #
> >  # The supported algorithms for computing content digests
> >  #
> > @@ -55,7 +55,7 @@
> >  
> >  
> >  ##
> > -# QCryptoCipherAlgorithm:
> > +# @QCryptoCipherAlgorithm:
> >  #
> >  # The supported algorithms for content encryption ciphers
> >  #
> > @@ -82,7 +82,7 @@
> >  
> >  
> >  ##
> > -# QCryptoCipherMode:
> > +# @QCryptoCipherMode:
> >  #
> >  # The supported modes for content encryption ciphers
> >  #
> > @@ -97,7 +97,7 @@
> >  
> >  
> >  ##
> > -# QCryptoIVGenAlgorithm:
> > +# @QCryptoIVGenAlgorithm:
> >  #
> >  # The supported algorithms for generating initialization
> >  # vectors for full disk encryption. The 'plain' generator
> > @@ -115,7 +115,7 @@
> >    'data': ['plain', 'plain64', 'essiv']}
> >  
> >  ##
> > -# QCryptoBlockFormat:
> > +# @QCryptoBlockFormat:
> >  #
> >  # The supported full disk encryption formats
> >  #
> > @@ -130,7 +130,7 @@
> >    'data': ['qcow', 'luks']}
> >  
> >  ##
> > -# QCryptoBlockOptionsBase:
> > +# @QCryptoBlockOptionsBase:
> >  #
> >  # The common options that apply to all full disk
> >  # encryption formats
> > @@ -143,7 +143,7 @@
> >    'data': { 'format': 'QCryptoBlockFormat' }}
> >  
> >  ##
> > -# QCryptoBlockOptionsQCow:
> > +# @QCryptoBlockOptionsQCow:
> >  #
> >  # The options that apply to QCow/QCow2 AES-CBC encryption format
> >  #
> > @@ -157,7 +157,7 @@
> >    'data': { '*key-secret': 'str' }}
> >  
> >  ##
> > -# QCryptoBlockOptionsLUKS:
> > +# @QCryptoBlockOptionsLUKS:
> >  #
> >  # The options that apply to LUKS encryption format
> >  #
> > @@ -171,7 +171,7 @@
> >  
> >  
> >  ##
> > -# QCryptoBlockCreateOptionsLUKS:
> > +# @QCryptoBlockCreateOptionsLUKS:
> >  #
> >  # The options that apply to LUKS encryption format initialization
> >  #
> > @@ -201,7 +201,7 @@
> >  
> >  
> >  ##
> > -# QCryptoBlockOpenOptions:
> > +# @QCryptoBlockOpenOptions:
> >  #
> >  # The options that are available for all encryption formats
> >  # when opening an existing volume
> > @@ -216,7 +216,7 @@
> >  
> >  
> >  ##
> > -# QCryptoBlockCreateOptions:
> > +# @QCryptoBlockCreateOptions:
> >  #
> >  # The options that are available for all encryption formats
> >  # when initializing a new volume
> > @@ -231,7 +231,7 @@
> >  
> >  
> >  ##
> > -# QCryptoBlockInfoBase:
> > +# @QCryptoBlockInfoBase:
> >  #
> >  # The common information that applies to all full disk
> >  # encryption formats
> > @@ -245,7 +245,7 @@
> >  
> >  
> >  ##
> > -# QCryptoBlockInfoLUKSSlot:
> > +# @QCryptoBlockInfoLUKSSlot:
> >  #
> >  # Information about the LUKS block encryption key
> >  # slot options
> > @@ -265,7 +265,7 @@
> >  
> >  
> >  ##
> > -# QCryptoBlockInfoLUKS:
> > +# @QCryptoBlockInfoLUKS:
> >  #
> >  # Information about the LUKS block encryption options
> >  #
> > @@ -293,7 +293,7 @@
> >             'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
> >  
> >  ##
> > -# QCryptoBlockInfoQCow:
> > +# @QCryptoBlockInfoQCow:
> >  #
> >  # Information about the QCow block encryption options
> >  #
> > @@ -304,7 +304,7 @@
> >  
> >  
> >  ##
> > -# QCryptoBlockInfo:
> > +# @QCryptoBlockInfo:
> >  #
> >  # Information about the block encryption options
> >  #
> 
> Additionally, there are a few lines that don't match the symbol the
> symbol being defined:
> 
>    diff --git a/qapi-schema.json b/qapi-schema.json
>    index 0cc9ee6..104cc62 100644
>    --- a/qapi-schema.json
>    +++ b/qapi-schema.json
>    @@ -1079,7 +1079,7 @@
>                '*service': 'str', '*auth': 'str', '*clients':
>                ['VncClientInfo']} }
> 
>     ##
>    -# @VncPriAuth:
>    +# @VncPrimaryAuth:
>     #
>     # vnc primary authentication method.
>     #
>    @@ -3889,7 +3889,7 @@
>        'data': { 'passthrough' : 'TPMPassthroughOptions' } }
> 
>     ##
>    -# @TpmInfo:
>    +# @TPMInfo:
>     #
>     # Information about the TPM
>     #
>    diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
>    index 09c9728..07a449b 100644
>    --- a/qga/qapi-schema.json
>    +++ b/qga/qapi-schema.json
>    @@ -378,7 +378,7 @@
>       'data': { 'handle': 'int' } }
> 
>     ##
>    -# @GuestFsFreezeStatus
>    +# @GuestFsfreezeStatus
>     #
>     # An enumeration of filesystem freeze states
>     #
> 
> The parser should flag such nonsense.
> 

Done

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/11] qapi: fix schema symbol sections
  2016-10-26 13:30   ` Markus Armbruster
@ 2016-11-04 12:11     ` Marc-André Lureau
  0 siblings, 0 replies; 29+ messages in thread
From: Marc-André Lureau @ 2016-11-04 12:11 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Marc-André Lureau, qemu-devel

Hi

----- Original Message -----
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> 
> > According to documentation, there needs to be '##' to start a symbol
> 
> Suggest to be explicit, and say "According to docs/qapi-code-gen.txt".
> 

ok

> > section, that's also what the documentation parser expects.
> 
> Does the doc parser complain when its expectation isn't met?  I haven't
> reviewed it, yet...

I have improved the error reporting in the next iteration, it will raise an error in this case and others.

> 
> In my opinion, qapi-code-gen.txt should demand everything the doc parser
> needs (it may demand more), and the doc parser should complain about
> everything qapi-code-gen.txt demands and the schema doesn't provide.
> 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> The patch fixes all missing '##' at the beginning of definition comment
> blocks.  Good.
> 
> qapi-code-gen.txt also demands '##' at the end.  Does the parser rely on
> it?  Offenders:

fixed

> 
> diff --git a/qapi-schema.json b/qapi-schema.json
> index fc732cb..0cc9ee6 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -780,6 +780,7 @@
>  # command.
>  #
>  # Since: 2.5
> +##
>  { 'command': 'migrate-start-postcopy' }
>  
>  ##
> @@ -4429,7 +4430,7 @@
>  #
>  # @DIMM: memory slot
>  # @CPU: logical CPU slot (since 2.7)
> -#
> +##
>  { 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
>  
>  ##
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template
  2016-10-27 14:55   ` Markus Armbruster
@ 2016-11-04 13:27     ` Marc-André Lureau
  2016-11-08 14:04       ` Markus Armbruster
  0 siblings, 1 reply; 29+ messages in thread
From: Marc-André Lureau @ 2016-11-04 13:27 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Marc-André Lureau, qemu-devel

Hi

----- Original Message -----
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> 
> > The qapi2texi scripts uses a template for the texi file. Since we are
> > going to generate the documentation in multiple formats, move qmp-intro
> > to qemu-qapi template. (it would be nice to write something similar for
> > qemu-ga, but this is left for a future patch)
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> I'm not exactly a Texinfo expert, but I can compare to the Texinfo
> manual.
> 
> Lots of comments below.  Please don't let them discourage you!  Your two
> manuals are pretty slick already, and a most welcome step forward.

I based it on some older version of qemu-doc.texi. Many of your remarks are also valid for it.

> 
> > ---
> >  docs/qemu-ga-qapi.template.texi |  58 ++++++++++++++++
> >  docs/qemu-qapi.template.texi    | 148
> >  ++++++++++++++++++++++++++++++++++++++++
> >  docs/qmp-intro.txt              |  87 -----------------------
> >  3 files changed, 206 insertions(+), 87 deletions(-)
> >  create mode 100644 docs/qemu-ga-qapi.template.texi
> >  create mode 100644 docs/qemu-qapi.template.texi
> >  delete mode 100644 docs/qmp-intro.txt
> >
> > diff --git a/docs/qemu-ga-qapi.template.texi
> > b/docs/qemu-ga-qapi.template.texi
> > new file mode 100644
> > index 0000000..3ddbf56
> > --- /dev/null
> > +++ b/docs/qemu-ga-qapi.template.texi
> > @@ -0,0 +1,58 @@
> > +\input texinfo
> 
> The Texinfo manual uses
> 
>    \input texinfo   @c -*-texinfo-*-
> 
> but my version of Emacs seems to be fine without this.

Shouldn't be necessary imho (in general, I am not fond of modeline unless necessary)
> 
> > +@setfilename qemu-ga-qapi
> 
> Not wrong, but the Texinfo manual recommends to replace the extension
> (here: .texi) with .info, so let's do that:
> 
>    @setfilename qemu-ga-qapi.info

ok

> 
> > +@documentlanguage en
> 
> This overrides the default en_US to just en.  Is that what we want?

let's keep the default

> 
> > +@exampleindent 0
> > +@paragraphindent 0
> > +
> > +@settitle QEMU-GA QAPI Reference Manual
> 
> What is "QAPI", and why would the reader care?  I think the manual is
> about the QEMU Guest Agent Protocol.  The fact that its implementation
> relies on QAPI is immaterial here.  What about:
> 
>    @settitle QEMU Guest Agent Protocol Reference
> 
> But then the filenames are off.  Rename to qemu-ga-ref.*.

fine by me

> 
> > +
> 
> I think we need a copyright note.  Something like:
> 
>    @copying
>    This is the QEMU Guest Agent QAPI reference manual.
> 
>    Copyright @copyright{} 2016 The QEMU Project developers
> 
>    @quotation
>    Permission is granted to ...
>    @end quotation
>    @end copying
> 
> > +@ifinfo
> 
>    @dircategory QEMU

ok

> Should be added to qemu-doc.texi as well.

I'll leave that for another series

> 
> > +@direntry
> > +* QEMU-GA-QAPI: (qemu-doc).    QEMU-GA QAPI Reference Manual
> 
> Pasto: (qemu-doc)
> 
> The description should start at column 32, not 31.
> 
> If we retitle and rename as suggested, this becomes:
> 
>    * QEMU-GA-Ref: (qemu-ga-ref):   QEMU Guest Agent Protocol Reference
> 

ok

> > +@end direntry
> > +@end ifinfo
> 
> Are you sure we need @ifinfo?

Probably not, but it looks more explicit to me that this part is only for .info

> > +
> > +@iftex
> > +@titlepage
> > +@sp 7
> > +@center @titlefont{{QEMU Guest Agent {version}}}
> 
> {version} seems to get replaced by qapi2texi.py.  Worth a comment.
> 

ok

> > +@sp 1
> > +@center @titlefont{{QAPI Reference Manual}}
> 
> Protocol Reference Manual
> 
> > +@sp 3
> 
> Isn't @sp right before @end titlepage redundant?

ok

> 
> We need to include the copyright notice:
> 
>    @page
>    @vskip 0pt plus 1filll
>    @insertcopying
> 

ok

> > +@end titlepage
> > +@end iftex
> 
> Are you sure we need @iftex?

Same as qemu-doc.texi, I suppose it looks better with info.

> 
> We can also let Texinfo do the spacing, like this:
> 
>    @titlepage
>    @title QEMU Guest Agent {version}
>    @subtitle Protocol Reference Manual
>    @page
>    @vskip 0pt plus 1filll
>    @insertcopying
>    @end titlepage
> 

That ends up with a different results than qapi-doc, but I also prefer it

> The @title isn't really the title, though.  Could reshuffle things a
> bit, e.g.
> 
>    @title QEMU Guest Agent Protocol Reference Manual
>    @subtitle for QEMU {version}
> 
> Your choice.

Yep, looks good, altough doesn't fit on a single line, I am dropping the leading QEMU

> The examples in Texinfo manual Appendix C "Sample Texinfo Files" have
> @contents right here, after the title page.
> 

Ok

> > +
> > +@ifnottex
> > +@node Top
> > +@top
> 
>    @top QEMU Guest Agent QAPI reference
> 
> > +
> > +This is the QEMU Guest Agent QAPI reference for QEMU {version}.
> 
> "protocol reference manual for"
> 
> According to the Texinfo manual's examples, the @end ifnottex goes
> here...

Removing it, now redundant with @copying text

> 
> > +
> > +@menu
> > +* API Reference::
> > +* Commands and Events Index::
> > +* Data Types Index::
> > +@end menu
> > +
> > +@end ifnottex
> 
> ... and not here.
> 

ok

> > +
> > +@contents
> 
> Suggest to move this up, as mentioned above.
> 

ok

> > +
> > +@node API Reference
> > +@chapter API Reference
> > +
> > +@c man begin DESCRIPTION
> 
> What does this @c man magic do?  Suggest to explain in a comment.

It's for texi2pod, I'll add a comment
> 
> > +{qapi}
> 
> This seems to get replaced with the generated reference documentation by
> qapi2texi.py.  Worth a comment.

ok

> 
> > +@c man end
> > +
> > +@c man begin SEEALSO
> > +The HTML documentation of QEMU for more precise information.
> > +@c man end
> 
> More @c man magic.
> 
> > +
> > +@node Commands and Events Index
> > +@unnumbered Commands and Events Index
> > +@printindex fn
> 
> Blank line here, please.
> 

ok

> > +@node Data Types Index
> > +@unnumbered Data Types Index
> > +@printindex tp
> 
> And here.

ok

> 
> > +@bye
> > diff --git a/docs/qemu-qapi.template.texi b/docs/qemu-qapi.template.texi
> > new file mode 100644
> > index 0000000..102c8d9
> > --- /dev/null
> > +++ b/docs/qemu-qapi.template.texi
> 
> The comments above largely apply; I won't repeat them.
> 
> > @@ -0,0 +1,148 @@
> > +\input texinfo
> > +@setfilename qemu-qapi
> > +@documentlanguage en
> > +@exampleindent 0
> > +@paragraphindent 0
> > +
> > +@settitle QEMU QAPI Reference Manual
> 
> Again, QAPI is detail; it's the QEMU QMP reference manual.  Except it
> has more than just QMP, because we choose to use qapi-schema.json for
> purely internal types in addition to QMP.
> 
> Options:
> 
> * Claim this is the QMP reference manual, include the internal types
>   anyway.
> 
> * Filter out the internal types automatically, similar to
>   qmp-introspect.py.
> 
> * Filter out the internal types manually, by annotating them in the
>   schema.  Feels error-prone.
> 
> * Split the QAPI schema.
> 
> * Reflect the curious mix of QMP protocol and internal data type
>   reference in the title.
> 
> We don't need a perfect solution to commit this, but an understanding of
> what we want to do would be nice.

What are the internal types? How is it filtered?

> 
> > +
> > +@ifinfo
> > +@direntry
> > +* QEMU: (qemu-doc).    QEMU QAPI Reference Manual
> > +@end direntry
> > +@end ifinfo
> > +
> > +@iftex
> > +@titlepage
> > +@sp 7
> > +@center @titlefont{{QEMU Emulator {version}}}
> > +@sp 1
> > +@center @titlefont{{QAPI Reference Manual}}
> > +@sp 3
> > +@end titlepage
> > +@end iftex
> > +
> > +@ifnottex
> > +@node Top
> > +@top
> > +
> > +This is the QMP QAPI reference for QEMU {version}.
> > +
> > +@menu
> > +* Introduction::
> > +* API Reference::
> > +* Commands and Events Index::
> > +* Data Types Index::
> > +@end menu
> > +
> > +@end ifnottex
> > +
> > +@contents
> > +
> > +@node Introduction
> > +@chapter Introduction
> > +
> > +The QEMU Machine Protocol (@acronym{{QMP}}) allows applications to
> > +operate a QEMU instance.
> > +
> > +QMP is @uref{{http://www.json.org, JSON}} based and features the
> > +following:
> > +
> > +@itemize @minus
> 
> @bullet is more common.  Matter of taste.

ok

> 
> > +@item
> > +Lightweight, text-based, easy to parse data format
> 
> Suggest "plain text" instead of "text-based".

ok

> 
> JSON is "easy to parse" until you hit the potholes in its specification.
> See "Parsing JSON is a Minefield" <http://seriot.ch/parsing_json.html>.
> 
>    QMP provides the following features:
> 
>    @itemize @bullet
>    @item
>    Simple @uref{{http://www.json.org, JSON}} syntax
> 
> > +@item
> > +Asynchronous messages support (ie. events)
> 
> i.e.
> 
> But I'd say
> 
>    @item
>    Synchronous commands and replies
>    @item
>    Asynchronous messages ("events")
> 
> > +@item
> > +Capabilities Negotiation
> 
> I'd add
> 
>    @item
>    Introspection
> 
> > +@end itemize
> > +
> > +For detailed information on QEMU Machine Protocol, the specification
> > +is in @file{{qmp-spec.txt}}.
> > +
> > +@section Usage
> > +
> > +You can use the @option{{-qmp}} option to enable QMP. For example, the
> > +following makes QMP available on localhost port 4444:
> > +
> > +@example
> > +$ qemu [...] -qmp tcp:localhost:4444,server,nowait
> > +@end example
> > +
> > +However, for more flexibility and to make use of more options, the
> > +@option{{-mon}} command-line option should be used. For instance, the
> > +following example creates one HMP instance (human monitor) on stdio
> > +and one QMP instance on localhost port 4444:
> 
> This sounds a bit like we don't want people to use -qmp.  What about
> 
>    However, for more flexibility and to make use of more options, the
>    @option{{-mon}} command-line option should be used. For instance, the
>    following example creates one HMP instance (human monitor) on stdio
>    and one QMP instance on localhost port 4444:
>    
> 
> > +
> > +@example
> > +$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
> > +             -chardev
> > socket,id=mon1,host=localhost,port=4444,server,nowait \
> > +             -mon chardev=mon1,mode=control,pretty=on
> > +@end example
> 
> Not sure we want to drag in HMP here.
> 
> > +
> > +Please, refer to QEMU's manpage for more information.
> 
> Drop the comma.
> 
> Hrmmm, I just realized this is merely moved from qmp-intro.txt.  I guess
> I should read your commit message before your patch %-)
> 
> I'm not sure a *reference* manual is a good home for an *introduction*
> to use.  It's certainly not where I'd look first.
> 
> We can decide this isn't a reference manual after all, and change title,
> file name and so forth accordingly.
> 
> Or we can stick to the reference manual idea, and include qmp-intro.txt
> by reference.

Imho it would be nice to include qmp-intro in the document, has there are more chances it gets read, be it online in html/pdf for, or with the info/man pages.

Any suggestion for the the naming? (tbh, I don't mind it being called reference manual or not, even if it includes that text).

thanks

> 
> > +
> > +@section Simple testing
> > +
> > +To manually test QMP one can connect with telnet and issue commands by
> > +hand:
> > +
> > +@example
> > +$ telnet localhost 4444
> > +Trying 127.0.0.1...
> > +Connected to localhost.
> > +Escape character is '^]'.
> > +@{{
> > +    "QMP": @{{
> > +        "version": @{{
> > +            "qemu": @{{
> > +                "micro": 50,
> > +                "minor": 6,
> > +                "major": 1
> > +            @}},
> > +            "package": ""
> > +        @}},
> > +        "capabilities": [
> > +        ]
> > +    @}}
> > +@}}
> > +
> > +@{{ "execute": "qmp_capabilities" @}}
> > +@{{
> > +    "return": @{{
> > +    @}}
> > +@}}
> > +
> > +@{{ "execute": "query-status" @}}
> > +@{{
> > +    "return": @{{
> > +        "status": "prelaunch",
> > +        "singlestep": false,
> > +        "running": false
> > +    @}}
> > +@}}
> > +@end example
> > +
> > +@section Wiki
> > +
> > +Please refer to the @uref{{http://wiki.qemu-project.org/QMP, QMP QEMU
> > + wiki page}} for more details on QMP.
> > +
> > +@node API Reference
> > +@chapter API Reference
> > +
> > +@c man begin DESCRIPTION
> > +{qapi}
> > +@c man end
> > +
> > +@c man begin SEEALSO
> > +The HTML documentation of QEMU for more precise information.
> > +@c man end
> > +
> > +@node Commands and Events Index
> > +@unnumbered Commands and Events Index
> > +@printindex fn
> > +@node Data Types Index
> > +@unnumbered Data Types Index
> > +@printindex tp
> > +@bye
> > diff --git a/docs/qmp-intro.txt b/docs/qmp-intro.txt
> > deleted file mode 100644
> > index f6a3a03..0000000
> > --- a/docs/qmp-intro.txt
> > +++ /dev/null
> > @@ -1,87 +0,0 @@
> > -                          QEMU Machine Protocol
> > -                          =====================
> > -
> > -Introduction
> > -------------
> > -
> > -The QEMU Machine Protocol (QMP) allows applications to operate a
> > -QEMU instance.
> > -
> > -QMP is JSON[1] based and features the following:
> > -
> > -- Lightweight, text-based, easy to parse data format
> > -- Asynchronous messages support (ie. events)
> > -- Capabilities Negotiation
> > -
> > -For detailed information on QMP's usage, please, refer to the following
> > files:
> > -
> > -o qmp-spec.txt      QEMU Machine Protocol current specification
> > -o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
> > -o qmp-events.txt    List of available asynchronous events
> > -
> > -[1] http://www.json.org
> > -
> > -Usage
> > ------
> > -
> > -You can use the -qmp option to enable QMP. For example, the following
> > -makes QMP available on localhost port 4444:
> > -
> > -$ qemu [...] -qmp tcp:localhost:4444,server,nowait
> > -
> > -However, for more flexibility and to make use of more options, the -mon
> > -command-line option should be used. For instance, the following example
> > -creates one HMP instance (human monitor) on stdio and one QMP instance
> > -on localhost port 4444:
> > -
> > -$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
> > -             -chardev
> > socket,id=mon1,host=localhost,port=4444,server,nowait \
> > -             -mon chardev=mon1,mode=control,pretty=on
> > -
> > -Please, refer to QEMU's manpage for more information.
> > -
> > -Simple Testing
> > ---------------
> > -
> > -To manually test QMP one can connect with telnet and issue commands by
> > hand:
> > -
> > -$ telnet localhost 4444
> > -Trying 127.0.0.1...
> > -Connected to localhost.
> > -Escape character is '^]'.
> > -{
> > -    "QMP": {
> > -        "version": {
> > -            "qemu": {
> > -                "micro": 50,
> > -                "minor": 6,
> > -                "major": 1
> > -            },
> > -            "package": ""
> > -        },
> > -        "capabilities": [
> > -        ]
> > -    }
> > -}
> > -
> > -{ "execute": "qmp_capabilities" }
> > -{
> > -    "return": {
> > -    }
> > -}
> > -
> > -{ "execute": "query-status" }
> > -{
> > -    "return": {
> > -        "status": "prelaunch",
> > -        "singlestep": false,
> > -        "running": false
> > -    }
> > -}
> > -
> > -Please, refer to the qapi-schema.json file for a complete command
> > reference.
> > -
> > -QMP wiki page
> > --------------
> > -
> > -http://wiki.qemu-project.org/QMP
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template
  2016-11-04 13:27     ` Marc-André Lureau
@ 2016-11-08 14:04       ` Markus Armbruster
  0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2016-11-08 14:04 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: Marc-André Lureau, qemu-devel

Marc-André Lureau <mlureau@redhat.com> writes:

> Hi
>
> ----- Original Message -----
>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>> 
>> > The qapi2texi scripts uses a template for the texi file. Since we are
>> > going to generate the documentation in multiple formats, move qmp-intro
>> > to qemu-qapi template. (it would be nice to write something similar for
>> > qemu-ga, but this is left for a future patch)
>> >
>> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> 
>> I'm not exactly a Texinfo expert, but I can compare to the Texinfo
>> manual.
>> 
>> Lots of comments below.  Please don't let them discourage you!  Your two
>> manuals are pretty slick already, and a most welcome step forward.
>
> I based it on some older version of qemu-doc.texi. Many of your remarks are also valid for it.

Let's touch it up once this series is in.

>> > ---
>> >  docs/qemu-ga-qapi.template.texi |  58 ++++++++++++++++
>> >  docs/qemu-qapi.template.texi    | 148
>> >  ++++++++++++++++++++++++++++++++++++++++
>> >  docs/qmp-intro.txt              |  87 -----------------------
>> >  3 files changed, 206 insertions(+), 87 deletions(-)
>> >  create mode 100644 docs/qemu-ga-qapi.template.texi
>> >  create mode 100644 docs/qemu-qapi.template.texi
>> >  delete mode 100644 docs/qmp-intro.txt
>> >
>> > diff --git a/docs/qemu-ga-qapi.template.texi
>> > b/docs/qemu-ga-qapi.template.texi
>> > new file mode 100644
>> > index 0000000..3ddbf56
>> > --- /dev/null
>> > +++ b/docs/qemu-ga-qapi.template.texi
>> > @@ -0,0 +1,58 @@
>> > +\input texinfo
>> 
>> The Texinfo manual uses
>> 
>>    \input texinfo   @c -*-texinfo-*-
>> 
>> but my version of Emacs seems to be fine without this.
>
> Shouldn't be necessary imho (in general, I am not fond of modeline unless necessary)
>> 
>> > +@setfilename qemu-ga-qapi
>> 
>> Not wrong, but the Texinfo manual recommends to replace the extension
>> (here: .texi) with .info, so let's do that:
>> 
>>    @setfilename qemu-ga-qapi.info
>
> ok
>
>> 
>> > +@documentlanguage en
>> 
>> This overrides the default en_US to just en.  Is that what we want?
>
> let's keep the default
>
>> 
>> > +@exampleindent 0
>> > +@paragraphindent 0
>> > +
>> > +@settitle QEMU-GA QAPI Reference Manual
>> 
>> What is "QAPI", and why would the reader care?  I think the manual is
>> about the QEMU Guest Agent Protocol.  The fact that its implementation
>> relies on QAPI is immaterial here.  What about:
>> 
>>    @settitle QEMU Guest Agent Protocol Reference
>> 
>> But then the filenames are off.  Rename to qemu-ga-ref.*.
>
> fine by me
>
>> 
>> > +
>> 
>> I think we need a copyright note.  Something like:
>> 
>>    @copying
>>    This is the QEMU Guest Agent QAPI reference manual.
>> 
>>    Copyright @copyright{} 2016 The QEMU Project developers
>> 
>>    @quotation
>>    Permission is granted to ...
>>    @end quotation
>>    @end copying
>> 
>> > +@ifinfo
>> 
>>    @dircategory QEMU
>
> ok
>
>> Should be added to qemu-doc.texi as well.
>
> I'll leave that for another series
>
>> > +@direntry
>> > +* QEMU-GA-QAPI: (qemu-doc).    QEMU-GA QAPI Reference Manual
>> 
>> Pasto: (qemu-doc)
>> 
>> The description should start at column 32, not 31.
>> 
>> If we retitle and rename as suggested, this becomes:
>> 
>>    * QEMU-GA-Ref: (qemu-ga-ref):   QEMU Guest Agent Protocol Reference
>> 
>
> ok
>
>> > +@end direntry
>> > +@end ifinfo
>> 
>> Are you sure we need @ifinfo?
>
> Probably not, but it looks more explicit to me that this part is only for .info

I don't think redundant conditionals buy us anything.

>> > +
>> > +@iftex
>> > +@titlepage
>> > +@sp 7
>> > +@center @titlefont{{QEMU Guest Agent {version}}}
>> 
>> {version} seems to get replaced by qapi2texi.py.  Worth a comment.
>> 
>
> ok

Peeking at your v3, I see you found a better solution :)

>> > +@sp 1
>> > +@center @titlefont{{QAPI Reference Manual}}
>> 
>> Protocol Reference Manual
>> 
>> > +@sp 3
>> 
>> Isn't @sp right before @end titlepage redundant?
>
> ok
>
>> 
>> We need to include the copyright notice:
>> 
>>    @page
>>    @vskip 0pt plus 1filll
>>    @insertcopying
>> 
>
> ok
>
>> > +@end titlepage
>> > +@end iftex
>> 
>> Are you sure we need @iftex?
>
> Same as qemu-doc.texi, I suppose it looks better with info.
>
>> 
>> We can also let Texinfo do the spacing, like this:
>> 
>>    @titlepage
>>    @title QEMU Guest Agent {version}
>>    @subtitle Protocol Reference Manual
>>    @page
>>    @vskip 0pt plus 1filll
>>    @insertcopying
>>    @end titlepage
>> 
>
> That ends up with a different results than qapi-doc, but I also prefer it
>
>> The @title isn't really the title, though.  Could reshuffle things a
>> bit, e.g.
>> 
>>    @title QEMU Guest Agent Protocol Reference Manual
>>    @subtitle for QEMU {version}
>> 
>> Your choice.
>
> Yep, looks good, altough doesn't fit on a single line, I am dropping the leading QEMU
>
>> The examples in Texinfo manual Appendix C "Sample Texinfo Files" have
>> @contents right here, after the title page.
>> 
>
> Ok
>
>> > +
>> > +@ifnottex
>> > +@node Top
>> > +@top
>> 
>>    @top QEMU Guest Agent QAPI reference
>> 
>> > +
>> > +This is the QEMU Guest Agent QAPI reference for QEMU {version}.
>> 
>> "protocol reference manual for"
>> 
>> According to the Texinfo manual's examples, the @end ifnottex goes
>> here...
>
> Removing it, now redundant with @copying text
>
>> 
>> > +
>> > +@menu
>> > +* API Reference::
>> > +* Commands and Events Index::
>> > +* Data Types Index::
>> > +@end menu
>> > +
>> > +@end ifnottex
>> 
>> ... and not here.
>> 
>
> ok
>
>> > +
>> > +@contents
>> 
>> Suggest to move this up, as mentioned above.
>> 
>
> ok
>
>> > +
>> > +@node API Reference
>> > +@chapter API Reference
>> > +
>> > +@c man begin DESCRIPTION
>> 
>> What does this @c man magic do?  Suggest to explain in a comment.
>
> It's for texi2pod, I'll add a comment
>> 
>> > +{qapi}
>> 
>> This seems to get replaced with the generated reference documentation by
>> qapi2texi.py.  Worth a comment.
>
> ok
>
>> 
>> > +@c man end
>> > +
>> > +@c man begin SEEALSO
>> > +The HTML documentation of QEMU for more precise information.
>> > +@c man end
>> 
>> More @c man magic.
>> 
>> > +
>> > +@node Commands and Events Index
>> > +@unnumbered Commands and Events Index
>> > +@printindex fn
>> 
>> Blank line here, please.
>> 
>
> ok
>
>> > +@node Data Types Index
>> > +@unnumbered Data Types Index
>> > +@printindex tp
>> 
>> And here.
>
> ok
>
>> 
>> > +@bye
>> > diff --git a/docs/qemu-qapi.template.texi b/docs/qemu-qapi.template.texi
>> > new file mode 100644
>> > index 0000000..102c8d9
>> > --- /dev/null
>> > +++ b/docs/qemu-qapi.template.texi
>> 
>> The comments above largely apply; I won't repeat them.
>> 
>> > @@ -0,0 +1,148 @@
>> > +\input texinfo
>> > +@setfilename qemu-qapi
>> > +@documentlanguage en
>> > +@exampleindent 0
>> > +@paragraphindent 0
>> > +
>> > +@settitle QEMU QAPI Reference Manual
>> 
>> Again, QAPI is detail; it's the QEMU QMP reference manual.  Except it
>> has more than just QMP, because we choose to use qapi-schema.json for
>> purely internal types in addition to QMP.
>> 
>> Options:
>> 
>> * Claim this is the QMP reference manual, include the internal types
>>   anyway.
>> 
>> * Filter out the internal types automatically, similar to
>>   qmp-introspect.py.
>> 
>> * Filter out the internal types manually, by annotating them in the
>>   schema.  Feels error-prone.
>> 
>> * Split the QAPI schema.
>> 
>> * Reflect the curious mix of QMP protocol and internal data type
>>   reference in the title.
>> 
>> We don't need a perfect solution to commit this, but an understanding of
>> what we want to do would be nice.
>
> What are the internal types? How is it filtered?

We define several types in the QAPI schema that are used only
internally.  Useful trick to see what's external:

    $ python -B scripts/qapi-introspect.py -cu -p scratch- qapi-schema.json

This generates scratch-qmp-introspect.c describing the external QMP
interface with unmasked type names (-u).  Anything not mentioned there
is not externally visible.

To see how qapi-introspect.py finds the externally visible part of the
schema, search it for _use_type.

>> > +
>> > +@ifinfo
>> > +@direntry
>> > +* QEMU: (qemu-doc).    QEMU QAPI Reference Manual
>> > +@end direntry
>> > +@end ifinfo
>> > +
>> > +@iftex
>> > +@titlepage
>> > +@sp 7
>> > +@center @titlefont{{QEMU Emulator {version}}}
>> > +@sp 1
>> > +@center @titlefont{{QAPI Reference Manual}}
>> > +@sp 3
>> > +@end titlepage
>> > +@end iftex
>> > +
>> > +@ifnottex
>> > +@node Top
>> > +@top
>> > +
>> > +This is the QMP QAPI reference for QEMU {version}.
>> > +
>> > +@menu
>> > +* Introduction::
>> > +* API Reference::
>> > +* Commands and Events Index::
>> > +* Data Types Index::
>> > +@end menu
>> > +
>> > +@end ifnottex
>> > +
>> > +@contents
>> > +
>> > +@node Introduction
>> > +@chapter Introduction
>> > +
>> > +The QEMU Machine Protocol (@acronym{{QMP}}) allows applications to
>> > +operate a QEMU instance.
>> > +
>> > +QMP is @uref{{http://www.json.org, JSON}} based and features the
>> > +following:
>> > +
>> > +@itemize @minus
>> 
>> @bullet is more common.  Matter of taste.
>
> ok
>
>> 
>> > +@item
>> > +Lightweight, text-based, easy to parse data format
>> 
>> Suggest "plain text" instead of "text-based".
>
> ok
>
>> 
>> JSON is "easy to parse" until you hit the potholes in its specification.
>> See "Parsing JSON is a Minefield" <http://seriot.ch/parsing_json.html>.
>> 
>>    QMP provides the following features:
>> 
>>    @itemize @bullet
>>    @item
>>    Simple @uref{{http://www.json.org, JSON}} syntax
>> 
>> > +@item
>> > +Asynchronous messages support (ie. events)
>> 
>> i.e.
>> 
>> But I'd say
>> 
>>    @item
>>    Synchronous commands and replies
>>    @item
>>    Asynchronous messages ("events")
>> 
>> > +@item
>> > +Capabilities Negotiation
>> 
>> I'd add
>> 
>>    @item
>>    Introspection
>> 
>> > +@end itemize
>> > +
>> > +For detailed information on QEMU Machine Protocol, the specification
>> > +is in @file{{qmp-spec.txt}}.
>> > +
>> > +@section Usage
>> > +
>> > +You can use the @option{{-qmp}} option to enable QMP. For example, the
>> > +following makes QMP available on localhost port 4444:
>> > +
>> > +@example
>> > +$ qemu [...] -qmp tcp:localhost:4444,server,nowait
>> > +@end example
>> > +
>> > +However, for more flexibility and to make use of more options, the
>> > +@option{{-mon}} command-line option should be used. For instance, the
>> > +following example creates one HMP instance (human monitor) on stdio
>> > +and one QMP instance on localhost port 4444:
>> 
>> This sounds a bit like we don't want people to use -qmp.  What about
>> 
>>    However, for more flexibility and to make use of more options, the
>>    @option{{-mon}} command-line option should be used. For instance, the
>>    following example creates one HMP instance (human monitor) on stdio
>>    and one QMP instance on localhost port 4444:
>>    
>> 
>> > +
>> > +@example
>> > +$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
>> > +             -chardev
>> > socket,id=mon1,host=localhost,port=4444,server,nowait \
>> > +             -mon chardev=mon1,mode=control,pretty=on
>> > +@end example
>> 
>> Not sure we want to drag in HMP here.
>> 
>> > +
>> > +Please, refer to QEMU's manpage for more information.
>> 
>> Drop the comma.
>> 
>> Hrmmm, I just realized this is merely moved from qmp-intro.txt.  I guess
>> I should read your commit message before your patch %-)
>> 
>> I'm not sure a *reference* manual is a good home for an *introduction*
>> to use.  It's certainly not where I'd look first.
>> 
>> We can decide this isn't a reference manual after all, and change title,
>> file name and so forth accordingly.
>> 
>> Or we can stick to the reference manual idea, and include qmp-intro.txt
>> by reference.
>
> Imho it would be nice to include qmp-intro in the document, has there are more chances it gets read, be it online in html/pdf for, or with the info/man pages.

Replacing qmp-commands.txt by a QMP reference manual is a
straightforward task: we don't have to worry about scope or structure,
only about not losing valuable contents.

But as soon you draw in qmp-intro.txt, we're making a QMP manual.
That's a more complex task, posing additional questions.  For starters,
why is qmp-spec.txt not part of it?  Should the QGA manual get similar
contents?

I'm not saying that task should not be tackled.  But let's control this
series' scope, and make just a QMP reference manual.  We can expand it
into a QMP manual with a reference part later if we like.

> Any suggestion for the the naming? (tbh, I don't mind it being called reference manual or not, even if it includes that text).

We could call it "QMP User Manual".

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2016-11-08 14:04 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-09-25 18:18 [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Marc-André Lureau
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 01/11] qapi: add qapi2texi script Marc-André Lureau
2016-10-28 16:44   ` Markus Armbruster
2016-10-28 19:56     ` Eric Blake
2016-11-02  9:25     ` Marc-André Lureau
2016-11-03 13:46       ` Markus Armbruster
2016-11-03 16:24         ` Marc-André Lureau
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 02/11] qapi: fix schema symbol sections Marc-André Lureau
2016-10-26 13:30   ` Markus Armbruster
2016-11-04 12:11     ` Marc-André Lureau
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 03/11] qapi: fix missing symbol @prefix Marc-André Lureau
2016-10-26 13:37   ` Markus Armbruster
2016-11-04 12:05     ` Marc-André Lureau
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 04/11] qapi: fix @ACPI sections Marc-André Lureau
2016-10-26 13:38   ` Markus Armbruster
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 05/11] docs: add qapi texi template Marc-André Lureau
2016-10-27 14:55   ` Markus Armbruster
2016-11-04 13:27     ` Marc-André Lureau
2016-11-08 14:04       ` Markus Armbruster
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 06/11] build-sys: add qapi doc generation targets Marc-André Lureau
2016-10-27 16:16   ` Markus Armbruster
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 07/11] (SQUASHED) qmp-commands docs move to schema Marc-André Lureau
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 08/11] qapi: add some sections in docs and fix Marc-André Lureau
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 09/11] qga: fix guest-get-memory-block-info doc Marc-André Lureau
2016-10-27 16:58   ` Markus Armbruster
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 10/11] texi2pod: learn quotation, deftp and deftypefn Marc-André Lureau
2016-09-25 18:18 ` [Qemu-devel] [PATCH v2 11/11] build-sys: make and install the generated schema docs Marc-André Lureau
2016-10-26  9:36 ` [Qemu-devel] [PATCH v2 00/11] qapi doc generation (whole version, squashed) Markus Armbruster
2016-11-02 12:11   ` Markus Armbruster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).