mirror of https://github.com/xemu-project/xemu.git
ui: Move HMP commands from monitor to new ui/ui-hmp-cmds.c
This moves these commands from MAINTAINERS section "Human Monitor (HMP)" to "Graphics". Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20230109190321.1056914-12-armbru@redhat.com>
This commit is contained in:
parent
3125af295e
commit
5011d262f0
|
@ -81,6 +81,8 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
|
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_getfd(Monitor *mon, const QDict *qdict);
|
void hmp_getfd(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_closefd(Monitor *mon, const QDict *qdict);
|
void hmp_closefd(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_mouse_move(Monitor *mon, const QDict *qdict);
|
||||||
|
void hmp_mouse_button(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_sendkey(Monitor *mon, const QDict *qdict);
|
void hmp_sendkey(Monitor *mon, const QDict *qdict);
|
||||||
void coroutine_fn hmp_screendump(Monitor *mon, const QDict *qdict);
|
void coroutine_fn hmp_screendump(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_chardev_add(Monitor *mon, const QDict *qdict);
|
void hmp_chardev_add(Monitor *mon, const QDict *qdict);
|
||||||
|
|
|
@ -51,7 +51,6 @@
|
||||||
#include "qapi/string-input-visitor.h"
|
#include "qapi/string-input-visitor.h"
|
||||||
#include "qapi/string-output-visitor.h"
|
#include "qapi/string-output-visitor.h"
|
||||||
#include "qom/object_interfaces.h"
|
#include "qom/object_interfaces.h"
|
||||||
#include "ui/console.h"
|
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
@ -59,10 +58,6 @@
|
||||||
#include "migration/snapshot.h"
|
#include "migration/snapshot.h"
|
||||||
#include "migration/misc.h"
|
#include "migration/misc.h"
|
||||||
|
|
||||||
#ifdef CONFIG_SPICE
|
|
||||||
#include <spice/enums.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool hmp_handle_error(Monitor *mon, Error *err)
|
bool hmp_handle_error(Monitor *mon, Error *err)
|
||||||
{
|
{
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -178,26 +173,6 @@ void hmp_info_chardev(Monitor *mon, const QDict *qdict)
|
||||||
qapi_free_ChardevInfoList(char_info);
|
qapi_free_ChardevInfoList(char_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
MouseInfoList *mice_list, *mouse;
|
|
||||||
|
|
||||||
mice_list = qmp_query_mice(NULL);
|
|
||||||
if (!mice_list) {
|
|
||||||
monitor_printf(mon, "No mouse devices connected\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (mouse = mice_list; mouse; mouse = mouse->next) {
|
|
||||||
monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
|
|
||||||
mouse->value->current ? '*' : ' ',
|
|
||||||
mouse->value->index, mouse->value->name,
|
|
||||||
mouse->value->absolute ? " (absolute)" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
qapi_free_MouseInfoList(mice_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
MigrationInfo *info;
|
MigrationInfo *info;
|
||||||
|
@ -516,168 +491,6 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
|
||||||
qapi_free_MigrationParameters(params);
|
qapi_free_MigrationParameters(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_VNC
|
|
||||||
/* Helper for hmp_info_vnc_clients, _servers */
|
|
||||||
static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
monitor_printf(mon, " %s: %s:%s (%s%s)\n",
|
|
||||||
name,
|
|
||||||
info->host,
|
|
||||||
info->service,
|
|
||||||
NetworkAddressFamily_str(info->family),
|
|
||||||
info->websocket ? " (Websocket)" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helper displaying and auth and crypt info */
|
|
||||||
static void hmp_info_vnc_authcrypt(Monitor *mon, const char *indent,
|
|
||||||
VncPrimaryAuth auth,
|
|
||||||
VncVencryptSubAuth *vencrypt)
|
|
||||||
{
|
|
||||||
monitor_printf(mon, "%sAuth: %s (Sub: %s)\n", indent,
|
|
||||||
VncPrimaryAuth_str(auth),
|
|
||||||
vencrypt ? VncVencryptSubAuth_str(*vencrypt) : "none");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmp_info_vnc_clients(Monitor *mon, VncClientInfoList *client)
|
|
||||||
{
|
|
||||||
while (client) {
|
|
||||||
VncClientInfo *cinfo = client->value;
|
|
||||||
|
|
||||||
hmp_info_VncBasicInfo(mon, qapi_VncClientInfo_base(cinfo), "Client");
|
|
||||||
monitor_printf(mon, " x509_dname: %s\n",
|
|
||||||
cinfo->x509_dname ?: "none");
|
|
||||||
monitor_printf(mon, " sasl_username: %s\n",
|
|
||||||
cinfo->sasl_username ?: "none");
|
|
||||||
|
|
||||||
client = client->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server)
|
|
||||||
{
|
|
||||||
while (server) {
|
|
||||||
VncServerInfo2 *sinfo = server->value;
|
|
||||||
hmp_info_VncBasicInfo(mon, qapi_VncServerInfo2_base(sinfo), "Server");
|
|
||||||
hmp_info_vnc_authcrypt(mon, " ", sinfo->auth,
|
|
||||||
sinfo->has_vencrypt ? &sinfo->vencrypt : NULL);
|
|
||||||
server = server->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmp_info_vnc(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
VncInfo2List *info2l, *info2l_head;
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
info2l = qmp_query_vnc_servers(&err);
|
|
||||||
info2l_head = info2l;
|
|
||||||
if (hmp_handle_error(mon, err)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!info2l) {
|
|
||||||
monitor_printf(mon, "None\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (info2l) {
|
|
||||||
VncInfo2 *info = info2l->value;
|
|
||||||
monitor_printf(mon, "%s:\n", info->id);
|
|
||||||
hmp_info_vnc_servers(mon, info->server);
|
|
||||||
hmp_info_vnc_clients(mon, info->clients);
|
|
||||||
if (!info->server) {
|
|
||||||
/*
|
|
||||||
* The server entry displays its auth, we only need to
|
|
||||||
* display in the case of 'reverse' connections where
|
|
||||||
* there's no server.
|
|
||||||
*/
|
|
||||||
hmp_info_vnc_authcrypt(mon, " ", info->auth,
|
|
||||||
info->has_vencrypt ? &info->vencrypt : NULL);
|
|
||||||
}
|
|
||||||
if (info->display) {
|
|
||||||
monitor_printf(mon, " Display: %s\n", info->display);
|
|
||||||
}
|
|
||||||
info2l = info2l->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
qapi_free_VncInfo2List(info2l_head);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_SPICE
|
|
||||||
void hmp_info_spice(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
SpiceChannelList *chan;
|
|
||||||
SpiceInfo *info;
|
|
||||||
const char *channel_name;
|
|
||||||
static const char *const channel_names[] = {
|
|
||||||
[SPICE_CHANNEL_MAIN] = "main",
|
|
||||||
[SPICE_CHANNEL_DISPLAY] = "display",
|
|
||||||
[SPICE_CHANNEL_INPUTS] = "inputs",
|
|
||||||
[SPICE_CHANNEL_CURSOR] = "cursor",
|
|
||||||
[SPICE_CHANNEL_PLAYBACK] = "playback",
|
|
||||||
[SPICE_CHANNEL_RECORD] = "record",
|
|
||||||
[SPICE_CHANNEL_TUNNEL] = "tunnel",
|
|
||||||
[SPICE_CHANNEL_SMARTCARD] = "smartcard",
|
|
||||||
[SPICE_CHANNEL_USBREDIR] = "usbredir",
|
|
||||||
[SPICE_CHANNEL_PORT] = "port",
|
|
||||||
[SPICE_CHANNEL_WEBDAV] = "webdav",
|
|
||||||
};
|
|
||||||
|
|
||||||
info = qmp_query_spice(NULL);
|
|
||||||
|
|
||||||
if (!info->enabled) {
|
|
||||||
monitor_printf(mon, "Server: disabled\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor_printf(mon, "Server:\n");
|
|
||||||
if (info->has_port) {
|
|
||||||
monitor_printf(mon, " address: %s:%" PRId64 "\n",
|
|
||||||
info->host, info->port);
|
|
||||||
}
|
|
||||||
if (info->has_tls_port) {
|
|
||||||
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
|
||||||
info->host, info->tls_port);
|
|
||||||
}
|
|
||||||
monitor_printf(mon, " migrated: %s\n",
|
|
||||||
info->migrated ? "true" : "false");
|
|
||||||
monitor_printf(mon, " auth: %s\n", info->auth);
|
|
||||||
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
|
||||||
monitor_printf(mon, " mouse-mode: %s\n",
|
|
||||||
SpiceQueryMouseMode_str(info->mouse_mode));
|
|
||||||
|
|
||||||
if (!info->has_channels || info->channels == NULL) {
|
|
||||||
monitor_printf(mon, "Channels: none\n");
|
|
||||||
} else {
|
|
||||||
for (chan = info->channels; chan; chan = chan->next) {
|
|
||||||
monitor_printf(mon, "Channel:\n");
|
|
||||||
monitor_printf(mon, " address: %s:%s%s\n",
|
|
||||||
chan->value->host, chan->value->port,
|
|
||||||
chan->value->tls ? " [tls]" : "");
|
|
||||||
monitor_printf(mon, " session: %" PRId64 "\n",
|
|
||||||
chan->value->connection_id);
|
|
||||||
monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n",
|
|
||||||
chan->value->channel_type, chan->value->channel_id);
|
|
||||||
|
|
||||||
channel_name = "unknown";
|
|
||||||
if (chan->value->channel_type > 0 &&
|
|
||||||
chan->value->channel_type < ARRAY_SIZE(channel_names) &&
|
|
||||||
channel_names[chan->value->channel_type]) {
|
|
||||||
channel_name = channel_names[chan->value->channel_type];
|
|
||||||
}
|
|
||||||
|
|
||||||
monitor_printf(mon, " channel name: %s\n", channel_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
qapi_free_SpiceInfo(info);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
BalloonInfo *info;
|
BalloonInfo *info;
|
||||||
|
@ -1262,69 +1075,6 @@ void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict)
|
||||||
hmp_handle_error(mon, err);
|
hmp_handle_error(mon, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
||||||
const char *password = qdict_get_str(qdict, "password");
|
|
||||||
const char *display = qdict_get_try_str(qdict, "display");
|
|
||||||
const char *connected = qdict_get_try_str(qdict, "connected");
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
SetPasswordOptions opts = {
|
|
||||||
.password = (char *)password,
|
|
||||||
.has_connected = !!connected,
|
|
||||||
};
|
|
||||||
|
|
||||||
opts.connected = qapi_enum_parse(&SetPasswordAction_lookup, connected,
|
|
||||||
SET_PASSWORD_ACTION_KEEP, &err);
|
|
||||||
if (err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol,
|
|
||||||
DISPLAY_PROTOCOL_VNC, &err);
|
|
||||||
if (err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.protocol == DISPLAY_PROTOCOL_VNC) {
|
|
||||||
opts.u.vnc.display = (char *)display;
|
|
||||||
}
|
|
||||||
|
|
||||||
qmp_set_password(&opts, &err);
|
|
||||||
|
|
||||||
out:
|
|
||||||
hmp_handle_error(mon, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmp_expire_password(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
||||||
const char *whenstr = qdict_get_str(qdict, "time");
|
|
||||||
const char *display = qdict_get_try_str(qdict, "display");
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
ExpirePasswordOptions opts = {
|
|
||||||
.time = (char *)whenstr,
|
|
||||||
};
|
|
||||||
|
|
||||||
opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol,
|
|
||||||
DISPLAY_PROTOCOL_VNC, &err);
|
|
||||||
if (err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.protocol == DISPLAY_PROTOCOL_VNC) {
|
|
||||||
opts.u.vnc.display = (char *)display;
|
|
||||||
}
|
|
||||||
|
|
||||||
qmp_expire_password(&opts, &err);
|
|
||||||
|
|
||||||
out:
|
|
||||||
hmp_handle_error(mon, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_VNC
|
#ifdef CONFIG_VNC
|
||||||
static void hmp_change_read_arg(void *opaque, const char *password,
|
static void hmp_change_read_arg(void *opaque, const char *password,
|
||||||
void *readline_opaque)
|
void *readline_opaque)
|
||||||
|
@ -1521,94 +1271,6 @@ void hmp_closefd(Monitor *mon, const QDict *qdict)
|
||||||
hmp_handle_error(mon, err);
|
hmp_handle_error(mon, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
const char *keys = qdict_get_str(qdict, "keys");
|
|
||||||
KeyValue *v = NULL;
|
|
||||||
KeyValueList *head = NULL, **tail = &head;
|
|
||||||
int has_hold_time = qdict_haskey(qdict, "hold-time");
|
|
||||||
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
|
|
||||||
Error *err = NULL;
|
|
||||||
const char *separator;
|
|
||||||
int keyname_len;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
separator = qemu_strchrnul(keys, '-');
|
|
||||||
keyname_len = separator - keys;
|
|
||||||
|
|
||||||
/* Be compatible with old interface, convert user inputted "<" */
|
|
||||||
if (keys[0] == '<' && keyname_len == 1) {
|
|
||||||
keys = "less";
|
|
||||||
keyname_len = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
v = g_malloc0(sizeof(*v));
|
|
||||||
|
|
||||||
if (strstart(keys, "0x", NULL)) {
|
|
||||||
const char *endp;
|
|
||||||
int value;
|
|
||||||
|
|
||||||
if (qemu_strtoi(keys, &endp, 0, &value) < 0) {
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
assert(endp <= keys + keyname_len);
|
|
||||||
if (endp != keys + keyname_len) {
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
v->type = KEY_VALUE_KIND_NUMBER;
|
|
||||||
v->u.number.data = value;
|
|
||||||
} else {
|
|
||||||
int idx = index_from_key(keys, keyname_len);
|
|
||||||
if (idx == Q_KEY_CODE__MAX) {
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
v->type = KEY_VALUE_KIND_QCODE;
|
|
||||||
v->u.qcode.data = idx;
|
|
||||||
}
|
|
||||||
QAPI_LIST_APPEND(tail, v);
|
|
||||||
v = NULL;
|
|
||||||
|
|
||||||
if (!*separator) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
keys = separator + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qmp_send_key(head, has_hold_time, hold_time, &err);
|
|
||||||
hmp_handle_error(mon, err);
|
|
||||||
|
|
||||||
out:
|
|
||||||
qapi_free_KeyValue(v);
|
|
||||||
qapi_free_KeyValueList(head);
|
|
||||||
return;
|
|
||||||
|
|
||||||
err_out:
|
|
||||||
monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void coroutine_fn
|
|
||||||
hmp_screendump(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
const char *filename = qdict_get_str(qdict, "filename");
|
|
||||||
const char *id = qdict_get_try_str(qdict, "device");
|
|
||||||
int64_t head = qdict_get_try_int(qdict, "head", 0);
|
|
||||||
const char *input_format = qdict_get_try_str(qdict, "format");
|
|
||||||
Error *err = NULL;
|
|
||||||
ImageFormat format;
|
|
||||||
|
|
||||||
format = qapi_enum_parse(&ImageFormat_lookup, input_format,
|
|
||||||
IMAGE_FORMAT_PPM, &err);
|
|
||||||
if (err) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
qmp_screendump(filename, id, id != NULL, head,
|
|
||||||
input_format != NULL, format, &err);
|
|
||||||
end:
|
|
||||||
hmp_handle_error(mon, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmp_chardev_add(Monitor *mon, const QDict *qdict)
|
void hmp_chardev_add(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *args = qdict_get_str(qdict, "args");
|
const char *args = qdict_get_str(qdict, "args");
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/ctype.h"
|
#include "qemu/ctype.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
#include "ui/input.h"
|
|
||||||
#include "audio/audio.h"
|
#include "audio/audio.h"
|
||||||
#include "disas/disas.h"
|
#include "disas/disas.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
|
@ -825,49 +824,6 @@ static void hmp_sum(Monitor *mon, const QDict *qdict)
|
||||||
monitor_printf(mon, "%05d\n", sum);
|
monitor_printf(mon, "%05d\n", sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mouse_button_state;
|
|
||||||
|
|
||||||
static void hmp_mouse_move(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
int dx, dy, dz, button;
|
|
||||||
const char *dx_str = qdict_get_str(qdict, "dx_str");
|
|
||||||
const char *dy_str = qdict_get_str(qdict, "dy_str");
|
|
||||||
const char *dz_str = qdict_get_try_str(qdict, "dz_str");
|
|
||||||
|
|
||||||
dx = strtol(dx_str, NULL, 0);
|
|
||||||
dy = strtol(dy_str, NULL, 0);
|
|
||||||
qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
|
|
||||||
qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
|
|
||||||
|
|
||||||
if (dz_str) {
|
|
||||||
dz = strtol(dz_str, NULL, 0);
|
|
||||||
if (dz != 0) {
|
|
||||||
button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
|
|
||||||
qemu_input_queue_btn(NULL, button, true);
|
|
||||||
qemu_input_event_sync();
|
|
||||||
qemu_input_queue_btn(NULL, button, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qemu_input_event_sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmp_mouse_button(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
static uint32_t bmap[INPUT_BUTTON__MAX] = {
|
|
||||||
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
|
|
||||||
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
|
|
||||||
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
|
|
||||||
};
|
|
||||||
int button_state = qdict_get_int(qdict, "button_state");
|
|
||||||
|
|
||||||
if (mouse_button_state == button_state) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state);
|
|
||||||
qemu_input_event_sync();
|
|
||||||
mouse_button_state = button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmp_ioport_read(Monitor *mon, const QDict *qdict)
|
static void hmp_ioport_read(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
int size = qdict_get_int(qdict, "size");
|
int size = qdict_get_int(qdict, "size");
|
||||||
|
@ -1700,28 +1656,6 @@ void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||||
qapi_free_ObjectPropertyInfoList(start);
|
qapi_free_ObjectPropertyInfoList(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *sep;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (nb_args != 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sep = strrchr(str, '-');
|
|
||||||
if (sep) {
|
|
||||||
str = sep + 1;
|
|
||||||
}
|
|
||||||
len = strlen(str);
|
|
||||||
readline_set_completion_index(rs, len);
|
|
||||||
for (i = 0; i < Q_KEY_CODE__MAX; i++) {
|
|
||||||
if (!strncmp(str, QKeyCode_str(i), len)) {
|
|
||||||
readline_add_completion(rs, QKeyCode_str(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
|
void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
|
@ -14,6 +14,7 @@ softmmu_ss.add(files(
|
||||||
'kbd-state.c',
|
'kbd-state.c',
|
||||||
'keymaps.c',
|
'keymaps.c',
|
||||||
'qemu-pixman.c',
|
'qemu-pixman.c',
|
||||||
|
'ui-hmp-cmds.c',
|
||||||
'ui-qmp-cmds.c',
|
'ui-qmp-cmds.c',
|
||||||
'util.c',
|
'util.c',
|
||||||
))
|
))
|
||||||
|
|
|
@ -0,0 +1,422 @@
|
||||||
|
/*
|
||||||
|
* HMP commands related to UI
|
||||||
|
*
|
||||||
|
* 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"
|
||||||
|
#ifdef CONFIG_SPICE
|
||||||
|
#include <spice/enums.h>
|
||||||
|
#endif
|
||||||
|
#include "monitor/hmp.h"
|
||||||
|
#include "monitor/monitor.h"
|
||||||
|
#include "qapi/qapi-commands-ui.h"
|
||||||
|
#include "qapi/qmp/qdict.h"
|
||||||
|
#include "qemu/cutils.h"
|
||||||
|
#include "ui/console.h"
|
||||||
|
#include "ui/input.h"
|
||||||
|
|
||||||
|
static int mouse_button_state;
|
||||||
|
|
||||||
|
void hmp_mouse_move(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
int dx, dy, dz, button;
|
||||||
|
const char *dx_str = qdict_get_str(qdict, "dx_str");
|
||||||
|
const char *dy_str = qdict_get_str(qdict, "dy_str");
|
||||||
|
const char *dz_str = qdict_get_try_str(qdict, "dz_str");
|
||||||
|
|
||||||
|
dx = strtol(dx_str, NULL, 0);
|
||||||
|
dy = strtol(dy_str, NULL, 0);
|
||||||
|
qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
|
||||||
|
qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
|
||||||
|
|
||||||
|
if (dz_str) {
|
||||||
|
dz = strtol(dz_str, NULL, 0);
|
||||||
|
if (dz != 0) {
|
||||||
|
button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
|
||||||
|
qemu_input_queue_btn(NULL, button, true);
|
||||||
|
qemu_input_event_sync();
|
||||||
|
qemu_input_queue_btn(NULL, button, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qemu_input_event_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmp_mouse_button(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
static uint32_t bmap[INPUT_BUTTON__MAX] = {
|
||||||
|
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
|
||||||
|
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
|
||||||
|
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
|
||||||
|
};
|
||||||
|
int button_state = qdict_get_int(qdict, "button_state");
|
||||||
|
|
||||||
|
if (mouse_button_state == button_state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state);
|
||||||
|
qemu_input_event_sync();
|
||||||
|
mouse_button_state = button_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
MouseInfoList *mice_list, *mouse;
|
||||||
|
|
||||||
|
mice_list = qmp_query_mice(NULL);
|
||||||
|
if (!mice_list) {
|
||||||
|
monitor_printf(mon, "No mouse devices connected\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mouse = mice_list; mouse; mouse = mouse->next) {
|
||||||
|
monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
|
||||||
|
mouse->value->current ? '*' : ' ',
|
||||||
|
mouse->value->index, mouse->value->name,
|
||||||
|
mouse->value->absolute ? " (absolute)" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
qapi_free_MouseInfoList(mice_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_VNC
|
||||||
|
/* Helper for hmp_info_vnc_clients, _servers */
|
||||||
|
static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
monitor_printf(mon, " %s: %s:%s (%s%s)\n",
|
||||||
|
name,
|
||||||
|
info->host,
|
||||||
|
info->service,
|
||||||
|
NetworkAddressFamily_str(info->family),
|
||||||
|
info->websocket ? " (Websocket)" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper displaying and auth and crypt info */
|
||||||
|
static void hmp_info_vnc_authcrypt(Monitor *mon, const char *indent,
|
||||||
|
VncPrimaryAuth auth,
|
||||||
|
VncVencryptSubAuth *vencrypt)
|
||||||
|
{
|
||||||
|
monitor_printf(mon, "%sAuth: %s (Sub: %s)\n", indent,
|
||||||
|
VncPrimaryAuth_str(auth),
|
||||||
|
vencrypt ? VncVencryptSubAuth_str(*vencrypt) : "none");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmp_info_vnc_clients(Monitor *mon, VncClientInfoList *client)
|
||||||
|
{
|
||||||
|
while (client) {
|
||||||
|
VncClientInfo *cinfo = client->value;
|
||||||
|
|
||||||
|
hmp_info_VncBasicInfo(mon, qapi_VncClientInfo_base(cinfo), "Client");
|
||||||
|
monitor_printf(mon, " x509_dname: %s\n",
|
||||||
|
cinfo->x509_dname ?: "none");
|
||||||
|
monitor_printf(mon, " sasl_username: %s\n",
|
||||||
|
cinfo->sasl_username ?: "none");
|
||||||
|
|
||||||
|
client = client->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server)
|
||||||
|
{
|
||||||
|
while (server) {
|
||||||
|
VncServerInfo2 *sinfo = server->value;
|
||||||
|
hmp_info_VncBasicInfo(mon, qapi_VncServerInfo2_base(sinfo), "Server");
|
||||||
|
hmp_info_vnc_authcrypt(mon, " ", sinfo->auth,
|
||||||
|
sinfo->has_vencrypt ? &sinfo->vencrypt : NULL);
|
||||||
|
server = server->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmp_info_vnc(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
VncInfo2List *info2l, *info2l_head;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
info2l = qmp_query_vnc_servers(&err);
|
||||||
|
info2l_head = info2l;
|
||||||
|
if (hmp_handle_error(mon, err)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!info2l) {
|
||||||
|
monitor_printf(mon, "None\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (info2l) {
|
||||||
|
VncInfo2 *info = info2l->value;
|
||||||
|
monitor_printf(mon, "%s:\n", info->id);
|
||||||
|
hmp_info_vnc_servers(mon, info->server);
|
||||||
|
hmp_info_vnc_clients(mon, info->clients);
|
||||||
|
if (!info->server) {
|
||||||
|
/*
|
||||||
|
* The server entry displays its auth, we only need to
|
||||||
|
* display in the case of 'reverse' connections where
|
||||||
|
* there's no server.
|
||||||
|
*/
|
||||||
|
hmp_info_vnc_authcrypt(mon, " ", info->auth,
|
||||||
|
info->has_vencrypt ? &info->vencrypt : NULL);
|
||||||
|
}
|
||||||
|
if (info->display) {
|
||||||
|
monitor_printf(mon, " Display: %s\n", info->display);
|
||||||
|
}
|
||||||
|
info2l = info2l->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
qapi_free_VncInfo2List(info2l_head);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPICE
|
||||||
|
void hmp_info_spice(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
SpiceChannelList *chan;
|
||||||
|
SpiceInfo *info;
|
||||||
|
const char *channel_name;
|
||||||
|
static const char *const channel_names[] = {
|
||||||
|
[SPICE_CHANNEL_MAIN] = "main",
|
||||||
|
[SPICE_CHANNEL_DISPLAY] = "display",
|
||||||
|
[SPICE_CHANNEL_INPUTS] = "inputs",
|
||||||
|
[SPICE_CHANNEL_CURSOR] = "cursor",
|
||||||
|
[SPICE_CHANNEL_PLAYBACK] = "playback",
|
||||||
|
[SPICE_CHANNEL_RECORD] = "record",
|
||||||
|
[SPICE_CHANNEL_TUNNEL] = "tunnel",
|
||||||
|
[SPICE_CHANNEL_SMARTCARD] = "smartcard",
|
||||||
|
[SPICE_CHANNEL_USBREDIR] = "usbredir",
|
||||||
|
[SPICE_CHANNEL_PORT] = "port",
|
||||||
|
[SPICE_CHANNEL_WEBDAV] = "webdav",
|
||||||
|
};
|
||||||
|
|
||||||
|
info = qmp_query_spice(NULL);
|
||||||
|
|
||||||
|
if (!info->enabled) {
|
||||||
|
monitor_printf(mon, "Server: disabled\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_printf(mon, "Server:\n");
|
||||||
|
if (info->has_port) {
|
||||||
|
monitor_printf(mon, " address: %s:%" PRId64 "\n",
|
||||||
|
info->host, info->port);
|
||||||
|
}
|
||||||
|
if (info->has_tls_port) {
|
||||||
|
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
||||||
|
info->host, info->tls_port);
|
||||||
|
}
|
||||||
|
monitor_printf(mon, " migrated: %s\n",
|
||||||
|
info->migrated ? "true" : "false");
|
||||||
|
monitor_printf(mon, " auth: %s\n", info->auth);
|
||||||
|
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
||||||
|
monitor_printf(mon, " mouse-mode: %s\n",
|
||||||
|
SpiceQueryMouseMode_str(info->mouse_mode));
|
||||||
|
|
||||||
|
if (!info->has_channels || info->channels == NULL) {
|
||||||
|
monitor_printf(mon, "Channels: none\n");
|
||||||
|
} else {
|
||||||
|
for (chan = info->channels; chan; chan = chan->next) {
|
||||||
|
monitor_printf(mon, "Channel:\n");
|
||||||
|
monitor_printf(mon, " address: %s:%s%s\n",
|
||||||
|
chan->value->host, chan->value->port,
|
||||||
|
chan->value->tls ? " [tls]" : "");
|
||||||
|
monitor_printf(mon, " session: %" PRId64 "\n",
|
||||||
|
chan->value->connection_id);
|
||||||
|
monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n",
|
||||||
|
chan->value->channel_type, chan->value->channel_id);
|
||||||
|
|
||||||
|
channel_name = "unknown";
|
||||||
|
if (chan->value->channel_type > 0 &&
|
||||||
|
chan->value->channel_type < ARRAY_SIZE(channel_names) &&
|
||||||
|
channel_names[chan->value->channel_type]) {
|
||||||
|
channel_name = channel_names[chan->value->channel_type];
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor_printf(mon, " channel name: %s\n", channel_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
qapi_free_SpiceInfo(info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||||
|
const char *password = qdict_get_str(qdict, "password");
|
||||||
|
const char *display = qdict_get_try_str(qdict, "display");
|
||||||
|
const char *connected = qdict_get_try_str(qdict, "connected");
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
SetPasswordOptions opts = {
|
||||||
|
.password = (char *)password,
|
||||||
|
.has_connected = !!connected,
|
||||||
|
};
|
||||||
|
|
||||||
|
opts.connected = qapi_enum_parse(&SetPasswordAction_lookup, connected,
|
||||||
|
SET_PASSWORD_ACTION_KEEP, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol,
|
||||||
|
DISPLAY_PROTOCOL_VNC, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.protocol == DISPLAY_PROTOCOL_VNC) {
|
||||||
|
opts.u.vnc.display = (char *)display;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmp_set_password(&opts, &err);
|
||||||
|
|
||||||
|
out:
|
||||||
|
hmp_handle_error(mon, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmp_expire_password(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||||
|
const char *whenstr = qdict_get_str(qdict, "time");
|
||||||
|
const char *display = qdict_get_try_str(qdict, "display");
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
ExpirePasswordOptions opts = {
|
||||||
|
.time = (char *)whenstr,
|
||||||
|
};
|
||||||
|
|
||||||
|
opts.protocol = qapi_enum_parse(&DisplayProtocol_lookup, protocol,
|
||||||
|
DISPLAY_PROTOCOL_VNC, &err);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.protocol == DISPLAY_PROTOCOL_VNC) {
|
||||||
|
opts.u.vnc.display = (char *)display;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmp_expire_password(&opts, &err);
|
||||||
|
|
||||||
|
out:
|
||||||
|
hmp_handle_error(mon, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
const char *keys = qdict_get_str(qdict, "keys");
|
||||||
|
KeyValue *v = NULL;
|
||||||
|
KeyValueList *head = NULL, **tail = &head;
|
||||||
|
int has_hold_time = qdict_haskey(qdict, "hold-time");
|
||||||
|
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
|
||||||
|
Error *err = NULL;
|
||||||
|
const char *separator;
|
||||||
|
int keyname_len;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
separator = qemu_strchrnul(keys, '-');
|
||||||
|
keyname_len = separator - keys;
|
||||||
|
|
||||||
|
/* Be compatible with old interface, convert user inputted "<" */
|
||||||
|
if (keys[0] == '<' && keyname_len == 1) {
|
||||||
|
keys = "less";
|
||||||
|
keyname_len = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = g_malloc0(sizeof(*v));
|
||||||
|
|
||||||
|
if (strstart(keys, "0x", NULL)) {
|
||||||
|
const char *endp;
|
||||||
|
int value;
|
||||||
|
|
||||||
|
if (qemu_strtoi(keys, &endp, 0, &value) < 0) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
assert(endp <= keys + keyname_len);
|
||||||
|
if (endp != keys + keyname_len) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
v->type = KEY_VALUE_KIND_NUMBER;
|
||||||
|
v->u.number.data = value;
|
||||||
|
} else {
|
||||||
|
int idx = index_from_key(keys, keyname_len);
|
||||||
|
if (idx == Q_KEY_CODE__MAX) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
v->type = KEY_VALUE_KIND_QCODE;
|
||||||
|
v->u.qcode.data = idx;
|
||||||
|
}
|
||||||
|
QAPI_LIST_APPEND(tail, v);
|
||||||
|
v = NULL;
|
||||||
|
|
||||||
|
if (!*separator) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
keys = separator + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmp_send_key(head, has_hold_time, hold_time, &err);
|
||||||
|
hmp_handle_error(mon, err);
|
||||||
|
|
||||||
|
out:
|
||||||
|
qapi_free_KeyValue(v);
|
||||||
|
qapi_free_KeyValueList(head);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *sep;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (nb_args != 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sep = strrchr(str, '-');
|
||||||
|
if (sep) {
|
||||||
|
str = sep + 1;
|
||||||
|
}
|
||||||
|
len = strlen(str);
|
||||||
|
readline_set_completion_index(rs, len);
|
||||||
|
for (i = 0; i < Q_KEY_CODE__MAX; i++) {
|
||||||
|
if (!strncmp(str, QKeyCode_str(i), len)) {
|
||||||
|
readline_add_completion(rs, QKeyCode_str(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void coroutine_fn
|
||||||
|
hmp_screendump(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
const char *filename = qdict_get_str(qdict, "filename");
|
||||||
|
const char *id = qdict_get_try_str(qdict, "device");
|
||||||
|
int64_t head = qdict_get_try_int(qdict, "head", 0);
|
||||||
|
const char *input_format = qdict_get_try_str(qdict, "format");
|
||||||
|
Error *err = NULL;
|
||||||
|
ImageFormat format;
|
||||||
|
|
||||||
|
format = qapi_enum_parse(&ImageFormat_lookup, input_format,
|
||||||
|
IMAGE_FORMAT_PPM, &err);
|
||||||
|
if (err) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
qmp_screendump(filename, id, id != NULL, head,
|
||||||
|
input_format != NULL, format, &err);
|
||||||
|
end:
|
||||||
|
hmp_handle_error(mon, err);
|
||||||
|
}
|
Loading…
Reference in New Issue