diff mbox

RFC: Full introspection support for QMP (with draft patch)

Message ID 20130614095244.GA24720@t430s.nay.redhat.com
State New
Headers show

Commit Message

Amos Kong June 14, 2013, 9:52 a.m. UTC
On Fri, Jun 07, 2013 at 06:17:26PM +0800, Amos Kong wrote:
> On Fri, Jun 07, 2013 at 06:12:30PM +0800, Amos Kong wrote:
> > Sent out a draft patch in the end of this week. It doesn't support:
> > * output all stuffs in one shot.
> > * introspect event
> > * provide metadata date
> > 
> > How can we define a dynamic dict in qmp-schema.json ?
> > 
> > Currently I just output the raw json dict by a string, Libvirt needs
> > parse two times, convert the string to json format.
> > 
> > qmp-schema.h: auto generated head file by qapi script
> > 
> > Attached some examples.


Hello all,

I defined a new type 'SchemaData', it contains 4 keys (type, name, data, returns)

| { 'type': 'SchemaData',
|   'data': { 'type': 'str', 'name': 'str', '*data': 'str', '*returns': 'str' } }
| 
| { 'command': 'query-qmp-schema', 'data': { '*type': 'str', '*name': 'str' },
|   'returns': ['SchemaData'] }

Then we can provice meaningful result to Libvirt. Currently I set a string
for SchemaData['data'].


I tried to define a dynamical dict for 'data', but it's failed. 

| { 'type': 'SchemaData',
|   'data': { 'type': 'str', 'name': 'str', '*data': '**', '*returns': 'str' } }  (Failed!!)


Does qapi support to define a dynamical dict, then I can convert dict string
and set to SchemaData['data'] ?



{ "execute": "query-qmp-schema"}
{
    "return": [
        {
            "name": "ErrorClass", 
            "type": "enum", 
            "data": "['GenericError', 'CommandNotFound', 'DeviceEncrypted', 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap']"
        }, 
        {
            "name": "SchemaData", 
            "type": "type", 
            "data": "{'*returns': 'str', 'type': 'str', 'name': 'str', '*data': 'str'}"
        }, 
        ......
        ......
        {
            "name": "query-qmp-schema", 
            "type": "command", 
            "returns": "['SchemaData']", 
            "data": "{'*name': 'str', '*type': 'str'}"
        }
    ]
}
/* convert qapi-schema.json to a string table */

