X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qmp.c;h=4c149b33a459af7d3cb8da25c057298d9fd6fdcf;hb=30c367ed446b6ea53245589a5cf373578ac075d7;hp=9c9ea629ede67fa7c868337a3be072707bc9ae0c;hpb=903a881481745584b538591ea4db92bca7156956;p=qemu.git diff --git a/qmp.c b/qmp.c index 9c9ea629e..4c149b33a 100644 --- a/qmp.c +++ b/qmp.c @@ -14,15 +14,17 @@ */ #include "qemu-common.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "qmp-commands.h" +#include "sysemu/char.h" #include "ui/qemu-spice.h" #include "ui/vnc.h" -#include "kvm.h" -#include "arch_init.h" +#include "sysemu/kvm.h" +#include "sysemu/arch_init.h" #include "hw/qdev.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/qmp-output-visitor.h" +#include "sysemu/blockdev.h" +#include "qom/qom-qobject.h" +#include "hw/boards.h" NameInfo *qmp_query_name(Error **errp) { @@ -85,7 +87,11 @@ void qmp_quit(Error **err) void qmp_stop(Error **errp) { - vm_stop(RUN_STATE_PAUSED); + if (runstate_check(RUN_STATE_INMIGRATE)) { + autostart = 0; + } else { + vm_stop(RUN_STATE_PAUSED); + } } void qmp_system_reset(Error **errp) @@ -103,6 +109,15 @@ void qmp_cpu(int64_t index, Error **errp) /* Just do nothing */ } +void qmp_cpu_add(int64_t id, Error **errp) +{ + if (current_machine->hot_add_cpu) { + current_machine->hot_add_cpu(id, errp); + } else { + error_setg(errp, "Not supported"); + } +} + #ifndef CONFIG_VNC /* If VNC support is enabled, the "true" query-vnc command is defined in the VNC subsystem */ @@ -144,13 +159,11 @@ 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)) { + if (runstate_needs_reset()) { error_set(errp, QERR_RESET_REQUIRED); return; + } else if (runstate_check(RUN_STATE_SUSPENDED)) { + return; } bdrv_iterate(iostatus_bdrv_it, NULL); @@ -160,26 +173,35 @@ void qmp_cont(Error **errp) return; } - vm_start(); + if (runstate_check(RUN_STATE_INMIGRATE)) { + autostart = 1; + } else { + vm_start(); + } +} + +void qmp_system_wakeup(Error **errp) +{ + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); } -DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp) +ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) { - DeviceState *dev; + Object *obj; bool ambiguous = false; - DevicePropertyInfoList *props = NULL; - DeviceProperty *prop; + ObjectPropertyInfoList *props = NULL; + ObjectProperty *prop; - dev = qdev_resolve_path(path, &ambiguous); - if (dev == NULL) { + obj = object_resolve_path(path, &ambiguous); + if (obj == NULL) { error_set(errp, QERR_DEVICE_NOT_FOUND, path); return NULL; } - QTAILQ_FOREACH(prop, &dev->properties, node) { - DevicePropertyInfoList *entry = g_malloc0(sizeof(*entry)); + QTAILQ_FOREACH(prop, &obj->properties, node) { + ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry)); - entry->value = g_malloc0(sizeof(DevicePropertyInfo)); + entry->value = g_malloc0(sizeof(ObjectPropertyInfo)); entry->next = props; props = entry; @@ -197,19 +219,15 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret) const char *property = qdict_get_str(qdict, "property"); QObject *value = qdict_get(qdict, "value"); Error *local_err = NULL; - QmpInputVisitor *mi; - DeviceState *dev; + Object *obj; - dev = qdev_resolve_path(path, NULL); - if (!dev) { + obj = object_resolve_path(path, NULL); + if (!obj) { 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); + object_property_set_qobject(obj, value, property, &local_err); out: if (local_err) { @@ -226,22 +244,15 @@ 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; + Object *obj; - dev = qdev_resolve_path(path, NULL); - if (!dev) { + obj = object_resolve_path(path, NULL); + if (!obj) { 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); + *ret = object_property_get_qobject(obj, property, &local_err); out: if (local_err) { @@ -345,9 +356,176 @@ void qmp_expire_password(const char *protocol, const char *whenstr, 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 **errp) +{ + vnc_display_open(NULL, target, errp); +} + +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 *qmp_query_cpu_definitions(Error **errp) +{ + return arch_query_cpu_definitions(errp); +} + +void qmp_add_client(const char *protocol, const char *fdname, + bool has_skipauth, bool skipauth, bool has_tls, bool tls, + Error **errp) +{ + CharDriverState *s; + int fd; + + fd = monitor_get_fd(cur_mon, fdname, errp); + if (fd < 0) { + return; + } + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice"); + close(fd); + return; + } + skipauth = has_skipauth ? skipauth : false; + tls = has_tls ? tls : false; + if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) { + error_setg(errp, "spice failed to add client"); + close(fd); + } + return; +#ifdef CONFIG_VNC + } else if (strcmp(protocol, "vnc") == 0) { + skipauth = has_skipauth ? skipauth : false; + vnc_display_add_client(NULL, fd, skipauth); + return; +#endif + } else if ((s = qemu_chr_find(protocol)) != NULL) { + if (qemu_chr_add_client(s, fd) < 0) { + error_setg(errp, "failed to add client"); + close(fd); + return; + } + return; + } + + error_setg(errp, "protocol '%s' is invalid", protocol); + close(fd); +}