diff --git a/monitor.h b/monitor.h index 052f1cb244..cfa2f679f4 100644 --- a/monitor.h +++ b/monitor.h @@ -67,4 +67,8 @@ typedef void (MonitorCompletion)(void *opaque, QObject *ret_data); void monitor_set_error(Monitor *mon, QError *qerror); +int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret); + +int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret); + #endif /* !MONITOR_H */ diff --git a/qapi-schema.json b/qapi-schema.json index 7c979b2921..44cf764ec3 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1216,3 +1216,62 @@ { 'command': 'qom-list', 'data': { 'path': 'str' }, 'returns': [ 'DevicePropertyInfo' ] } + +## +# @qom-get: +# +# This command will get a property from a device model path and return the +# value. +# +# @path: The path within the device model. There are two forms of supported +# paths--absolute and partial paths. +# +# Absolute paths are derived from the root device and can follow child<> +# or link<> properties. Since they can follow link<> properties, they +# can be arbitrarily long. Absolute paths look like absolute filenames +# and are prefixed with a leading slash. +# +# Partial paths look like relative filenames. They do not begin +# with a prefix. The matching rules for partial paths are subtle but +# designed to make specifying devices easy. At each level of the +# composition tree, the partial path is matched as an absolute path. +# The first match is not returned. At least two matches are searched +# for. A successful result is only returned if only one match is +# found. If more than one match is found, a flag is return to +# indicate that the match was ambiguous. +# +# @property: The property name to read +# +# Returns: The property value. The type depends on the property type. legacy<> +# properties are returned as #str. child<> and link<> properties are +# returns as #str pathnames. All integer property types (u8, u16, etc) +# are returned as #int. +# +# Since: 1.1 +# +# Notes: This command is experimental and may change syntax in future releases. +## +{ 'command': 'qom-get', + 'data': { 'path': 'str', 'property': 'str' }, + 'returns': 'visitor', + 'gen': 'no' } + +## +# @qom-set: +# +# This command will set a property from a device model path. +# +# @path: see @qom-get for a description of this parameter +# +# @property: the property name to set +# +# @value: a value who's type is appropriate for the property type. See @qom-get +# for a description of type mapping. +# +# Since: 1.1 +# +# Notes: This command is experimental and may change syntax in future releases. +## +{ 'command': 'qom-set', + 'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' }, + 'gen': 'no' } diff --git a/qmp-commands.hx b/qmp-commands.hx index c1f0718eff..7e3f4b9a59 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2015,3 +2015,15 @@ EQMP .args_type = "path:s", .mhandler.cmd_new = qmp_marshal_input_qom_list, }, + + { + .name = "qom-set", + .args_type = "path:s,property:s,opts:O", + .mhandler.cmd_new = qmp_qom_set, + }, + + { + .name = "qom-get", + .args_type = "path:s,property:s", + .mhandler.cmd_new = qmp_qom_get, + }, diff --git a/qmp.c b/qmp.c index 8e9a595398..5e09b4189e 100644 --- a/qmp.c +++ b/qmp.c @@ -17,6 +17,8 @@ #include "kvm.h" #include "arch_init.h" #include "hw/qdev.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" NameInfo *qmp_query_name(Error **errp) { @@ -182,3 +184,66 @@ DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp) return props; } + +/* FIXME: teach qapi about how to pass through Visitors */ +int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret) +{ + const char *path = qdict_get_str(qdict, "path"); + const char *property = qdict_get_str(qdict, "property"); + QObject *value = qdict_get(qdict, "value"); + Error *local_err = NULL; + QmpInputVisitor *mi; + DeviceState *dev; + + dev = qdev_resolve_path(path, NULL); + if (!dev) { + error_set(&local_err, QERR_DEVICE_NOT_FOUND, path); + goto out; + } + + mi = qmp_input_visitor_new(value); + qdev_property_set(dev, qmp_input_get_visitor(mi), property, &local_err); + + qmp_input_visitor_cleanup(mi); + +out: + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + + return 0; +} + +int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret) +{ + const char *path = qdict_get_str(qdict, "path"); + const char *property = qdict_get_str(qdict, "property"); + Error *local_err = NULL; + QmpOutputVisitor *mo; + DeviceState *dev; + + dev = qdev_resolve_path(path, NULL); + if (!dev) { + error_set(&local_err, QERR_DEVICE_NOT_FOUND, path); + goto out; + } + + mo = qmp_output_visitor_new(); + qdev_property_get(dev, qmp_output_get_visitor(mo), property, &local_err); + if (!local_err) { + *ret = qmp_output_get_qobject(mo); + } + + qmp_output_visitor_cleanup(mo); + +out: + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + + return 0; +}