struct qmp_schem {
const char *type;
const char *name;
const char *data;
const char *returns;
} qmp_schema_table[] = {
{"enum", "ErrorClass", "['GenericError', 'CommandNotFound', 'DeviceEncrypted', 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap']", ""},
{"command", "add_client", "{'*skipauth': 'bool', 'protocol': 'str', 'fdname': 'str', '*tls': 'bool'}", ""},
{"type", "NameInfo", "{'*name': 'str'}", ""},
{"command", "query-name", "", "NameInfo"},
{"type", "VersionInfo", "{'qemu': OrderedDict([('major', 'int'), ('minor', 'int'), ('micro', 'int')]), 'package': 'str'}", ""},
{"command", "query-version", "", "VersionInfo"},
{"type", "KvmInfo", "{'enabled': 'bool', 'present': 'bool'}", ""},
{"command", "query-kvm", "", "KvmInfo"},
{"enum", "RunState", "['debug', 'inmigrate', 'internal-error', 'io-error', 'paused', 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm', 'running', 'save-vm', 'shutdown', 'suspended', 'watchdog', 'guest-panicked']", ""},
{"type", "SnapshotInfo", "{'name': 'str', 'date-sec': 'int', 'vm-state-size': 'int', 'vm-clock-nsec': 'int', 'vm-clock-sec': 'int', 'date-nsec': 'int', 'id': 'str'}", ""},
{"type", "ImageInfo", "{'*snapshots': ['SnapshotInfo'], 'format': 'str', '*encrypted': 'bool', '*dirty-flag': 'bool', '*backing-filename-format': 'str', '*backing-filename': 'str', '*actual-size': 'int', 'filename': 'str', 'virtual-size': 'int', '*full-backing-filename': 'str', '*cluster-size': 'int'}", ""},
{"type", "ImageCheck", "{'check-errors': 'int', '*image-end-offset': 'int', '*corruptions-fixed': 'int', '*allocated-clusters': 'int', 'format': 'str', '*corruptions': 'int', '*total-clusters': 'int', 'filename': 'str', '*fragmented-clusters': 'int', '*leaks-fixed': 'int', '*compressed-clusters': 'int', '*leaks': 'int'}", ""},
{"type", "StatusInfo", "{'singlestep': 'bool', 'status': 'RunState', 'running': 'bool'}", ""},
{"command", "query-status", "", "StatusInfo"},
{"type", "UuidInfo", "{'UUID': 'str'}", ""},
{"command", "query-uuid", "", "UuidInfo"},
{"type", "ChardevInfo", "{'filename': 'str', 'label': 'str'}", ""},
{"command", "query-chardev", "", "['ChardevInfo']"},
{"enum", "DataFormat", "['utf8', 'base64']", ""},
{"command", "ringbuf-write", "{'device': 'str', '*format': 'DataFormat', 'data': 'str'}", ""},
{"command", "ringbuf-read", "{'device': 'str', '*format': 'DataFormat', 'size': 'int'}", "str"},
{"type", "CommandInfo", "{'name': 'str'}", ""},
{"command", "query-commands", "", "['CommandInfo']"},
{"type", "EventInfo", "{'name': 'str'}", ""},
{"command", "query-events", "", "['EventInfo']"},
{"type", "MigrationStats", "{'skipped': 'int', 'dirty-pages-rate': 'int', 'normal': 'int', 'transferred': 'int', 'duplicate': 'int', 'total': 'int', 'remaining': 'int', 'normal-bytes': 'int'}", ""},
{"type", "XBZRLECacheStats", "{'cache-miss': 'int', 'overflow': 'int', 'bytes': 'int', 'pages': 'int', 'cache-size': 'int'}", ""},
{"type", "MigrationInfo", "{'*ram': 'MigrationStats', '*total-time': 'int', '*downtime': 'int', '*expected-downtime': 'int', '*status': 'str', '*xbzrle-cache': 'XBZRLECacheStats', '*disk': 'MigrationStats'}", ""},
{"command", "query-migrate", "", "MigrationInfo"},
{"enum", "MigrationCapability", "['xbzrle']", ""},
{"type", "MigrationCapabilityStatus", "{'capability': 'MigrationCapability', 'state': 'bool'}", ""},
{"command", "migrate-set-capabilities", "{'capabilities': ['MigrationCapabilityStatus']}", ""},
{"command", "query-migrate-capabilities", "", "['MigrationCapabilityStatus']"},
{"type", "MouseInfo", "{'current': 'bool', 'index': 'int', 'name': 'str', 'absolute': 'bool'}", ""},
{"command", "query-mice", "", "['MouseInfo']"},
{"type", "CpuInfo", "{'halted': 'bool', '*npc': 'int', '*PC': 'int', '*pc': 'int', 'current': 'bool', 'thread_id': 'int', 'CPU': 'int', '*nip': 'int'}", ""},
{"command", "query-cpus", "", "['CpuInfo']"},
{"type", "BlockDeviceInfo", "{'bps_rd': 'int', 'backing_file_depth': 'int', 'encrypted': 'bool', '*backing_file': 'str', 'bps_wr': 'int', 'drv': 'str', 'bps': 'int', 'iops': 'int', 'file': 'str', 'iops_rd': 'int', 'encryption_key_missing': 'bool', 'ro': 'bool', 'iops_wr': 'int'}", ""},
{"enum", "BlockDeviceIoStatus", "['ok', 'failed', 'nospace']", ""},
{"type", "BlockDirtyInfo", "{'count': 'int', 'granularity': 'int'}", ""},
{"type", "BlockInfo", "{'*tray_open': 'bool', 'locked': 'bool', '*io-status': 'BlockDeviceIoStatus', '*dirty': 'BlockDirtyInfo', '*inserted': 'BlockDeviceInfo', 'removable': 'bool', 'device': 'str', 'type': 'str'}", ""},
{"command", "query-block", "", "['BlockInfo']"},
{"type", "BlockDeviceStats", "{'rd_operations': 'int', 'flush_total_time_ns': 'int', 'wr_highest_offset': 'int', 'rd_total_time_ns': 'int', 'rd_bytes': 'int', 'wr_total_time_ns': 'int', 'flush_operations': 'int', 'wr_operations': 'int', 'wr_bytes': 'int'}", ""},
{"type", "BlockStats", "{'stats': 'BlockDeviceStats', '*parent': 'BlockStats', '*device': 'str'}", ""},
{"command", "query-blockstats", "", "['BlockStats']"},
{"type", "VncClientInfo", "{'*sasl_username': 'str', 'host': 'str', 'service': 'str', 'family': 'str', '*x509_dname': 'str'}", ""},
{"type", "VncInfo", "{'*auth': 'str', 'enabled': 'bool', '*host': 'str', '*clients': ['VncClientInfo'], '*family': 'str', '*service': 'str'}", ""},
{"command", "query-vnc", "", "VncInfo"},
{"type", "SpiceChannel", "{'tls': 'bool', 'family': 'str', 'host': 'str', 'channel-type': 'int', 'connection-id': 'int', 'port': 'str', 'channel-id': 'int'}", ""},
{"enum", "SpiceQueryMouseMode", "['client', 'server', 'unknown']", ""},
{"type", "SpiceInfo", "{'migrated': 'bool', '*tls-port': 'int', '*port': 'int', '*auth': 'str', 'enabled': 'bool', '*host': 'str', '*channels': ['SpiceChannel'], 'mouse-mode': 'SpiceQueryMouseMode', '*compiled-version': 'str'}", ""},
{"command", "query-spice", "", "SpiceInfo"},
{"type", "BalloonInfo", "{'actual': 'int'}", ""},
{"command", "query-balloon", "", "BalloonInfo"},
{"type", "PciMemoryRange", "{'base': 'int', 'limit': 'int'}", ""},
{"type", "PciMemoryRegion", "{'bar': 'int', '*prefetch': 'bool', 'address': 'int', 'type': 'str', '*mem_type_64': 'bool', 'size': 'int'}", ""},
{"type", "PciBridgeInfo", "{'bus': OrderedDict([('number', 'int'), ('secondary', 'int'), ('subordinate', 'int'), ('io_range', 'PciMemoryRange'), ('memory_range', 'PciMemoryRange'), ('prefetchable_range', 'PciMemoryRange')]), '*devices': ['PciDeviceInfo']}", ""},
{"type", "PciDeviceInfo", "{'slot': 'int', 'function': 'int', 'bus': 'int', 'class_info': OrderedDict([('*desc', 'str'), ('class', 'int')]), '*pci_bridge': 'PciBridgeInfo', '*irq': 'int', 'regions': ['PciMemoryRegion'], 'qdev_id': 'str', 'id': OrderedDict([('device', 'int'), ('vendor', 'int')])}", ""},
{"type", "PciInfo", "{'bus': 'int', 'devices': ['PciDeviceInfo']}", ""},
{"command", "query-pci", "", "['PciInfo']"},
{"enum", "BlockdevOnError", "['report', 'ignore', 'enospc', 'stop']", ""},
{"enum", "MirrorSyncMode", "['top', 'full', 'none']", ""},
{"type", "BlockJobInfo", "{'busy': 'bool', 'speed': 'int', 'len': 'int', 'paused': 'bool', 'io-status': 'BlockDeviceIoStatus', 'offset': 'int', 'device': 'str', 'type': 'str'}", ""},
{"command", "query-block-jobs", "", "['BlockJobInfo']"},
{"command", "quit", "", ""},
{"command", "stop", "", ""},
{"command", "system_reset", "", ""},
{"command", "system_powerdown", "", ""},
{"command", "cpu", "{'index': 'int'}", ""},
{"command", "cpu-add", "{'id': 'int'}", ""},
{"command", "memsave", "{'filename': 'str', '*cpu-index': 'int', 'val': 'int', 'size': 'int'}", ""},
{"command", "pmemsave", "{'filename': 'str', 'val': 'int', 'size': 'int'}", ""},
{"command", "cont", "", ""},
{"command", "system_wakeup", "", ""},
{"command", "inject-nmi", "", ""},
{"command", "set_link", "{'name': 'str', 'up': 'bool'}", ""},
{"command", "block_passwd", "{'device': 'str', 'password': 'str'}", ""},
{"command", "balloon", "{'value': 'int'}", ""},
{"command", "block_resize", "{'device': 'str', 'size': 'int'}", ""},
{"enum", "NewImageMode", "['existing', 'absolute-paths']", ""},
{"type", "BlockdevSnapshot", "{'device': 'str', '*format': 'str', 'snapshot-file': 'str', '*mode': 'NewImageMode'}", ""},
{"union", "TransactionAction", "{'blockdev-snapshot-sync': 'BlockdevSnapshot'}", ""},
{"command", "transaction", "{'actions': ['TransactionAction']}", ""},
{"command", "blockdev-snapshot-sync", "{'device': 'str', '*format': 'str', 'snapshot-file': 'str', '*mode': 'NewImageMode'}", ""},
{"command", "human-monitor-command", "{'*cpu-index': 'int', 'command-line': 'str'}", "str"},
{"command", "block-commit", "{'device': 'str', 'top': 'str', '*base': 'str', '*speed': 'int'}", ""},
{"command", "drive-mirror", "{'*on-target-error': 'BlockdevOnError', '*buf-size': 'int', 'target': 'str', '*granularity': 'uint32', '*format': 'str', '*speed': 'int', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', 'device': 'str', '*on-source-error': 'BlockdevOnError'}", ""},
{"command", "migrate_cancel", "", ""},
{"command", "migrate_set_downtime", "{'value': 'number'}", ""},
{"command", "migrate_set_speed", "{'value': 'int'}", ""},
{"command", "migrate-set-cache-size", "{'value': 'int'}", ""},
{"command", "query-migrate-cache-size", "", "int"},
{"type", "ObjectPropertyInfo", "{'type': 'str', 'name': 'str'}", ""},
{"command", "qom-list", "{'path': 'str'}", "['ObjectPropertyInfo']"},
{"command", "qom-get", "{'path': 'str', 'property': 'str'}", "visitor"},
{"command", "qom-set", "{'path': 'str', 'property': 'str', 'value': 'visitor'}", ""},
{"command", "set_password", "{'password': 'str', 'protocol': 'str', '*connected': 'str'}", ""},
{"command", "expire_password", "{'protocol': 'str', 'time': 'str'}", ""},
{"command", "eject", "{'device': 'str', '*force': 'bool'}", ""},
{"command", "change-vnc-password", "{'password': 'str'}", ""},
{"command", "change", "{'device': 'str', 'target': 'str', '*arg': 'str'}", ""},
{"command", "block_set_io_throttle", "{'bps_rd': 'int', 'bps_wr': 'int', 'bps': 'int', 'iops': 'int', 'iops_rd': 'int', 'device': 'str', 'iops_wr': 'int'}", ""},
{"command", "block-stream", "{'device': 'str', '*on-error': 'BlockdevOnError', '*base': 'str', '*speed': 'int'}", ""},
{"command", "block-job-set-speed", "{'device': 'str', 'speed': 'int'}", ""},
{"command", "block-job-cancel", "{'device': 'str', '*force': 'bool'}", ""},
{"command", "block-job-pause", "{'device': 'str'}", ""},
{"command", "block-job-resume", "{'device': 'str'}", ""},
{"command", "block-job-complete", "{'device': 'str'}", ""},
{"type", "ObjectTypeInfo", "{'name': 'str'}", ""},
{"command", "qom-list-types", "{'*abstract': 'bool', '*implements': 'str'}", "['ObjectTypeInfo']"},
{"type", "DevicePropertyInfo", "{'type': 'str', 'name': 'str'}", ""},
{"command", "device-list-properties", "{'typename': 'str'}", "['DevicePropertyInfo']"},
{"command", "migrate", "{'*detach': 'bool', 'uri': 'str', '*inc': 'bool', '*blk': 'bool'}", ""},
{"command", "xen-save-devices-state", "{'filename': 'str'}", ""},
{"command", "xen-set-global-dirty-log", "{'enable': 'bool'}", ""},
{"command", "device_del", "{'id': 'str'}", ""},
{"command", "dump-guest-memory", "{'*length': 'int', 'paging': 'bool', 'protocol': 'str', '*begin': 'int'}", ""},
{"command", "netdev_add", "{'*props': '**', 'type': 'str', 'id': 'str'}", ""},
{"command", "netdev_del", "{'id': 'str'}", ""},
{"type", "NetdevNoneOptions", "{}", ""},
{"type", "NetLegacyNicOptions", "{'*macaddr': 'str', '*model': 'str', '*addr': 'str', '*vectors': 'uint32', '*netdev': 'str'}", ""},
{"type", "String", "{'str': 'str'}", ""},
{"type", "NetdevUserOptions", "{'*hostname': 'str', '*tftp': 'str', '*dhcpstart': 'str', '*guestfwd': ['String'], '*smbserver': 'str', '*hostfwd': ['String'], '*host': 'str', '*net': 'str', '*restrict': 'bool', '*dnssearch': ['String'], '*ip': 'str', '*dns': 'str', '*smb': 'str', '*bootfile': 'str'}", ""},
{"type", "NetdevTapOptions", "{'*vhostfd': 'str', '*script': 'str', '*helper': 'str', '*vhostfds': 'str', '*vnet_hdr': 'bool', '*downscript': 'str', '*queues': 'uint32', '*fd': 'str', '*vhostforce': 'bool', '*ifname': 'str', '*fds': 'str', '*vhost': 'bool', '*sndbuf': 'size'}", ""},
{"type", "NetdevSocketOptions", "{'*mcast': 'str', '*connect': 'str', '*fd': 'str', '*listen': 'str', '*udp': 'str', '*localaddr': 'str'}", ""},
{"type", "NetdevVdeOptions", "{'*mode': 'uint16', '*group': 'str', '*port': 'uint16', '*sock': 'str'}", ""},
{"type", "NetdevDumpOptions", "{'*len': 'size', '*file': 'str'}", ""},
{"type", "NetdevBridgeOptions", "{'*helper': 'str', '*br': 'str'}", ""},
{"type", "NetdevHubPortOptions", "{'hubid': 'int32'}", ""},
{"union", "NetClientOptions", "{'bridge': 'NetdevBridgeOptions', 'none': 'NetdevNoneOptions', 'tap': 'NetdevTapOptions', 'socket': 'NetdevSocketOptions', 'dump': 'NetdevDumpOptions', 'nic': 'NetLegacyNicOptions', 'vde': 'NetdevVdeOptions', 'user': 'NetdevUserOptions', 'hubport': 'NetdevHubPortOptions'}", ""},
{"type", "NetLegacy", "{'*id': 'str', '*vlan': 'int32', '*name': 'str', 'opts': 'NetClientOptions'}", ""},
{"type", "Netdev", "{'id': 'str', 'opts': 'NetClientOptions'}", ""},
{"type", "InetSocketAddress", "{'*ipv6': 'bool', 'host': 'str', '*to': 'uint16', 'port': 'str', '*ipv4': 'bool'}", ""},
{"type", "UnixSocketAddress", "{'path': 'str'}", ""},
{"union", "SocketAddress", "{'unix': 'UnixSocketAddress', 'fd': 'String', 'inet': 'InetSocketAddress'}", ""},
{"command", "getfd", "{'fdname': 'str'}", ""},
{"command", "closefd", "{'fdname': 'str'}", ""},
{"type", "MachineInfo", "{'*alias': 'str', '*is-default': 'bool', 'cpu-max': 'int', 'name': 'str'}", ""},
{"command", "query-machines", "", "['MachineInfo']"},
{"type", "CpuDefinitionInfo", "{'name': 'str'}", ""},
{"command", "query-cpu-definitions", "", "['CpuDefinitionInfo']"},
{"type", "AddfdInfo", "{'fdset-id': 'int', 'fd': 'int'}", ""},
{"command", "add-fd", "{'*opaque': 'str', '*fdset-id': 'int'}", "AddfdInfo"},
{"command", "remove-fd", "{'fdset-id': 'int', '*fd': 'int'}", ""},
{"type", "FdsetFdInfo", "{'*opaque': 'str', 'fd': 'int'}", ""},
{"type", "FdsetInfo", "{'fdset-id': 'int', 'fds': ['FdsetFdInfo']}", ""},
{"command", "query-fdsets", "", "['FdsetInfo']"},
{"enum", "TargetType", "['alpha', 'arm', 'cris', 'i386', 'lm32', 'm68k', 'microblazeel', 'microblaze', 'mips64el', 'mips64', 'mipsel', 'mips', 'moxie', 'or32', 'ppc64', 'ppcemb', 'ppc', 's390x', 'sh4eb', 'sh4', 'sparc64', 'sparc', 'unicore32', 'x86_64', 'xtensaeb', 'xtensa']", ""},
{"type", "TargetInfo", "{'arch': 'TargetType'}", ""},
{"command", "query-target", "", "TargetInfo"},
{"enum", "QKeyCode", "['shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl', 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right', 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'semicolon', 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', 'caps_lock', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply', 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', 'sysrq', 'kp_0', 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', 'kp_7', 'kp_8', 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end', 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again', 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut', 'lf', 'help', 'meta_l', 'meta_r', 'compose']", ""},
{"union", "KeyValue", "{'qcode': 'QKeyCode', 'number': 'int'}", ""},
{"command", "send-key", "{'keys': ['KeyValue'], '*hold-time': 'int'}", ""},
{"command", "screendump", "{'filename': 'str'}", ""},
{"command", "nbd-server-start", "{'addr': 'SocketAddress'}", ""},
{"command", "nbd-server-add", "{'device': 'str', '*writable': 'bool'}", ""},
{"command", "nbd-server-stop", "", ""},
{"type", "ChardevFile", "{'*in': 'str', 'out': 'str'}", ""},
{"type", "ChardevHostdev", "{'device': 'str'}", ""},
{"type", "ChardevSocket", "{'*nodelay': 'bool', '*wait': 'bool', '*server': 'bool', 'addr': 'SocketAddress', '*telnet': 'bool'}", ""},
{"type", "ChardevUdp", "{'*local': 'SocketAddress', 'remote': 'SocketAddress'}", ""},
{"type", "ChardevMux", "{'chardev': 'str'}", ""},
{"type", "ChardevStdio", "{'*signal': 'bool'}", ""},
{"type", "ChardevSpiceChannel", "{'type': 'str'}", ""},
{"type", "ChardevSpicePort", "{'fqdn': 'str'}", ""},
{"type", "ChardevVC", "{'*width': 'int', '*height': 'int', '*cols': 'int', '*rows': 'int'}", ""},
{"type", "ChardevMemory", "{'*size': 'int'}", ""},
{"type", "ChardevDummy", "{}", ""},
{"union", "ChardevBackend", "{'udp': 'ChardevUdp', 'vc': 'ChardevVC', 'console': 'ChardevDummy', 'socket': 'ChardevSocket', 'braille': 'ChardevDummy', 'stdio': 'ChardevStdio', 'spiceport': 'ChardevSpicePort', 'mux': 'ChardevMux', 'pipe': 'ChardevHostdev', 'msmouse': 'ChardevDummy', 'file': 'ChardevFile', 'memory': 'ChardevMemory', 'spicevmc': 'ChardevSpiceChannel', 'serial': 'ChardevHostdev', 'null': 'ChardevDummy', 'parallel': 'ChardevHostdev', 'pty': 'ChardevDummy'}", ""},
{"type", "ChardevReturn", "{'*pty': 'str'}", ""},
{"command", "chardev-add", "{'id': 'str', 'backend': 'ChardevBackend'}", "ChardevReturn"},
{"command", "chardev-remove", "{'id': 'str'}", ""},
{"enum", "TpmModel", "['tpm-tis']", ""},
{"command", "query-tpm-models", "", "['TpmModel']"},
{"enum", "TpmType", "['passthrough']", ""},
{"command", "query-tpm-types", "", "['TpmType']"},
{"type", "TPMPassthroughOptions", "{'*cancel-path': 'str', '*path': 'str'}", ""},
{"union", "TpmTypeOptions", "{'passthrough': 'TPMPassthroughOptions'}", ""},
{"type", "TPMInfo", "{'model': 'TpmModel', 'id': 'str', 'options': 'TpmTypeOptions'}", ""},
{"command", "query-tpm", "", "['TPMInfo']"},
{"type", "AcpiTableOptions", "{'*asl_compiler_rev': 'uint32', '*oem_rev': 'uint32', '*sig': 'str', '*file': 'str', '*data': 'str', '*rev': 'uint8', '*asl_compiler_id': 'str', '*oem_table_id': 'str', '*oem_id': 'str'}", ""},
{"enum", "CommandLineParameterType", "['string', 'boolean', 'number', 'size']", ""},
{"type", "CommandLineParameterInfo", "{'type': 'CommandLineParameterType', 'name': 'str', '*help': 'str'}", ""},
{"type", "CommandLineOptionInfo", "{'option': 'str', 'parameters': ['CommandLineParameterInfo']}", ""},
{"command", "query-command-line-options", "{'*option': 'str'}", "['CommandLineOptionInfo']"},
{"enum", "X86CPURegister32", "['EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI']", ""},
{"type", "X86CPUFeatureWordInfo", "{'cpuid-register': 'X86CPURegister32', '*cpuid-input-ecx': 'int', 'cpuid-input-eax': 'int', 'features': 'int'}", ""},
{"type", "SchemaData", "{'*returns': 'str', 'type': 'str', 'name': 'str', '*data': 'str'}", ""},
{"command", "query-qmp-schema", "{'*name': 'str', '*type': 'str'}", "['SchemaData']"},
{NULL, NULL, NULL } };
{ "execute": "query-qmp-schema"}
{
    "return": [
        {
            "name": "ErrorClass", 
            "type": "enum", 
            "data": "['GenericError', 'CommandNotFound', 'DeviceEncrypted', 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap']"
        }, 
        {
            "name": "add_client", 
            "type": "command", 
            "data": "{'*skipauth': 'bool', 'protocol': 'str', 'fdname': 'str', '*tls': 'bool'}"
        }, 
        {
            "name": "NameInfo", 
            "type": "type", 
            "data": "{'*name': 'str'}"
        }, 
        {
            "name": "query-name", 
            "type": "command", 
            "returns": "NameInfo"
        }, 
        {
            "name": "VersionInfo", 
            "type": "type", 
            "data": "{'qemu': OrderedDict([('major', 'int'), ('minor', 'int'), ('micro', 'int')]), 'package': 'str'}"
        }, 
        {
            "name": "query-version", 
            "type": "command", 
            "returns": "VersionInfo"
        }, 
        {
            "name": "KvmInfo", 
            "type": "type", 
            "data": "{'enabled': 'bool', 'present': 'bool'}"
        }, 
        {
            "name": "query-kvm", 
            "type": "command", 
            "returns": "KvmInfo"
        }, 
        {
            "name": "RunState", 
            "type": "enum", 
            "data": "['debug', 'inmigrate', 'internal-error', 'io-error', 'paused', 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm', 'running', 'save-vm', 'shutdown', 'suspended', 'watchdog', 'guest-panicked']"
        }, 
        {
            "name": "SnapshotInfo", 
            "type": "type", 
            "data": "{'name': 'str', 'date-sec': 'int', 'vm-state-size': 'int', 'vm-clock-nsec': 'int', 'vm-clock-sec': 'int', 'date-nsec': 'int', 'id': 'str'}"
        }, 
        {
            "name": "ImageInfo", 
            "type": "type", 
            "data": "{'*snapshots': ['SnapshotInfo'], 'format': 'str', '*encrypted': 'bool', '*dirty-flag': 'bool', '*backing-filename-format': 'str', '*backing-filename': 'str', '*actual-size': 'int', 'filename': 'str', 'virtual-size': 'int', '*full-backing-filename': 'str', '*cluster-size': 'int'}"
        }, 
        {
            "name": "ImageCheck", 
            "type": "type", 
            "data": "{'check-errors': 'int', '*image-end-offset': 'int', '*corruptions-fixed': 'int', '*allocated-clusters': 'int', 'format': 'str', '*corruptions': 'int', '*total-clusters': 'int', 'filename': 'str', '*fragmented-clusters': 'int', '*leaks-fixed': 'int', '*compressed-clusters': 'int', '*leaks': 'int'}"
        }, 
        {
            "name": "StatusInfo", 
            "type": "type", 
            "data": "{'singlestep': 'bool', 'status': 'RunState', 'running': 'bool'}"
        }, 
        {
            "name": "query-status", 
            "type": "command", 
            "returns": "StatusInfo"
        }, 
        {
            "name": "UuidInfo", 
            "type": "type", 
            "data": "{'UUID': 'str'}"
        }, 
        {
            "name": "query-uuid", 
            "type": "command", 
            "returns": "UuidInfo"
        }, 
        {
            "name": "ChardevInfo", 
            "type": "type", 
            "data": "{'filename': 'str', 'label': 'str'}"
        }, 
        {
            "name": "query-chardev", 
            "type": "command", 
            "returns": "['ChardevInfo']"
        }, 
        {
            "name": "DataFormat", 
            "type": "enum", 
            "data": "['utf8', 'base64']"
        }, 
        {
            "name": "ringbuf-write", 
            "type": "command", 
            "data": "{'device': 'str', '*format': 'DataFormat', 'data': 'str'}"
        }, 
        {
            "name": "ringbuf-read", 
            "type": "command", 
            "returns": "str", 
            "data": "{'device': 'str', '*format': 'DataFormat', 'size': 'int'}"
        }, 
        {
            "name": "CommandInfo", 
            "type": "type", 
            "data": "{'name': 'str'}"
        }, 
        {
            "name": "query-commands", 
            "type": "command", 
            "returns": "['CommandInfo']"
        }, 
        {
            "name": "EventInfo", 
            "type": "type", 
            "data": "{'name': 'str'}"
        }, 
        {
            "name": "query-events", 
            "type": "command", 
            "returns": "['EventInfo']"
        }, 
        {
            "name": "MigrationStats", 
            "type": "type", 
            "data": "{'skipped': 'int', 'dirty-pages-rate': 'int', 'normal': 'int', 'transferred': 'int', 'duplicate': 'int', 'total': 'int', 'remaining': 'int', 'normal-bytes': 'int'}"
        }, 
        {
            "name": "XBZRLECacheStats", 
            "type": "type", 
            "data": "{'cache-miss': 'int', 'overflow': 'int', 'bytes': 'int', 'pages': 'int', 'cache-size': 'int'}"
        }, 
        {
            "name": "MigrationInfo", 
            "type": "type", 
            "data": "{'*ram': 'MigrationStats', '*total-time': 'int', '*downtime': 'int', '*expected-downtime': 'int', '*status': 'str', '*xbzrle-cache': 'XBZRLECacheStats', '*disk': 'MigrationStats'}"
        }, 
        {
            "name": "query-migrate", 
            "type": "command", 
            "returns": "MigrationInfo"
        }, 
        {
            "name": "MigrationCapability", 
            "type": "enum", 
            "data": "['xbzrle']"
        }, 
        {
            "name": "MigrationCapabilityStatus", 
            "type": "type", 
            "data": "{'capability': 'MigrationCapability', 'state': 'bool'}"
        }, 
        {
            "name": "migrate-set-capabilities", 
            "type": "command", 
            "data": "{'capabilities': ['MigrationCapabilityStatus']}"
        }, 
        {
            "name": "query-migrate-capabilities", 
            "type": "command", 
            "returns": "['MigrationCapabilityStatus']"
        }, 
        {
            "name": "MouseInfo", 
            "type": "type", 
            "data": "{'current': 'bool', 'index': 'int', 'name': 'str', 'absolute': 'bool'}"
        }, 
        {
            "name": "query-mice", 
            "type": "command", 
            "returns": "['MouseInfo']"
        }, 
        {
            "name": "CpuInfo", 
            "type": "type", 
            "data": "{'halted': 'bool', '*npc': 'int', '*PC': 'int', '*pc': 'int', 'current': 'bool', 'thread_id': 'int', 'CPU': 'int', '*nip': 'int'}"
        }, 
        {
            "name": "query-cpus", 
            "type": "command", 
            "returns": "['CpuInfo']"
        }, 
        {
            "name": "BlockDeviceInfo", 
            "type": "type", 
            "data": "{'bps_rd': 'int', 'backing_file_depth': 'int', 'encrypted': 'bool', '*backing_file': 'str', 'bps_wr': 'int', 'drv': 'str', 'bps': 'int', 'iops': 'int', 'file': 'str', 'iops_rd': 'int', 'encryption_key_missing': 'bool', 'ro': 'bool', 'iops_wr': 'int'}"
        }, 
        {
            "name": "BlockDeviceIoStatus", 
            "type": "enum", 
            "data": "['ok', 'failed', 'nospace']"
        }, 
        {
            "name": "BlockDirtyInfo", 
            "type": "type", 
            "data": "{'count': 'int', 'granularity': 'int'}"
        }, 
        {
            "name": "BlockInfo", 
            "type": "type", 
            "data": "{'*tray_open': 'bool', 'locked': 'bool', '*io-status': 'BlockDeviceIoStatus', '*dirty': 'BlockDirtyInfo', '*inserted': 'BlockDeviceInfo', 'removable': 'bool', 'device': 'str', 'type': 'str'}"
        }, 
        {
            "name": "query-block", 
            "type": "command", 
            "returns": "['BlockInfo']"
        }, 
        {
            "name": "BlockDeviceStats", 
            "type": "type", 
            "data": "{'rd_operations': 'int', 'flush_total_time_ns': 'int', 'wr_highest_offset': 'int', 'rd_total_time_ns': 'int', 'rd_bytes': 'int', 'wr_total_time_ns': 'int', 'flush_operations': 'int', 'wr_operations': 'int', 'wr_bytes': 'int'}"
        }, 
        {
            "name": "BlockStats", 
            "type": "type", 
            "data": "{'stats': 'BlockDeviceStats', '*parent': 'BlockStats', '*device': 'str'}"
        }, 
        {
            "name": "query-blockstats", 
            "type": "command", 
            "returns": "['BlockStats']"
        }, 
        {
            "name": "VncClientInfo", 
            "type": "type", 
            "data": "{'*sasl_username': 'str', 'host': 'str', 'service': 'str', 'family': 'str', '*x509_dname': 'str'}"
        }, 
        {
            "name": "VncInfo", 
            "type": "type", 
            "data": "{'*auth': 'str', 'enabled': 'bool', '*host': 'str', '*clients': ['VncClientInfo'], '*family': 'str', '*service': 'str'}"
        }, 
        {
            "name": "query-vnc", 
            "type": "command", 
            "returns": "VncInfo"
        }, 
        {
            "name": "SpiceChannel", 
            "type": "type", 
            "data": "{'tls': 'bool', 'family': 'str', 'host': 'str', 'channel-type': 'int', 'connection-id': 'int', 'port': 'str', 'channel-id': 'int'}"
        }, 
        {
            "name": "SpiceQueryMouseMode", 
            "type": "enum", 
            "data": "['client', 'server', 'unknown']"
        }, 
        {
            "name": "SpiceInfo", 
            "type": "type", 
            "data": "{'migrated': 'bool', '*tls-port': 'int', '*port': 'int', '*auth': 'str', 'enabled': 'bool', '*host': 'str', '*channels': ['SpiceChannel'], 'mouse-mode': 'SpiceQueryMouseMode', '*compiled-version': 'str'}"
        }, 
        {
            "name": "query-spice", 
            "type": "command", 
            "returns": "SpiceInfo"
        }, 
        {
            "name": "BalloonInfo", 
            "type": "type", 
            "data": "{'actual': 'int'}"
        }, 
        {
            "name": "query-balloon", 
            "type": "command", 
            "returns": "BalloonInfo"
        }, 
        {
            "name": "PciMemoryRange", 
            "type": "type", 
            "data": "{'base': 'int', 'limit': 'int'}"
        }, 
        {
            "name": "PciMemoryRegion", 
            "type": "type", 
            "data": "{'bar': 'int', '*prefetch': 'bool', 'address': 'int', 'type': 'str', '*mem_type_64': 'bool', 'size': 'int'}"
        }, 
        {
            "name": "PciBridgeInfo", 
            "type": "type", 
            "data": "{'bus': OrderedDict([('number', 'int'), ('secondary', 'int'), ('subordinate', 'int'), ('io_range', 'PciMemoryRange'), ('memory_range', 'PciMemoryRange'), ('prefetchable_range', 'PciMemoryRange')]), '*devices': ['PciDeviceInfo']}"
        }, 
        {
            "name": "PciDeviceInfo", 
            "type": "type", 
            "data": "{'slot': 'int', 'function': 'int', 'bus': 'int', 'class_info': OrderedDict([('*desc', 'str'), ('class', 'int')]), '*pci_bridge': 'PciBridgeInfo', '*irq': 'int', 'regions': ['PciMemoryRegion'], 'qdev_id': 'str', 'id': OrderedDict([('device', 'int'), ('vendor', 'int')])}"
        }, 
        {
            "name": "PciInfo", 
            "type": "type", 
            "data": "{'bus': 'int', 'devices': ['PciDeviceInfo']}"
        }, 
        {
            "name": "query-pci", 
            "type": "command", 
            "returns": "['PciInfo']"
        }, 
        {
            "name": "BlockdevOnError", 
            "type": "enum", 
            "data": "['report', 'ignore', 'enospc', 'stop']"
        }, 
        {
            "name": "MirrorSyncMode", 
            "type": "enum", 
            "data": "['top', 'full', 'none']"
        }, 
        {
            "name": "BlockJobInfo", 
            "type": "type", 
            "data": "{'busy': 'bool', 'speed': 'int', 'len': 'int', 'paused': 'bool', 'io-status': 'BlockDeviceIoStatus', 'offset': 'int', 'device': 'str', 'type': 'str'}"
        }, 
        {
            "name": "query-block-jobs", 
            "type": "command", 
            "returns": "['BlockJobInfo']"
        }, 
        {
            "name": "quit", 
            "type": "command"
        }, 
        {
            "name": "stop", 
            "type": "command"
        }, 
        {
            "name": "system_reset", 
            "type": "command"
        }, 
        {
            "name": "system_powerdown", 
            "type": "command"
        }, 
        {
            "name": "cpu", 
            "type": "command", 
            "data": "{'index': 'int'}"
        }, 
        {
            "name": "cpu-add", 
            "type": "command", 
            "data": "{'id': 'int'}"
        }, 
        {
            "name": "memsave", 
            "type": "command", 
            "data": "{'filename': 'str', '*cpu-index': 'int', 'val': 'int', 'size': 'int'}"
        }, 
        {
            "name": "pmemsave", 
            "type": "command", 
            "data": "{'filename': 'str', 'val': 'int', 'size': 'int'}"
        }, 
        {
            "name": "cont", 
            "type": "command"
        }, 
        {
            "name": "system_wakeup", 
            "type": "command"
        }, 
        {
            "name": "inject-nmi", 
            "type": "command"
        }, 
        {
            "name": "set_link", 
            "type": "command", 
            "data": "{'name': 'str', 'up': 'bool'}"
        }, 
        {
            "name": "block_passwd", 
            "type": "command", 
            "data": "{'device': 'str', 'password': 'str'}"
        }, 
        {
            "name": "balloon", 
            "type": "command", 
            "data": "{'value': 'int'}"
        }, 
        {
            "name": "block_resize", 
            "type": "command", 
            "data": "{'device': 'str', 'size': 'int'}"
        }, 
        {
            "name": "NewImageMode", 
            "type": "enum", 
            "data": "['existing', 'absolute-paths']"
        }, 
        {
            "name": "BlockdevSnapshot", 
            "type": "type", 
            "data": "{'device': 'str', '*format': 'str', 'snapshot-file': 'str', '*mode': 'NewImageMode'}"
        }, 
        {
            "name": "TransactionAction", 
            "type": "union", 
            "data": "{'blockdev-snapshot-sync': 'BlockdevSnapshot'}"
        }, 
        {
            "name": "transaction", 
            "type": "command", 
            "data": "{'actions': ['TransactionAction']}"
        }, 
        {
            "name": "blockdev-snapshot-sync", 
            "type": "command", 
            "data": "{'device': 'str', '*format': 'str', 'snapshot-file': 'str', '*mode': 'NewImageMode'}"
        }, 
        {
            "name": "human-monitor-command", 
            "type": "command", 
            "returns": "str", 
            "data": "{'*cpu-index': 'int', 'command-line': 'str'}"
        }, 
        {
            "name": "block-commit", 
            "type": "command", 
            "data": "{'device': 'str', 'top': 'str', '*base': 'str', '*speed': 'int'}"
        }, 
        {
            "name": "drive-mirror", 
            "type": "command", 
            "data": "{'*on-target-error': 'BlockdevOnError', '*buf-size': 'int', 'target': 'str', '*granularity': 'uint32', '*format': 'str', '*speed': 'int', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', 'device': 'str', '*on-source-error': 'BlockdevOnError'}"
        }, 
        {
            "name": "migrate_cancel", 
            "type": "command"
        }, 
        {
            "name": "migrate_set_downtime", 
            "type": "command", 
            "data": "{'value': 'number'}"
        }, 
        {
            "name": "migrate_set_speed", 
            "type": "command", 
            "data": "{'value': 'int'}"
        }, 
        {
            "name": "migrate-set-cache-size", 
            "type": "command", 
            "data": "{'value': 'int'}"
        }, 
        {
            "name": "query-migrate-cache-size", 
            "type": "command", 
            "returns": "int"
        }, 
        {
            "name": "ObjectPropertyInfo", 
            "type": "type", 
            "data": "{'type': 'str', 'name': 'str'}"
        }, 
        {
            "name": "qom-list", 
            "type": "command", 
            "returns": "['ObjectPropertyInfo']", 
            "data": "{'path': 'str'}"
        }, 
        {
            "name": "qom-get", 
            "type": "command", 
            "returns": "visitor", 
            "data": "{'path': 'str', 'property': 'str'}"
        }, 
        {
            "name": "qom-set", 
            "type": "command", 
            "data": "{'path': 'str', 'property': 'str', 'value': 'visitor'}"
        }, 
        {
            "name": "set_password", 
            "type": "command", 
            "data": "{'password': 'str', 'protocol': 'str', '*connected': 'str'}"
        }, 
        {
            "name": "expire_password", 
            "type": "command", 
            "data": "{'protocol': 'str', 'time': 'str'}"
        }, 
        {
            "name": "eject", 
            "type": "command", 
            "data": "{'device': 'str', '*force': 'bool'}"
        }, 
        {
            "name": "change-vnc-password", 
            "type": "command", 
            "data": "{'password': 'str'}"
        }, 
        {
            "name": "change", 
            "type": "command", 
            "data": "{'device': 'str', 'target': 'str', '*arg': 'str'}"
        }, 
        {
            "name": "block_set_io_throttle", 
            "type": "command", 
            "data": "{'bps_rd': 'int', 'bps_wr': 'int', 'bps': 'int', 'iops': 'int', 'iops_rd': 'int', 'device': 'str', 'iops_wr': 'int'}"
        }, 
        {
            "name": "block-stream", 
            "type": "command", 
            "data": "{'device': 'str', '*on-error': 'BlockdevOnError', '*base': 'str', '*speed': 'int'}"
        }, 
        {
            "name": "block-job-set-speed", 
            "type": "command", 
            "data": "{'device': 'str', 'speed': 'int'}"
        }, 
        {
            "name": "block-job-cancel", 
            "type": "command", 
            "data": "{'device': 'str', '*force': 'bool'}"
        }, 
        {
            "name": "block-job-pause", 
            "type": "command", 
            "data": "{'device': 'str'}"
        }, 
        {
            "name": "block-job-resume", 
            "type": "command", 
            "data": "{'device': 'str'}"
        }, 
        {
            "name": "block-job-complete", 
            "type": "command", 
            "data": "{'device': 'str'}"
        }, 
        {
            "name": "ObjectTypeInfo", 
            "type": "type", 
            "data": "{'name': 'str'}"
        }, 
        {
            "name": "qom-list-types", 
            "type": "command", 
            "returns": "['ObjectTypeInfo']", 
            "data": "{'*abstract': 'bool', '*implements': 'str'}"
        }, 
        {
            "name": "DevicePropertyInfo", 
            "type": "type", 
            "data": "{'type': 'str', 'name': 'str'}"
        }, 
        {
            "name": "device-list-properties", 
            "type": "command", 
            "returns": "['DevicePropertyInfo']", 
            "data": "{'typename': 'str'}"
        }, 
        {
            "name": "migrate", 
            "type": "command", 
            "data": "{'*detach': 'bool', 'uri': 'str', '*inc': 'bool', '*blk': 'bool'}"
        }, 
        {
            "name": "xen-save-devices-state", 
            "type": "command", 
            "data": "{'filename': 'str'}"
        }, 
        {
            "name": "xen-set-global-dirty-log", 
            "type": "command", 
            "data": "{'enable': 'bool'}"
        }, 
        {
            "name": "device_del", 
            "type": "command", 
            "data": "{'id': 'str'}"
        }, 
        {
            "name": "dump-guest-memory", 
            "type": "command", 
            "data": "{'*length': 'int', 'paging': 'bool', 'protocol': 'str', '*begin': 'int'}"
        }, 
        {
            "name": "netdev_add", 
            "type": "command", 
            "data": "{'*props': '**', 'type': 'str', 'id': 'str'}"
        }, 
        {
            "name": "netdev_del", 
            "type": "command", 
            "data": "{'id': 'str'}"
        }, 
        {
            "name": "NetdevNoneOptions", 
            "type": "type", 
            "data": "{}"
        }, 
        {
            "name": "NetLegacyNicOptions", 
            "type": "type", 
            "data": "{'*macaddr': 'str', '*model': 'str', '*addr': 'str', '*vectors': 'uint32', '*netdev': 'str'}"
        }, 
        {
            "name": "String", 
            "type": "type", 
            "data": "{'str': 'str'}"
        }, 
        {
            "name": "NetdevUserOptions", 
            "type": "type", 
            "data": "{'*hostname': 'str', '*tftp': 'str', '*dhcpstart': 'str', '*guestfwd': ['String'], '*smbserver': 'str', '*hostfwd': ['String'], '*host': 'str', '*net': 'str', '*restrict': 'bool', '*dnssearch': ['String'], '*ip': 'str', '*dns': 'str', '*smb': 'str', '*bootfile': 'str'}"
        }, 
        {
            "name": "NetdevTapOptions", 
            "type": "type", 
            "data": "{'*vhostfd': 'str', '*script': 'str', '*helper': 'str', '*vhostfds': 'str', '*vnet_hdr': 'bool', '*downscript': 'str', '*queues': 'uint32', '*fd': 'str', '*vhostforce': 'bool', '*ifname': 'str', '*fds': 'str', '*vhost': 'bool', '*sndbuf': 'size'}"
        }, 
        {
            "name": "NetdevSocketOptions", 
            "type": "type", 
            "data": "{'*mcast': 'str', '*connect': 'str', '*fd': 'str', '*listen': 'str', '*udp': 'str', '*localaddr': 'str'}"
        }, 
        {
            "name": "NetdevVdeOptions", 
            "type": "type", 
            "data": "{'*mode': 'uint16', '*group': 'str', '*port': 'uint16', '*sock': 'str'}"
        }, 
        {
            "name": "NetdevDumpOptions", 
            "type": "type", 
            "data": "{'*len': 'size', '*file': 'str'}"
        }, 
        {
            "name": "NetdevBridgeOptions", 
            "type": "type", 
            "data": "{'*helper': 'str', '*br': 'str'}"
        }, 
        {
            "name": "NetdevHubPortOptions", 
            "type": "type", 
            "data": "{'hubid': 'int32'}"
        }, 
        {
            "name": "NetClientOptions", 
            "type": "union", 
            "data": "{'bridge': 'NetdevBridgeOptions', 'none': 'NetdevNoneOptions', 'tap': 'NetdevTapOptions', 'socket': 'NetdevSocketOptions', 'dump': 'NetdevDumpOptions', 'nic': 'NetLegacyNicOptions', 'vde': 'NetdevVdeOptions', 'user': 'NetdevUserOptions', 'hubport': 'NetdevHubPortOptions'}"
        }, 
        {
            "name": "NetLegacy", 
            "type": "type", 
            "data": "{'*id': 'str', '*vlan': 'int32', '*name': 'str', 'opts': 'NetClientOptions'}"
        }, 
        {
            "name": "Netdev", 
            "type": "type", 
            "data": "{'id': 'str', 'opts': 'NetClientOptions'}"
        }, 
        {
            "name": "InetSocketAddress", 
            "type": "type", 
            "data": "{'*ipv6': 'bool', 'host': 'str', '*to': 'uint16', 'port': 'str', '*ipv4': 'bool'}"
        }, 
        {
            "name": "UnixSocketAddress", 
            "type": "type", 
            "data": "{'path': 'str'}"
        }, 
        {
            "name": "SocketAddress", 
            "type": "union", 
            "data": "{'unix': 'UnixSocketAddress', 'fd': 'String', 'inet': 'InetSocketAddress'}"
        }, 
        {
            "name": "getfd", 
            "type": "command", 
            "data": "{'fdname': 'str'}"
        }, 
        {
            "name": "closefd", 
            "type": "command", 
            "data": "{'fdname': 'str'}"
        }, 
        {
            "name": "MachineInfo", 
            "type": "type", 
            "data": "{'*alias': 'str', '*is-default': 'bool', 'cpu-max': 'int', 'name': 'str'}"
        }, 
        {
            "name": "query-machines", 
            "type": "command", 
            "returns": "['MachineInfo']"
        }, 
        {
            "name": "CpuDefinitionInfo", 
            "type": "type", 
            "data": "{'name': 'str'}"
        }, 
        {
            "name": "query-cpu-definitions", 
            "type": "command", 
            "returns": "['CpuDefinitionInfo']"
        }, 
        {
            "name": "AddfdInfo", 
            "type": "type", 
            "data": "{'fdset-id': 'int', 'fd': 'int'}"
        }, 
        {
            "name": "add-fd", 
            "type": "command", 
            "returns": "AddfdInfo", 
            "data": "{'*opaque': 'str', '*fdset-id': 'int'}"
        }, 
        {
            "name": "remove-fd", 
            "type": "command", 
            "data": "{'fdset-id': 'int', '*fd': 'int'}"
        }, 
        {
            "name": "FdsetFdInfo", 
            "type": "type", 
            "data": "{'*opaque': 'str', 'fd': 'int'}"
        }, 
        {
            "name": "FdsetInfo", 
            "type": "type", 
            "data": "{'fdset-id': 'int', 'fds': ['FdsetFdInfo']}"
        }, 
        {
            "name": "query-fdsets", 
            "type": "command", 
            "returns": "['FdsetInfo']"
        }, 
        {
            "name": "TargetType", 
            "type": "enum", 
            "data": "['alpha', 'arm', 'cris', 'i386', 'lm32', 'm68k', 'microblazeel', 'microblaze', 'mips64el', 'mips64', 'mipsel', 'mips', 'moxie', 'or32', 'ppc64', 'ppcemb', 'ppc', 's390x', 'sh4eb', 'sh4', 'sparc64', 'sparc', 'unicore32', 'x86_64', 'xtensaeb', 'xtensa']"
        }, 
        {
            "name": "TargetInfo", 
            "type": "type", 
            "data": "{'arch': 'TargetType'}"
        }, 
        {
            "name": "query-target", 
            "type": "command", 
            "returns": "TargetInfo"
        }, 
        {
            "name": "QKeyCode", 
            "type": "enum", 
            "data": "['shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl', 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right', 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'semicolon', 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', 'caps_lock', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply', 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', 'sysrq', 'kp_0', 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', 'kp_7', 'kp_8', 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end', 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again', 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut', 'lf', 'help', 'meta_l', 'meta_r', 'compose']"
        }, 
        {
            "name": "KeyValue", 
            "type": "union", 
            "data": "{'qcode': 'QKeyCode', 'number': 'int'}"
        }, 
        {
            "name": "send-key", 
            "type": "command", 
            "data": "{'keys': ['KeyValue'], '*hold-time': 'int'}"
        }, 
        {
            "name": "screendump", 
            "type": "command", 
            "data": "{'filename': 'str'}"
        }, 
        {
            "name": "nbd-server-start", 
            "type": "command", 
            "data": "{'addr': 'SocketAddress'}"
        }, 
        {
            "name": "nbd-server-add", 
            "type": "command", 
            "data": "{'device': 'str', '*writable': 'bool'}"
        }, 
        {
            "name": "nbd-server-stop", 
            "type": "command"
        }, 
        {
            "name": "ChardevFile", 
            "type": "type", 
            "data": "{'*in': 'str', 'out': 'str'}"
        }, 
        {
            "name": "ChardevHostdev", 
            "type": "type", 
            "data": "{'device': 'str'}"
        }, 
        {
            "name": "ChardevSocket", 
            "type": "type", 
            "data": "{'*nodelay': 'bool', '*wait': 'bool', '*server': 'bool', 'addr': 'SocketAddress', '*telnet': 'bool'}"
        }, 
        {
            "name": "ChardevUdp", 
            "type": "type", 
            "data": "{'*local': 'SocketAddress', 'remote': 'SocketAddress'}"
        }, 
        {
            "name": "ChardevMux", 
            "type": "type", 
            "data": "{'chardev': 'str'}"
        }, 
        {
            "name": "ChardevStdio", 
            "type": "type", 
            "data": "{'*signal': 'bool'}"
        }, 
        {
            "name": "ChardevSpiceChannel", 
            "type": "type", 
            "data": "{'type': 'str'}"
        }, 
        {
            "name": "ChardevSpicePort", 
            "type": "type", 
            "data": "{'fqdn': 'str'}"
        }, 
        {
            "name": "ChardevVC", 
            "type": "type", 
            "data": "{'*width': 'int', '*height': 'int', '*cols': 'int', '*rows': 'int'}"
        }, 
        {
            "name": "ChardevMemory", 
            "type": "type", 
            "data": "{'*size': 'int'}"
        }, 
        {
            "name": "ChardevDummy", 
            "type": "type", 
            "data": "{}"
        }, 
        {
            "name": "ChardevBackend", 
            "type": "union", 
            "data": "{'udp': 'ChardevUdp', 'vc': 'ChardevVC', 'console': 'ChardevDummy', 'socket': 'ChardevSocket', 'braille': 'ChardevDummy', 'stdio': 'ChardevStdio', 'spiceport': 'ChardevSpicePort', 'mux': 'ChardevMux', 'pipe': 'ChardevHostdev', 'msmouse': 'ChardevDummy', 'file': 'ChardevFile', 'memory': 'ChardevMemory', 'spicevmc': 'ChardevSpiceChannel', 'serial': 'ChardevHostdev', 'null': 'ChardevDummy', 'parallel': 'ChardevHostdev', 'pty': 'ChardevDummy'}"
        }, 
        {
            "name": "ChardevReturn", 
            "type": "type", 
            "data": "{'*pty': 'str'}"
        }, 
        {
            "name": "chardev-add", 
            "type": "command", 
            "returns": "ChardevReturn", 
            "data": "{'id': 'str', 'backend': 'ChardevBackend'}"
        }, 
        {
            "name": "chardev-remove", 
            "type": "command", 
            "data": "{'id': 'str'}"
        }, 
        {
            "name": "TpmModel", 
            "type": "enum", 
            "data": "['tpm-tis']"
        }, 
        {
            "name": "query-tpm-models", 
            "type": "command", 
            "returns": "['TpmModel']"
        }, 
        {
            "name": "TpmType", 
            "type": "enum", 
            "data": "['passthrough']"
        }, 
        {
            "name": "query-tpm-types", 
            "type": "command", 
            "returns": "['TpmType']"
        }, 
        {
            "name": "TPMPassthroughOptions", 
            "type": "type", 
            "data": "{'*cancel-path': 'str', '*path': 'str'}"
        }, 
        {
            "name": "TpmTypeOptions", 
            "type": "union", 
            "data": "{'passthrough': 'TPMPassthroughOptions'}"
        }, 
        {
            "name": "TPMInfo", 
            "type": "type", 
            "data": "{'model': 'TpmModel', 'id': 'str', 'options': 'TpmTypeOptions'}"
        }, 
        {
            "name": "query-tpm", 
            "type": "command", 
            "returns": "['TPMInfo']"
        }, 
        {
            "name": "AcpiTableOptions", 
            "type": "type", 
            "data": "{'*asl_compiler_rev': 'uint32', '*oem_rev': 'uint32', '*sig': 'str', '*file': 'str', '*data': 'str', '*rev': 'uint8', '*asl_compiler_id': 'str', '*oem_table_id': 'str', '*oem_id': 'str'}"
        }, 
        {
            "name": "CommandLineParameterType", 
            "type": "enum", 
            "data": "['string', 'boolean', 'number', 'size']"
        }, 
        {
            "name": "CommandLineParameterInfo", 
            "type": "type", 
            "data": "{'type': 'CommandLineParameterType', 'name': 'str', '*help': 'str'}"
        }, 
        {
            "name": "CommandLineOptionInfo", 
            "type": "type", 
            "data": "{'option': 'str', 'parameters': ['CommandLineParameterInfo']}"
        }, 
        {
            "name": "query-command-line-options", 
            "type": "command", 
            "returns": "['CommandLineOptionInfo']", 
            "data": "{'*option': 'str'}"
        }, 
        {
            "name": "X86CPURegister32", 
            "type": "enum", 
            "data": "['EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI']"
        }, 
        {
            "name": "X86CPUFeatureWordInfo", 
            "type": "type", 
            "data": "{'cpuid-register': 'X86CPURegister32', '*cpuid-input-ecx': 'int', 'cpuid-input-eax': 'int', 'features': 'int'}"
        }, 
        {
            "name": "SchemaData", 
            "type": "type", 
            "data": "{'*returns': 'str', 'type': 'str', 'name': 'str', '*data': 'str'}"
        }, 
        {
            "name": "query-qmp-schema", 
            "type": "command", 
            "returns": "['SchemaData']", 
            "data": "{'*name': 'str', '*type': 'str'}"
        }
    ]
}
From 2b39fe0f380eea6a96de3589b3d148673d28c1ff Mon Sep 17 00:00:00 2001
From: Amos Kong <akong@redhat.com>
Date: Fri, 7 Jun 2013 18:02:21 +0800
Subject: [PATCH] full introspection support for QMP

