/* * QEMU Management Protocol commands * * Copyright IBM, Corp. 2011 * * Authors: * Anthony Liguori * * 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/sockets.h" #include "monitor-internal.h" #include "monitor/qdev.h" #include "monitor/qmp-helpers.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "sysemu/runstate.h" #include "sysemu/runstate-action.h" #include "sysemu/block-backend.h" #include "qapi/error.h" #include "qapi/qapi-init-commands.h" #include "qapi/qapi-commands-control.h" #include "qapi/qapi-commands-misc.h" #include "qapi/qmp/qerror.h" #include "qapi/type-helpers.h" #include "hw/mem/memory-device.h" #include "hw/intc/intc.h" NameInfo *qmp_query_name(Error **errp) { NameInfo *info = g_malloc0(sizeof(*info)); info->name = g_strdup(qemu_name); return info; } void qmp_quit(Error **errp) { shutdown_action = SHUTDOWN_ACTION_POWEROFF; 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 (qemu_system_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_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 (qemu_system_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); } WITH_JOB_LOCK_GUARD() { for (job = block_job_next_locked(NULL); job; job = block_job_next_locked(job)) { block_job_iostatus_reset_locked(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_activate_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_add_client(const char *protocol, const char *fdname, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp) { static const struct { const char *name; bool (*add_client)(int fd, bool has_skipauth, bool skipauth, bool has_tls, bool tls, Error **errp); } protocol_table[] = { { "spice", qmp_add_client_spice }, #ifdef CONFIG_VNC { "vnc", qmp_add_client_vnc }, #endif #ifdef CONFIG_DBUS_DISPLAY { "@dbus-display", qmp_add_client_dbus_display }, #endif }; int fd, i; fd = monitor_get_fd(monitor_cur(), fdname, errp); if (fd < 0) { return; } if (!fd_is_socket(fd)) { error_setg(errp, "parameter @fdname must name a socket"); close(fd); return; } for (i = 0; i < ARRAY_SIZE(protocol_table); i++) { if (!strcmp(protocol, protocol_table[i].name)) { if (!protocol_table[i].add_client(fd, has_skipauth, skipauth, has_tls, tls, errp)) { close(fd); } return; } } if (!qmp_add_client_char(fd, has_skipauth, skipauth, has_tls, tls, protocol, errp)) { close(fd); } } char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, int64_t cpu_index, Error **errp) { char *output = NULL; MonitorHMP hmp = {}; monitor_data_init(&hmp.common, false, true, false); if (has_cpu_index) { int ret = monitor_set_cpu(&hmp.common, cpu_index); if (ret < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number"); goto out; } } handle_hmp_command(&hmp, command_line); WITH_QEMU_LOCK_GUARD(&hmp.common.mon_lock) { output = g_strdup(hmp.common.outbuf->str); } out: monitor_data_destroy(&hmp.common); return output; } static void __attribute__((__constructor__)) monitor_init_qmp_commands(void) { /* * Two command lists: * - qmp_commands contains all QMP commands * - qmp_cap_negotiation_commands contains just * "qmp_capabilities", to enforce capability negotiation */ qmp_init_marshal(&qmp_commands); qmp_register_command(&qmp_commands, "device_add", qmp_device_add, 0, 0); QTAILQ_INIT(&qmp_cap_negotiation_commands); qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities", qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG, 0); }