diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-11-06 07:50:24 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-11-06 07:50:24 -0800 |
commit | 060629c6ef0b7e5c267d84c91600113264d33120 (patch) | |
tree | 18fcb144ac71b9c4d08ee5d1dc58e2b16c109a5a /qmp.c | |
download | qemu-060629c6ef0b7e5c267d84c91600113264d33120.tar.gz qemu-060629c6ef0b7e5c267d84c91600113264d33120.tar.bz2 qemu-060629c6ef0b7e5c267d84c91600113264d33120.zip |
Imported Upstream version 1.2.0upstream/1.2.0
Diffstat (limited to 'qmp.c')
-rw-r--r-- | qmp.c | 481 |
1 files changed, 481 insertions, 0 deletions
@@ -0,0 +1,481 @@ +/* + * QEMU Management Protocol + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu-common.h" +#include "sysemu.h" +#include "qmp-commands.h" +#include "ui/qemu-spice.h" +#include "ui/vnc.h" +#include "kvm.h" +#include "arch_init.h" +#include "hw/qdev.h" +#include "blockdev.h" +#include "qemu/qom-qobject.h" + +NameInfo *qmp_query_name(Error **errp) +{ + NameInfo *info = g_malloc0(sizeof(*info)); + + if (qemu_name) { + info->has_name = true; + info->name = g_strdup(qemu_name); + } + + return info; +} + +VersionInfo *qmp_query_version(Error **err) +{ + VersionInfo *info = g_malloc0(sizeof(*info)); + const char *version = QEMU_VERSION; + char *tmp; + + info->qemu.major = strtol(version, &tmp, 10); + tmp++; + info->qemu.minor = strtol(tmp, &tmp, 10); + tmp++; + info->qemu.micro = strtol(tmp, &tmp, 10); + info->package = g_strdup(QEMU_PKGVERSION); + + return info; +} + +KvmInfo *qmp_query_kvm(Error **errp) +{ + KvmInfo *info = g_malloc0(sizeof(*info)); + + info->enabled = kvm_enabled(); + info->present = kvm_available(); + + return info; +} + +UuidInfo *qmp_query_uuid(Error **errp) +{ + UuidInfo *info = g_malloc0(sizeof(*info)); + char uuid[64]; + + snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1], + qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], + qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], + qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], + qemu_uuid[14], qemu_uuid[15]); + + info->UUID = g_strdup(uuid); + return info; +} + +void qmp_quit(Error **err) +{ + no_shutdown = 0; + qemu_system_shutdown_request(); +} + +void qmp_stop(Error **errp) +{ + vm_stop(RUN_STATE_PAUSED); +} + +void qmp_system_reset(Error **errp) +{ + qemu_system_reset_request(); +} + +void qmp_system_powerdown(Error **erp) +{ + qemu_system_powerdown_request(); +} + +void qmp_cpu(int64_t index, Error **errp) +{ + /* Just do nothing */ +} + +#ifndef CONFIG_VNC +/* If VNC support is enabled, the "true" query-vnc command is + defined in the VNC subsystem */ +VncInfo *qmp_query_vnc(Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "vnc"); + return NULL; +}; +#endif + +#ifndef CONFIG_SPICE +/* If SPICE support is enabled, the "true" query-spice command is + defined in the SPICE subsystem. Also note that we use a small + trick to maintain query-spice's original behavior, which is not + to be available in the namespace if SPICE is not compiled in */ +SpiceInfo *qmp_query_spice(Error **errp) +{ + error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice"); + return NULL; +}; +#endif + +static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs) +{ + bdrv_iostatus_reset(bs); +} + +static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs) +{ + Error **err = opaque; + + if (!error_is_set(err) && bdrv_key_required(bs)) { + error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs), + bdrv_get_encrypted_filename(bs)); + } +} + +void qmp_cont(Error **errp) +{ + Error *local_err = NULL; + + if (runstate_check(RUN_STATE_INMIGRATE)) { + error_set(errp, QERR_MIGRATION_EXPECTED); + return; + } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) || + runstate_check(RUN_STATE_SHUTDOWN)) { + error_set(errp, QERR_RESET_REQUIRED); + return; + } else if (runstate_check(RUN_STATE_SUSPENDED)) { + return; + } + + bdrv_iterate(iostatus_bdrv_it, NULL); + bdrv_iterate(encrypted_bdrv_it, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + vm_start(); +} + +void qmp_system_wakeup(Error **errp) +{ + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); +} + +ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) +{ + Object *obj; + bool ambiguous = false; + ObjectPropertyInfoList *props = NULL; + ObjectProperty *prop; + + obj = object_resolve_path(path, &ambiguous); + if (obj == NULL) { + error_set(errp, QERR_DEVICE_NOT_FOUND, path); + return NULL; + } + + QTAILQ_FOREACH(prop, &obj->properties, node) { + ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry)); + + entry->value = g_malloc0(sizeof(ObjectPropertyInfo)); + entry->next = props; + props = entry; + + entry->value->name = g_strdup(prop->name); + entry->value->type = g_strdup(prop->type); + } + + 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; + Object *obj; + + obj = object_resolve_path(path, NULL); + if (!obj) { + error_set(&local_err, QERR_DEVICE_NOT_FOUND, path); + goto out; + } + + object_property_set_qobject(obj, value, property, &local_err); + +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; + Object *obj; + + obj = object_resolve_path(path, NULL); + if (!obj) { + error_set(&local_err, QERR_DEVICE_NOT_FOUND, path); + goto out; + } + + *ret = object_property_get_qobject(obj, property, &local_err); + +out: + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + + return 0; +} + +void qmp_set_password(const char *protocol, const char *password, + bool has_connected, const char *connected, Error **errp) +{ + int disconnect_if_connected = 0; + int fail_if_connected = 0; + int rc; + + if (has_connected) { + if (strcmp(connected, "fail") == 0) { + fail_if_connected = 1; + } else if (strcmp(connected, "disconnect") == 0) { + disconnect_if_connected = 1; + } else if (strcmp(connected, "keep") == 0) { + /* nothing */ + } else { + error_set(errp, QERR_INVALID_PARAMETER, "connected"); + return; + } + } + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice"); + return; + } + rc = qemu_spice_set_passwd(password, fail_if_connected, + disconnect_if_connected); + if (rc != 0) { + error_set(errp, QERR_SET_PASSWD_FAILED); + } + return; + } + + if (strcmp(protocol, "vnc") == 0) { + if (fail_if_connected || disconnect_if_connected) { + /* vnc supports "connected=keep" only */ + error_set(errp, QERR_INVALID_PARAMETER, "connected"); + return; + } + /* Note that setting an empty password will not disable login through + * this interface. */ + rc = vnc_display_password(NULL, password); + if (rc < 0) { + error_set(errp, QERR_SET_PASSWD_FAILED); + } + return; + } + + error_set(errp, QERR_INVALID_PARAMETER, "protocol"); +} + +void qmp_expire_password(const char *protocol, const char *whenstr, + Error **errp) +{ + time_t when; + int rc; + + if (strcmp(whenstr, "now") == 0) { + when = 0; + } else if (strcmp(whenstr, "never") == 0) { + when = TIME_MAX; + } else if (whenstr[0] == '+') { + when = time(NULL) + strtoull(whenstr+1, NULL, 10); + } else { + when = strtoull(whenstr, NULL, 10); + } + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice"); + return; + } + rc = qemu_spice_set_pw_expire(when); + if (rc != 0) { + error_set(errp, QERR_SET_PASSWD_FAILED); + } + return; + } + + if (strcmp(protocol, "vnc") == 0) { + rc = vnc_display_pw_expire(NULL, when); + if (rc != 0) { + error_set(errp, QERR_SET_PASSWD_FAILED); + } + return; + } + + error_set(errp, QERR_INVALID_PARAMETER, "protocol"); +} + +#ifdef CONFIG_VNC +void qmp_change_vnc_password(const char *password, Error **errp) +{ + if (vnc_display_password(NULL, password) < 0) { + error_set(errp, QERR_SET_PASSWD_FAILED); + } +} + +static void qmp_change_vnc_listen(const char *target, Error **err) +{ + if (vnc_display_open(NULL, target) < 0) { + error_set(err, QERR_VNC_SERVER_FAILED, target); + } +} + +static void qmp_change_vnc(const char *target, bool has_arg, const char *arg, + Error **errp) +{ + if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) { + if (!has_arg) { + error_set(errp, QERR_MISSING_PARAMETER, "password"); + } else { + qmp_change_vnc_password(arg, errp); + } + } else { + qmp_change_vnc_listen(target, errp); + } +} +#else +void qmp_change_vnc_password(const char *password, Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "vnc"); +} +static void qmp_change_vnc(const char *target, bool has_arg, const char *arg, + Error **errp) +{ + error_set(errp, QERR_FEATURE_DISABLED, "vnc"); +} +#endif /* !CONFIG_VNC */ + +void qmp_change(const char *device, const char *target, + bool has_arg, const char *arg, Error **err) +{ + if (strcmp(device, "vnc") == 0) { + qmp_change_vnc(target, has_arg, arg, err); + } else { + qmp_change_blockdev(device, target, has_arg, arg, err); + } +} + +static void qom_list_types_tramp(ObjectClass *klass, void *data) +{ + ObjectTypeInfoList *e, **pret = data; + ObjectTypeInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(object_class_get_name(klass)); + + e = g_malloc0(sizeof(*e)); + e->value = info; + e->next = *pret; + *pret = e; +} + +ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, + const char *implements, + bool has_abstract, + bool abstract, + Error **errp) +{ + ObjectTypeInfoList *ret = NULL; + + object_class_foreach(qom_list_types_tramp, implements, abstract, &ret); + + return ret; +} + +DevicePropertyInfoList *qmp_device_list_properties(const char *typename, + Error **errp) +{ + ObjectClass *klass; + Property *prop; + DevicePropertyInfoList *prop_list = NULL; + + klass = object_class_by_name(typename); + if (klass == NULL) { + error_set(errp, QERR_DEVICE_NOT_FOUND, typename); + return NULL; + } + + klass = object_class_dynamic_cast(klass, TYPE_DEVICE); + if (klass == NULL) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + "name", TYPE_DEVICE); + return NULL; + } + + do { + for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) { + DevicePropertyInfoList *entry; + DevicePropertyInfo *info; + + /* + * TODO Properties without a parser are just for dirty hacks. + * qdev_prop_ptr is the only such PropertyInfo. It's marked + * for removal. This conditional should be removed along with + * it. + */ + if (!prop->info->set) { + continue; /* no way to set it, don't show */ + } + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(prop->name); + info->type = g_strdup(prop->info->legacy_name ?: prop->info->name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = prop_list; + prop_list = entry; + } + klass = object_class_get_parent(klass); + } while (klass != object_class_by_name(TYPE_DEVICE)); + + return prop_list; +} + +CpuDefinitionInfoList GCC_WEAK *arch_query_cpu_definitions(Error **errp) +{ + error_set(errp, QERR_NOT_SUPPORTED); + return NULL; +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + return arch_query_cpu_definitions(errp); +} + |