Signed-off-by: Amos Kong <akong@redhat.com>
---
 qapi-schema.json         |  6 ++++++
 qmp-commands.hx          | 23 +++++++++++++++++++++++
 qmp.c                    | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 scripts/qapi-commands.py |  2 +-
 scripts/qapi-types.py    | 42 +++++++++++++++++++++++++++++++++++++++++-
 scripts/qapi-visit.py    |  2 +-
 scripts/qapi.py          | 13 ++++++++++++-
 7 files changed, 130 insertions(+), 4 deletions(-)

Comments

Eric Blake June 14, 2013, 10:59 a.m. UTC | #1
On 06/14/2013 10:52 AM, Amos Kong wrote:
> On Fri, Jun 07, 2013 at 06:17:26PM +0800, Amos Kong wrote:
>> On Fri, Jun 07, 2013 at 06:12:30PM +0800, Amos Kong wrote:
>>> Sent out a draft patch in the end of this week. It doesn't support:
>>> * output all stuffs in one shot.
>>> * introspect event
>>> * provide metadata date
>>>
>>> How can we define a dynamic dict in qmp-schema.json ?
>>>
>>> Currently I just output the raw json dict by a string, Libvirt needs
>>> parse two times, convert the string to json format.
>>>
>>> qmp-schema.h: auto generated head file by qapi script
>>>
>>> Attached some examples.
> 
> 
> Hello all,
> 
> I defined a new type 'SchemaData', it contains 4 keys (type, name, data, returns)
> 
> | { 'type': 'SchemaData',
> |   'data': { 'type': 'str', 'name': 'str', '*data': 'str', '*returns': 'str' } }

