2 * HMP commands related to UI
4 * Copyright IBM, Corp. 2011
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
12 * Contributions after 2012-01-13 are licensed under the terms of the
13 * GNU GPL, version 2 or (at your option) any later version.
16 #include "qemu/osdep.h"
18 #include <spice/enums.h>
20 #include "monitor/hmp.h"
21 #include "monitor/monitor-internal.h"
22 #include "qapi/error.h"
23 #include "qapi/qapi-commands-ui.h"
24 #include "qapi/qmp/qdict.h"
25 #include "qemu/cutils.h"
26 #include "ui/console.h"
29 static int mouse_button_state
;
31 void hmp_mouse_move(Monitor
*mon
, const QDict
*qdict
)
33 int dx
, dy
, dz
, button
;
34 const char *dx_str
= qdict_get_str(qdict
, "dx_str");
35 const char *dy_str
= qdict_get_str(qdict
, "dy_str");
36 const char *dz_str
= qdict_get_try_str(qdict
, "dz_str");
38 dx
= strtol(dx_str
, NULL
, 0);
39 dy
= strtol(dy_str
, NULL
, 0);
40 qemu_input_queue_rel(NULL
, INPUT_AXIS_X
, dx
);
41 qemu_input_queue_rel(NULL
, INPUT_AXIS_Y
, dy
);
44 dz
= strtol(dz_str
, NULL
, 0);
46 button
= (dz
> 0) ? INPUT_BUTTON_WHEEL_UP
: INPUT_BUTTON_WHEEL_DOWN
;
47 qemu_input_queue_btn(NULL
, button
, true);
48 qemu_input_event_sync();
49 qemu_input_queue_btn(NULL
, button
, false);
52 qemu_input_event_sync();
55 void hmp_mouse_button(Monitor
*mon
, const QDict
*qdict
)
57 static uint32_t bmap
[INPUT_BUTTON__MAX
] = {
58 [INPUT_BUTTON_LEFT
] = MOUSE_EVENT_LBUTTON
,
59 [INPUT_BUTTON_MIDDLE
] = MOUSE_EVENT_MBUTTON
,
60 [INPUT_BUTTON_RIGHT
] = MOUSE_EVENT_RBUTTON
,
62 int button_state
= qdict_get_int(qdict
, "button_state");
64 if (mouse_button_state
== button_state
) {
67 qemu_input_update_buttons(NULL
, bmap
, mouse_button_state
, button_state
);
68 qemu_input_event_sync();
69 mouse_button_state
= button_state
;
72 void hmp_mouse_set(Monitor
*mon
, const QDict
*qdict
)
76 qemu_mouse_set(qdict_get_int(qdict
, "index"), &err
);
77 hmp_handle_error(mon
, err
);
80 void hmp_info_mice(Monitor
*mon
, const QDict
*qdict
)
82 MouseInfoList
*mice_list
, *mouse
;
84 mice_list
= qmp_query_mice(NULL
);
86 monitor_printf(mon
, "No mouse devices connected\n");
90 for (mouse
= mice_list
; mouse
; mouse
= mouse
->next
) {
91 monitor_printf(mon
, "%c Mouse #%" PRId64
": %s%s\n",
92 mouse
->value
->current
? '*' : ' ',
93 mouse
->value
->index
, mouse
->value
->name
,
94 mouse
->value
->absolute
? " (absolute)" : "");
97 qapi_free_MouseInfoList(mice_list
);
101 /* Helper for hmp_info_vnc_clients, _servers */
102 static void hmp_info_VncBasicInfo(Monitor
*mon
, VncBasicInfo
*info
,
105 monitor_printf(mon
, " %s: %s:%s (%s%s)\n",
109 NetworkAddressFamily_str(info
->family
),
110 info
->websocket
? " (Websocket)" : "");
113 /* Helper displaying and auth and crypt info */
114 static void hmp_info_vnc_authcrypt(Monitor
*mon
, const char *indent
,
116 VncVencryptSubAuth
*vencrypt
)
118 monitor_printf(mon
, "%sAuth: %s (Sub: %s)\n", indent
,
119 VncPrimaryAuth_str(auth
),
120 vencrypt
? VncVencryptSubAuth_str(*vencrypt
) : "none");
123 static void hmp_info_vnc_clients(Monitor
*mon
, VncClientInfoList
*client
)
126 VncClientInfo
*cinfo
= client
->value
;
128 hmp_info_VncBasicInfo(mon
, qapi_VncClientInfo_base(cinfo
), "Client");
129 monitor_printf(mon
, " x509_dname: %s\n",
130 cinfo
->x509_dname
?: "none");
131 monitor_printf(mon
, " sasl_username: %s\n",
132 cinfo
->sasl_username
?: "none");
134 client
= client
->next
;
138 static void hmp_info_vnc_servers(Monitor
*mon
, VncServerInfo2List
*server
)
141 VncServerInfo2
*sinfo
= server
->value
;
142 hmp_info_VncBasicInfo(mon
, qapi_VncServerInfo2_base(sinfo
), "Server");
143 hmp_info_vnc_authcrypt(mon
, " ", sinfo
->auth
,
144 sinfo
->has_vencrypt
? &sinfo
->vencrypt
: NULL
);
145 server
= server
->next
;
149 void hmp_info_vnc(Monitor
*mon
, const QDict
*qdict
)
151 VncInfo2List
*info2l
, *info2l_head
;
154 info2l
= qmp_query_vnc_servers(&err
);
155 info2l_head
= info2l
;
156 if (hmp_handle_error(mon
, err
)) {
160 monitor_printf(mon
, "None\n");
165 VncInfo2
*info
= info2l
->value
;
166 monitor_printf(mon
, "%s:\n", info
->id
);
167 hmp_info_vnc_servers(mon
, info
->server
);
168 hmp_info_vnc_clients(mon
, info
->clients
);
171 * The server entry displays its auth, we only need to
172 * display in the case of 'reverse' connections where
175 hmp_info_vnc_authcrypt(mon
, " ", info
->auth
,
176 info
->has_vencrypt
? &info
->vencrypt
: NULL
);
179 monitor_printf(mon
, " Display: %s\n", info
->display
);
181 info2l
= info2l
->next
;
184 qapi_free_VncInfo2List(info2l_head
);
190 void hmp_info_spice(Monitor
*mon
, const QDict
*qdict
)
192 SpiceChannelList
*chan
;
194 const char *channel_name
;
195 static const char *const channel_names
[] = {
196 [SPICE_CHANNEL_MAIN
] = "main",
197 [SPICE_CHANNEL_DISPLAY
] = "display",
198 [SPICE_CHANNEL_INPUTS
] = "inputs",
199 [SPICE_CHANNEL_CURSOR
] = "cursor",
200 [SPICE_CHANNEL_PLAYBACK
] = "playback",
201 [SPICE_CHANNEL_RECORD
] = "record",
202 [SPICE_CHANNEL_TUNNEL
] = "tunnel",
203 [SPICE_CHANNEL_SMARTCARD
] = "smartcard",
204 [SPICE_CHANNEL_USBREDIR
] = "usbredir",
205 [SPICE_CHANNEL_PORT
] = "port",
206 [SPICE_CHANNEL_WEBDAV
] = "webdav",
209 info
= qmp_query_spice(NULL
);
211 if (!info
->enabled
) {
212 monitor_printf(mon
, "Server: disabled\n");
216 monitor_printf(mon
, "Server:\n");
217 if (info
->has_port
) {
218 monitor_printf(mon
, " address: %s:%" PRId64
"\n",
219 info
->host
, info
->port
);
221 if (info
->has_tls_port
) {
222 monitor_printf(mon
, " address: %s:%" PRId64
" [tls]\n",
223 info
->host
, info
->tls_port
);
225 monitor_printf(mon
, " migrated: %s\n",
226 info
->migrated
? "true" : "false");
227 monitor_printf(mon
, " auth: %s\n", info
->auth
);
228 monitor_printf(mon
, " compiled: %s\n", info
->compiled_version
);
229 monitor_printf(mon
, " mouse-mode: %s\n",
230 SpiceQueryMouseMode_str(info
->mouse_mode
));
232 if (!info
->has_channels
|| info
->channels
== NULL
) {
233 monitor_printf(mon
, "Channels: none\n");
235 for (chan
= info
->channels
; chan
; chan
= chan
->next
) {
236 monitor_printf(mon
, "Channel:\n");
237 monitor_printf(mon
, " address: %s:%s%s\n",
238 chan
->value
->host
, chan
->value
->port
,
239 chan
->value
->tls
? " [tls]" : "");
240 monitor_printf(mon
, " session: %" PRId64
"\n",
241 chan
->value
->connection_id
);
242 monitor_printf(mon
, " channel: %" PRId64
":%" PRId64
"\n",
243 chan
->value
->channel_type
, chan
->value
->channel_id
);
245 channel_name
= "unknown";
246 if (chan
->value
->channel_type
> 0 &&
247 chan
->value
->channel_type
< ARRAY_SIZE(channel_names
) &&
248 channel_names
[chan
->value
->channel_type
]) {
249 channel_name
= channel_names
[chan
->value
->channel_type
];
252 monitor_printf(mon
, " channel name: %s\n", channel_name
);
257 qapi_free_SpiceInfo(info
);
261 void hmp_set_password(Monitor
*mon
, const QDict
*qdict
)
263 const char *protocol
= qdict_get_str(qdict
, "protocol");
264 const char *password
= qdict_get_str(qdict
, "password");
265 const char *display
= qdict_get_try_str(qdict
, "display");
266 const char *connected
= qdict_get_try_str(qdict
, "connected");
269 SetPasswordOptions opts
= {
270 .password
= (char *)password
,
271 .has_connected
= !!connected
,
274 opts
.connected
= qapi_enum_parse(&SetPasswordAction_lookup
, connected
,
275 SET_PASSWORD_ACTION_KEEP
, &err
);
280 opts
.protocol
= qapi_enum_parse(&DisplayProtocol_lookup
, protocol
,
281 DISPLAY_PROTOCOL_VNC
, &err
);
286 if (opts
.protocol
== DISPLAY_PROTOCOL_VNC
) {
287 opts
.u
.vnc
.display
= (char *)display
;
290 qmp_set_password(&opts
, &err
);
293 hmp_handle_error(mon
, err
);
296 void hmp_expire_password(Monitor
*mon
, const QDict
*qdict
)
298 const char *protocol
= qdict_get_str(qdict
, "protocol");
299 const char *whenstr
= qdict_get_str(qdict
, "time");
300 const char *display
= qdict_get_try_str(qdict
, "display");
303 ExpirePasswordOptions opts
= {
304 .time
= (char *)whenstr
,
307 opts
.protocol
= qapi_enum_parse(&DisplayProtocol_lookup
, protocol
,
308 DISPLAY_PROTOCOL_VNC
, &err
);
313 if (opts
.protocol
== DISPLAY_PROTOCOL_VNC
) {
314 opts
.u
.vnc
.display
= (char *)display
;
317 qmp_expire_password(&opts
, &err
);
320 hmp_handle_error(mon
, err
);
324 static void hmp_change_read_arg(void *opaque
, const char *password
,
325 void *readline_opaque
)
327 qmp_change_vnc_password(password
, NULL
);
328 monitor_read_command(opaque
, 1);
331 void hmp_change_vnc(Monitor
*mon
, const char *device
, const char *target
,
332 const char *arg
, const char *read_only
, bool force
,
336 error_setg(errp
, "Parameter 'read-only-mode' is invalid for VNC");
339 if (strcmp(target
, "passwd") && strcmp(target
, "password")) {
340 error_setg(errp
, "Expected 'password' after 'vnc'");
344 MonitorHMP
*hmp_mon
= container_of(mon
, MonitorHMP
, common
);
345 monitor_read_password(hmp_mon
, hmp_change_read_arg
, NULL
);
347 qmp_change_vnc_password(arg
, errp
);
352 void hmp_sendkey(Monitor
*mon
, const QDict
*qdict
)
354 const char *keys
= qdict_get_str(qdict
, "keys");
356 KeyValueList
*head
= NULL
, **tail
= &head
;
357 int has_hold_time
= qdict_haskey(qdict
, "hold-time");
358 int hold_time
= qdict_get_try_int(qdict
, "hold-time", -1);
360 const char *separator
;
364 separator
= qemu_strchrnul(keys
, '-');
365 keyname_len
= separator
- keys
;
367 /* Be compatible with old interface, convert user inputted "<" */
368 if (keys
[0] == '<' && keyname_len
== 1) {
373 v
= g_malloc0(sizeof(*v
));
375 if (strstart(keys
, "0x", NULL
)) {
379 if (qemu_strtoi(keys
, &endp
, 0, &value
) < 0) {
382 assert(endp
<= keys
+ keyname_len
);
383 if (endp
!= keys
+ keyname_len
) {
386 v
->type
= KEY_VALUE_KIND_NUMBER
;
387 v
->u
.number
.data
= value
;
389 int idx
= index_from_key(keys
, keyname_len
);
390 if (idx
== Q_KEY_CODE__MAX
) {
393 v
->type
= KEY_VALUE_KIND_QCODE
;
394 v
->u
.qcode
.data
= idx
;
396 QAPI_LIST_APPEND(tail
, v
);
402 keys
= separator
+ 1;
405 qmp_send_key(head
, has_hold_time
, hold_time
, &err
);
406 hmp_handle_error(mon
, err
);
409 qapi_free_KeyValue(v
);
410 qapi_free_KeyValueList(head
);
414 monitor_printf(mon
, "invalid parameter: %.*s\n", keyname_len
, keys
);
418 void sendkey_completion(ReadLineState
*rs
, int nb_args
, const char *str
)
427 sep
= strrchr(str
, '-');
432 readline_set_completion_index(rs
, len
);
433 for (i
= 0; i
< Q_KEY_CODE__MAX
; i
++) {
434 if (!strncmp(str
, QKeyCode_str(i
), len
)) {
435 readline_add_completion(rs
, QKeyCode_str(i
));
442 hmp_screendump(Monitor
*mon
, const QDict
*qdict
)
444 const char *filename
= qdict_get_str(qdict
, "filename");
445 const char *id
= qdict_get_try_str(qdict
, "device");
446 int64_t head
= qdict_get_try_int(qdict
, "head", 0);
447 const char *input_format
= qdict_get_try_str(qdict
, "format");
451 format
= qapi_enum_parse(&ImageFormat_lookup
, input_format
,
452 IMAGE_FORMAT_PPM
, &err
);
457 qmp_screendump(filename
, id
, id
!= NULL
, head
,
458 input_format
!= NULL
, format
, &err
);
460 hmp_handle_error(mon
, err
);
464 void hmp_client_migrate_info(Monitor
*mon
, const QDict
*qdict
)
467 const char *protocol
= qdict_get_str(qdict
, "protocol");
468 const char *hostname
= qdict_get_str(qdict
, "hostname");
469 bool has_port
= qdict_haskey(qdict
, "port");
470 int port
= qdict_get_try_int(qdict
, "port", -1);
471 bool has_tls_port
= qdict_haskey(qdict
, "tls-port");
472 int tls_port
= qdict_get_try_int(qdict
, "tls-port", -1);
473 const char *cert_subject
= qdict_get_try_str(qdict
, "cert-subject");
475 qmp_client_migrate_info(protocol
, hostname
,
476 has_port
, port
, has_tls_port
, tls_port
,
478 hmp_handle_error(mon
, err
);