123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- /*
- * QEMU Management Protocol commands
- *
- * 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/osdep.h"
- #include "qemu-common.h"
- #include "qemu/cutils.h"
- #include "qemu/option.h"
- #include "monitor/monitor.h"
- #include "sysemu/sysemu.h"
- #include "qemu/config-file.h"
- #include "qemu/uuid.h"
- #include "chardev/char.h"
- #include "ui/qemu-spice.h"
- #include "ui/vnc.h"
- #include "sysemu/kvm.h"
- #include "sysemu/runstate.h"
- #include "sysemu/arch_init.h"
- #include "sysemu/blockdev.h"
- #include "sysemu/block-backend.h"
- #include "qapi/error.h"
- #include "qapi/qapi-commands-acpi.h"
- #include "qapi/qapi-commands-block.h"
- #include "qapi/qapi-commands-control.h"
- #include "qapi/qapi-commands-machine.h"
- #include "qapi/qapi-commands-misc.h"
- #include "qapi/qapi-commands-ui.h"
- #include "qapi/qmp/qerror.h"
- #include "hw/mem/memory-device.h"
- #include "hw/acpi/acpi_dev_interface.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;
- }
- 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));
- info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid);
- return info;
- }
- void qmp_quit(Error **errp)
- {
- no_shutdown = 0;
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT);
- }
- void qmp_stop(Error **errp)
- {
- /* if there is a dump in background, we should wait until the dump
- * finished */
- if (dump_in_progress()) {
- error_setg(errp, "There is a dump in process, please wait.");
- return;
- }
- if (runstate_check(RUN_STATE_INMIGRATE)) {
- autostart = 0;
- } else {
- vm_stop(RUN_STATE_PAUSED);
- }
- }
- void qmp_system_reset(Error **errp)
- {
- qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET);
- }
- void qmp_system_powerdown(Error **errp)
- {
- qemu_system_powerdown_request();
- }
- void qmp_x_exit_preconfig(Error **errp)
- {
- if (!runstate_check(RUN_STATE_PRECONFIG)) {
- error_setg(errp, "The command is permitted only in '%s' state",
- RunState_str(RUN_STATE_PRECONFIG));
- return;
- }
- qemu_exit_preconfig_request();
- }
- void qmp_cont(Error **errp)
- {
- BlockBackend *blk;
- BlockJob *job;
- Error *local_err = NULL;
- /* if there is a dump in background, we should wait until the dump
- * finished */
- if (dump_in_progress()) {
- error_setg(errp, "There is a dump in process, please wait.");
- return;
- }
- if (runstate_needs_reset()) {
- error_setg(errp, "Resetting the Virtual Machine is required");
- return;
- } else if (runstate_check(RUN_STATE_SUSPENDED)) {
- return;
- } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
- error_setg(errp, "Migration is not finalized yet");
- return;
- }
- for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
- blk_iostatus_reset(blk);
- }
- for (job = block_job_next(NULL); job; job = block_job_next(job)) {
- block_job_iostatus_reset(job);
- }
- /* Continuing after completed migration. Images have been inactivated to
- * allow the destination to take control. Need to get control back now.
- *
- * If there are no inactive block nodes (e.g. because the VM was just
- * paused rather than completing a migration), bdrv_inactivate_all() simply
- * doesn't do anything. */
- bdrv_invalidate_cache_all(&local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- if (runstate_check(RUN_STATE_INMIGRATE)) {
- autostart = 1;
- } else {
- vm_start();
- }
- }
- void qmp_system_wakeup(Error **errp)
- {
- if (!qemu_wakeup_suspend_enabled()) {
- error_setg(errp,
- "wake-up from suspend is not supported by this guest");
- return;
- }
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp);
- }
- 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_setg(errp, QERR_INVALID_PARAMETER, "connected");
- return;
- }
- }
- if (strcmp(protocol, "spice") == 0) {
- if (!qemu_using_spice(errp)) {
- return;
- }
- rc = qemu_spice_set_passwd(password, fail_if_connected,
- disconnect_if_connected);
- if (rc != 0) {
- error_setg(errp, QERR_SET_PASSWD_FAILED);
- }
- return;
- }
- if (strcmp(protocol, "vnc") == 0) {
- if (fail_if_connected || disconnect_if_connected) {
- /* vnc supports "connected=keep" only */
- error_setg(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_setg(errp, QERR_SET_PASSWD_FAILED);
- }
- return;
- }
- error_setg(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 (!qemu_using_spice(errp)) {
- return;
- }
- rc = qemu_spice_set_pw_expire(when);
- if (rc != 0) {
- error_setg(errp, QERR_SET_PASSWD_FAILED);
- }
- return;
- }
- if (strcmp(protocol, "vnc") == 0) {
- rc = vnc_display_pw_expire(NULL, when);
- if (rc != 0) {
- error_setg(errp, QERR_SET_PASSWD_FAILED);
- }
- return;
- }
- error_setg(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_setg(errp, QERR_SET_PASSWD_FAILED);
- }
- }
- static void qmp_change_vnc_listen(const char *target, Error **errp)
- {
- QemuOptsList *olist = qemu_find_opts("vnc");
- QemuOpts *opts;
- if (strstr(target, "id=")) {
- error_setg(errp, "id not supported");
- return;
- }
- opts = qemu_opts_find(olist, "default");
- if (opts) {
- qemu_opts_del(opts);
- }
- opts = vnc_parse(target, errp);
- if (!opts) {
- return;
- }
- vnc_display_open("default", 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_setg(errp, QERR_MISSING_PARAMETER, "password");
- } else {
- qmp_change_vnc_password(arg, errp);
- }
- } else {
- qmp_change_vnc_listen(target, errp);
- }
- }
- #endif /* !CONFIG_VNC */
- void qmp_change(const char *device, const char *target,
- bool has_arg, const char *arg, Error **errp)
- {
- if (strcmp(device, "vnc") == 0) {
- #ifdef CONFIG_VNC
- qmp_change_vnc(target, has_arg, arg, errp);
- #else
- error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
- #endif
- } else {
- qmp_blockdev_change_medium(true, device, false, NULL, target,
- has_arg, arg, false, 0, errp);
- }
- }
- void qmp_add_client(const char *protocol, const char *fdname,
- bool has_skipauth, bool skipauth, bool has_tls, bool tls,
- Error **errp)
- {
- Chardev *s;
- int fd;
- fd = monitor_get_fd(monitor_cur(), fdname, errp);
- if (fd < 0) {
- return;
- }
- if (strcmp(protocol, "spice") == 0) {
- if (!qemu_using_spice(errp)) {
- 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);
- }
- MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
- {
- return qmp_memory_device_list();
- }
- ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp)
- {
- bool ambig;
- ACPIOSTInfoList *head = NULL;
- ACPIOSTInfoList **prev = &head;
- Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig);
- if (obj) {
- AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
- AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
- adevc->ospm_status(adev, &prev);
- } else {
- error_setg(errp, "command is not supported, missing ACPI device");
- }
- return head;
- }
- MemoryInfo *qmp_query_memory_size_summary(Error **errp)
- {
- MemoryInfo *mem_info = g_malloc0(sizeof(MemoryInfo));
- mem_info->base_memory = ram_size;
- mem_info->plugged_memory = get_plugged_memory_size();
- mem_info->has_plugged_memory =
- mem_info->plugged_memory != (uint64_t)-1;
- return mem_info;
- }
|