It seems like 'type' should be an enum rather than an open-coded 'str'.

Returning 'data' and 'returns' as an open-coded 'str' is not nice - it
requires the client to do further parsing.  I was serious when I
suggested adding additional layers of formalized structure to the
result.  My suggestion was something like:

{ 'type': 'SchemaDataMember', 'data': {
    'option': 'str', 'type': 'str', '*optional': 'bool' } }
{ 'enum': 'SchemaMetatype', 'data': [ 'command', 'type', 'event' ] }
{ 'type': 'SchemaData', 'data': {
    'name': 'str',
    'metatype': 'SchemaMetatype',
    '*returns': 'str',
    '*data': [ 'SchemaDataMember' ] } }

> | 
> | { 'command': 'query-qmp-schema', 'data': { '*type': 'str', '*name': 'str' },
> |   'returns': ['SchemaData'] }


I'm still not sure whether optional filtering will be used by libvirt,
or if it adds any complexity on your end (I'm not opposed to it, but I
know that there hasn't been universal agreement on filtering queries yet).

Again, it seems like 'type' should be an enum.  Something like:

{ 'command': 'query-qmp-schema',
  'data': { '*type': 'SchemaMetatype', '*name': 'str' },
  'returns': ['SchemaData'] }

> 
> Then we can provice meaningful result to Libvirt. Currently I set a string
> for SchemaData['data'].
> 
> 
> I tried to define a dynamical dict for 'data', but it's failed. 
> 
> | { 'type': 'SchemaData',
> |   'data': { 'type': 'str', 'name': 'str', '*data': '**', '*returns': 'str' } }  (Failed!!)
> 
> 
> Does qapi support to define a dynamical dict, then I can convert dict string
> and set to SchemaData['data'] ?

Rather, you want to take an arbitrary dict, and turn it into an array
describing each key of the dict.  That is, given the .json file containing:

{ 'command': 'add_client',
  'data': { 'protocol': 'str', 'fdname': 'str', '*skipauth': 'bool',
            '*tls': 'bool' } }

you would create an array of four members, describing each of the four
dict members, resulting in this exchange:

=> { "execute": "query-qmp-schema",
     "arguments": { "name": "add_client" } }
<= { "return": [
     { "name": "add_client",
       "type": "command",
       "data": [
         { "name": "protocol",
           "type": "str" },
         { "name": "fdname",
           "type": "str" },
         { "name": "skipauth",
           "type": "bool",
           "optional": true },
         { "name": "tls",
           "type": "bool",
           "optional": true }
       ] } ] }
Eric Blake June 14, 2013, 11:09 a.m. UTC | #2
On 06/14/2013 10:52 AM, Amos Kong wrote:

>>From 2b39fe0f380eea6a96de3589b3d148673d28c1ff Mon Sep 17 00:00:00 2001
> From: Amos Kong <akong@redhat.com>
> Date: Fri, 7 Jun 2013 18:02:21 +0800
> Subject: [PATCH] full introspection support for QMP
> 
> Signed-off-by: Amos Kong <akong@redhat.com>
> ---
>  qapi-schema.json         |  6 ++++++
>  qmp-commands.hx          | 23 +++++++++++++++++++++++
>  qmp.c                    | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>  scripts/qapi-commands.py |  2 +-
>  scripts/qapi-types.py    | 42 +++++++++++++++++++++++++++++++++++++++++-
>  scripts/qapi-visit.py    |  2 +-
>  scripts/qapi.py          | 13 ++++++++++++-
>  7 files changed, 130 insertions(+), 4 deletions(-)
> 
> diff --git a/qapi-schema.json b/qapi-schema.json
> index ef1f657..128cc58 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -3618,3 +3618,9 @@
>              '*cpuid-input-ecx': 'int',
>              'cpuid-register': 'X86CPURegister32',
>              'features': 'int' } }
> +
> +{ 'type': 'SchemaData',
> +  'data': { 'type': 'str', 'name': 'str', '*data': 'str', '*returns': 'str' } }
> +
> +{ 'command': 'query-qmp-schema', 'data': { '*type': 'str', '*name': 'str' },
> +  'returns': ['SchemaData'] }

Needs documentation, and a since 1.6 notation in the docs (assuming that
we still make it in time for 1.6).  Also, see my other mail complaining
that this is not structured enough, yet.

> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index ffd130e..fc56fba 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -2932,3 +2932,26 @@ Example:

> +
> +EQMP
> \ No newline at end of file

Fix that.


>  }
>  
> +SchemaDataList * qmp_query_qmp_schema(bool has_type, const char * type,

No space after '*' when declaring a pointer return or pointer argument.
 Should be:

SchemaDataList *qmp_query_qmp_schema(bool has_type, const char *type,

> +++ b/scripts/qapi-types.py

> +
> +struct qmp_schem {

Aren't structs supposed to be named in CamelCase?

> +const char *type;
> +const char *name;
> +const char *data;
> +const char *returns;
> +} qmp_schema_table[] = {
> +"""
> +
> +for i in exprs_all[1]:
> +    print i
> +
> +    data = returns = ""
> +    type = i.keys()[0]
> +    name = i[type]
> +    for k in i.keys():
> +        if isinstance(i[k], OrderedDict):
> +            ret = {}
> +            for key in i[k]:
> +                ret[key] = i[k][key]
> +            i[k] = ret
> +
> +    if i.has_key('data'):
> +        data = i['data']

I think this is where you'd need to do more processing of data to spit
it out in a more structured format, but my python is too weak to
actually write that conversion.
Amos Kong June 18, 2013, 12:21 p.m. UTC | #3
On Fri, Jun 14, 2013 at 12:09:33PM +0100, Eric Blake wrote:
> On 06/14/2013 10:52 AM, Amos Kong wrote:

> > +const char *type;
> > +const char *name;
> > +const char *data;
> > +const char *returns;
> > +} qmp_schema_table[] = {
> > +"""
> > +
> > +for i in exprs_all[1]:
> > +    print i
> > +
> > +    data = returns = ""
> > +    type = i.keys()[0]
> > +    name = i[type]
> > +    for k in i.keys():
> > +        if isinstance(i[k], OrderedDict):
> > +            ret = {}
> > +            for key in i[k]:
> > +                ret[key] = i[k][key]
> > +            i[k] = ret
> > +
> > +    if i.has_key('data'):
> > +        data = i['data']
> 
> I think this is where you'd need to do more processing of data to spit
> it out in a more structured format, but my python is too weak to
> actually write that conversion.

I found a solution :-)

 Generate a string array in C head file to record the raw json string;
 Convert each json string to QObject, and convert the QObject to QDict
 for traversal by recursion;

 Define a new type and uion [1] to describe dynamical date for QMP.
 and allocate & connect nested members in recursion function.

 Finally, we can provide dynamical data with metadate according the
 definition in json file.

I will send a v1 patch later.


---- [1] ----
{ 'union': 'DataValue', 'data': { 'string': 'str', 'obj': 'DataObj' } }
{ 'type': 'DataObj', 'data': { '*key': 'str', 'value': 'DataValue' } }
{ 'type': 'SchemaData',
  'data': { 'type': 'str', 'name': 'str', '*data': ['DataObj'], '*returns': ['DataObj'] } }
diff mbox

Patch

diff --git a/qapi-schema.json b/qapi-schema.json
index ef1f657..128cc58 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3618,3 +3618,9 @@ 
             '*cpuid-input-ecx': 'int',
             'cpuid-register': 'X86CPURegister32',
             'features': 'int' } }
+
+{ 'type': 'SchemaData',
+  'data': { 'type': 'str', 'name': 'str', '*data': 'str', '*returns': 'str' } }
+
+{ 'command': 'query-qmp-schema', 'data': { '*type': 'str', '*name': 'str' },
+  'returns': ['SchemaData'] }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ffd130e..fc56fba 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2932,3 +2932,26 @@  Example:
 <- { "return": {} }
 
 EQMP
+
+    {
+        .name       = "query-qmp-schema",
+        .args_type  = "type:s?,name:s?",
+        .mhandler.cmd_new = qmp_marshal_input_query_qmp_schema,
+    },
+
+
+SQMP
+query-qmp-schema
+----------------
+
+query qmp schema information
+
+Example:
+
+-> { "execute": "query-qmp-schema", "arguments": { "name" : "query-name" }}
+<- { "return": [
+        "{ 'command': 'query-name', 'returns': 'NameInfo' }"
+      ]
+   }
+
+EQMP
\ No newline at end of file
diff --git a/qmp.c b/qmp.c
index 4c149b3..c062f88 100644
--- a/qmp.c
+++ b/qmp.c
@@ -25,6 +25,7 @@ 
 #include "sysemu/blockdev.h"
 #include "qom/qom-qobject.h"
 #include "hw/boards.h"
+#include "qmp-schema.h"
 
 NameInfo *qmp_query_name(Error **errp)
 {
@@ -486,6 +487,51 @@  CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
     return arch_query_cpu_definitions(errp);
 }
 
+SchemaDataList * qmp_query_qmp_schema(bool has_type, const char * type,
+                                      bool has_name, const char * name,
+                                      Error **errp)
+{
+    SchemaDataList *list = NULL, *last_entry, *entry;
+    SchemaData *info;
+    int i;
+
+    for (i = 0; qmp_schema_table[i].type; i++) {
+        if (has_type && strcmp(type, qmp_schema_table[i].type)) {
+            continue;
+        }
+        if (has_name && strcmp(name, qmp_schema_table[i].name)) {
+            continue;
+        }
+
+        info = g_malloc0(sizeof(*info));
+        info->type = g_strdup(qmp_schema_table[i].type);
+        info->name = g_strdup(qmp_schema_table[i].name);
+
+        if (qmp_schema_table[i].data && strlen(qmp_schema_table[i].data) > 0) {
+            info->has_data = true;
+        }
+        info->data = g_strdup(qmp_schema_table[i].data);
+
+        if (qmp_schema_table[i].returns && strlen(qmp_schema_table[i].returns) > 0) {
+            info->has_returns = true;
+        }
+        info->returns = g_strdup(qmp_schema_table[i].returns);
+
+        entry = malloc(sizeof(SchemaDataList *));
+        entry->value = info;
+        entry->next = NULL;
+
+        if (!list) {
+            list = entry;
+        } else {
+            last_entry->next = entry;
+        }
+        last_entry = entry;
+    }
+
+    return list;
+}
+
 void qmp_add_client(const char *protocol, const char *fdname,
                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
                     Error **errp)
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index e06332b..d15d04f 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -437,7 +437,7 @@  except os.error, e:
     if e.errno != errno.EEXIST:
         raise
 
-exprs = parse_schema(sys.stdin)
+exprs = parse_schema(sys.stdin)[0]
 commands = filter(lambda expr: expr.has_key('command'), exprs)
 commands = filter(lambda expr: not expr.has_key('gen'), commands)
 
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index ddcfed9..30e7e56 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -15,6 +15,7 @@  import sys
 import os
 import getopt
 import errno
+import re
 
 def generate_fwd_struct(name, members, builtin_type=False):
     if builtin_type:
@@ -303,7 +304,46 @@  fdecl.write(mcgen('''
 ''',
                   guard=guardname(h_file)))
 
-exprs = parse_schema(sys.stdin)
+exprs_all = parse_schema(sys.stdin)
+
+schema_table = """
+/* convert qapi-schema.json to a string table */
+
+struct qmp_schem {
+const char *type;
+const char *name;
+const char *data;
+const char *returns;
+} qmp_schema_table[] = {
+"""
+
+for i in exprs_all[1]:
+    print i
+
+    data = returns = ""
+    type = i.keys()[0]
+    name = i[type]
+    for k in i.keys():
+        if isinstance(i[k], OrderedDict):
+            ret = {}
+            for key in i[k]:
+                ret[key] = i[k][key]
+            i[k] = ret
+
+    if i.has_key('data'):
+        data = i['data']
+    if i.has_key('returns'):
+        returns = i['returns']
+
+    schema_table += '{"%s", "%s", "%s", "%s"},\n' % (type, name, data, returns)
+
+schema_table += '{NULL, NULL, NULL } };\n'
+
+f = open("qmp-schema.h", "w")
+f.write(schema_table)
+f.close()
+
+exprs = exprs_all[0]
 exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
 
 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 6cac05a..70f80eb 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -334,7 +334,7 @@  fdecl.write(mcgen('''
 ''',
                   prefix=prefix, guard=guardname(h_file)))
 
-exprs = parse_schema(sys.stdin)
+exprs = parse_schema(sys.stdin)[0]
 
 # to avoid header dependency hell, we always generate declarations
 # for built-in types in our header files and simply guard them
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 02ad668..076b5dc 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -80,6 +80,7 @@  def evaluate(string):
 
 def parse_schema(fp):
     exprs = []
+    raw_exprs = []
     expr = ''
     expr_eval = None
 
@@ -91,6 +92,11 @@  def parse_schema(fp):
             expr += line
         elif expr:
             expr_eval = evaluate(expr)
+
+            for name in ['command', 'type', 'enum', 'union']:
+                if expr_eval.has_key(name):
+                    raw_exprs.append(expr_eval)
+
             if expr_eval.has_key('enum'):
                 add_enum(expr_eval['enum'])
             elif expr_eval.has_key('union'):
@@ -102,13 +108,18 @@  def parse_schema(fp):
 
     if expr:
         expr_eval = evaluate(expr)
+
+        for name in ['command', 'type', 'enum', 'union']:
+            if expr_eval.has_key(name):
+                raw_exprs.append(expr_eval)
+
         if expr_eval.has_key('enum'):
             add_enum(expr_eval['enum'])
         elif expr_eval.has_key('union'):
             add_enum('%sKind' % expr_eval['union'])
         exprs.append(expr_eval)
 
-    return exprs
+    return exprs, raw_exprs
 
 def parse_args(typeinfo):
     for member in typeinfo: