2 * QMP 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 "io/channel-file.h"
19 #include "monitor/qmp-helpers.h"
20 #include "qapi/qapi-commands-ui.h"
21 #include "qapi/qmp/qerror.h"
22 #include "qemu/coroutine.h"
23 #include "qemu/cutils.h"
25 #include "ui/console.h"
26 #include "ui/dbus-display.h"
27 #include "ui/qemu-spice.h"
32 void qmp_set_password(SetPasswordOptions
*opts
, Error
**errp
)
36 if (opts
->protocol
== DISPLAY_PROTOCOL_SPICE
) {
37 if (!qemu_using_spice(errp
)) {
40 rc
= qemu_spice
.set_passwd(opts
->password
,
41 opts
->connected
== SET_PASSWORD_ACTION_FAIL
,
42 opts
->connected
== SET_PASSWORD_ACTION_DISCONNECT
);
44 assert(opts
->protocol
== DISPLAY_PROTOCOL_VNC
);
45 if (opts
->connected
!= SET_PASSWORD_ACTION_KEEP
) {
46 /* vnc supports "connected=keep" only */
47 error_setg(errp
, QERR_INVALID_PARAMETER
, "connected");
51 * Note that setting an empty password will not disable login
52 * through this interface.
54 rc
= vnc_display_password(opts
->u
.vnc
.display
, opts
->password
);
58 error_setg(errp
, "Could not set password");
62 void qmp_expire_password(ExpirePasswordOptions
*opts
, Error
**errp
)
66 const char *whenstr
= opts
->time
;
67 const char *numstr
= NULL
;
70 if (strcmp(whenstr
, "now") == 0) {
72 } else if (strcmp(whenstr
, "never") == 0) {
74 } else if (whenstr
[0] == '+') {
83 if (qemu_strtou64(numstr
, NULL
, 10, &num
) < 0) {
84 error_setg(errp
, "Parameter 'time' doesn't take value '%s'",
91 if (opts
->protocol
== DISPLAY_PROTOCOL_SPICE
) {
92 if (!qemu_using_spice(errp
)) {
95 rc
= qemu_spice
.set_pw_expire(when
);
97 assert(opts
->protocol
== DISPLAY_PROTOCOL_VNC
);
98 rc
= vnc_display_pw_expire(opts
->u
.vnc
.display
, when
);
102 error_setg(errp
, "Could not set password expire time");
107 void qmp_change_vnc_password(const char *password
, Error
**errp
)
109 if (vnc_display_password(NULL
, password
) < 0) {
110 error_setg(errp
, "Could not set password");
115 bool qmp_add_client_spice(int fd
, bool has_skipauth
, bool skipauth
,
116 bool has_tls
, bool tls
, Error
**errp
)
118 if (!qemu_using_spice(errp
)) {
121 skipauth
= has_skipauth
? skipauth
: false;
122 tls
= has_tls
? tls
: false;
123 if (qemu_spice
.display_add_client(fd
, skipauth
, tls
) < 0) {
124 error_setg(errp
, "spice failed to add client");
131 bool qmp_add_client_vnc(int fd
, bool has_skipauth
, bool skipauth
,
132 bool has_tls
, bool tls
, Error
**errp
)
134 skipauth
= has_skipauth
? skipauth
: false;
135 vnc_display_add_client(NULL
, fd
, skipauth
);
140 #ifdef CONFIG_DBUS_DISPLAY
141 bool qmp_add_client_dbus_display(int fd
, bool has_skipauth
, bool skipauth
,
142 bool has_tls
, bool tls
, Error
**errp
)
144 if (!qemu_using_dbus_display(errp
)) {
147 if (!qemu_dbus_display
.add_client(fd
, errp
)) {
154 void qmp_display_reload(DisplayReloadOptions
*arg
, Error
**errp
)
157 case DISPLAY_RELOAD_TYPE_VNC
:
159 if (arg
->u
.vnc
.has_tls_certs
&& arg
->u
.vnc
.tls_certs
) {
160 vnc_display_reload_certs(NULL
, errp
);
163 error_setg(errp
, "vnc is invalid, missing 'CONFIG_VNC'");
171 void qmp_display_update(DisplayUpdateOptions
*arg
, Error
**errp
)
174 case DISPLAY_UPDATE_TYPE_VNC
:
176 vnc_display_update(&arg
->u
.vnc
, errp
);
178 error_setg(errp
, "vnc is invalid, missing 'CONFIG_VNC'");
186 void qmp_client_migrate_info(const char *protocol
, const char *hostname
,
187 bool has_port
, int64_t port
,
188 bool has_tls_port
, int64_t tls_port
,
189 const char *cert_subject
,
192 if (strcmp(protocol
, "spice") == 0) {
193 if (!qemu_using_spice(errp
)) {
197 if (!has_port
&& !has_tls_port
) {
198 error_setg(errp
, QERR_MISSING_PARAMETER
, "port/tls-port");
202 if (qemu_spice
.migrate_info(hostname
,
203 has_port
? port
: -1,
204 has_tls_port
? tls_port
: -1,
206 error_setg(errp
, "Could not set up display for migration");
212 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, "protocol", "'spice'");
217 * png_save: Take a screenshot as PNG
219 * Saves screendump as a PNG file
221 * Returns true for success or false for error.
223 * @fd: File descriptor for PNG file.
224 * @image: Image data in pixman format.
225 * @errp: Pointer to an error.
227 static bool png_save(int fd
, pixman_image_t
*image
, Error
**errp
)
229 int width
= pixman_image_get_width(image
);
230 int height
= pixman_image_get_height(image
);
233 g_autoptr(pixman_image_t
) linebuf
=
234 qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8
, width
);
235 uint8_t *buf
= (uint8_t *)pixman_image_get_data(linebuf
);
236 FILE *f
= fdopen(fd
, "wb");
239 error_setg_errno(errp
, errno
,
240 "Failed to create file from file descriptor");
244 png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
, NULL
,
247 error_setg(errp
, "PNG creation failed. Unable to write struct");
252 info_ptr
= png_create_info_struct(png_ptr
);
255 error_setg(errp
, "PNG creation failed. Unable to write info");
257 png_destroy_write_struct(&png_ptr
, &info_ptr
);
261 png_init_io(png_ptr
, f
);
263 png_set_IHDR(png_ptr
, info_ptr
, width
, height
, 8,
264 PNG_COLOR_TYPE_RGB
, PNG_INTERLACE_NONE
,
265 PNG_COMPRESSION_TYPE_BASE
, PNG_FILTER_TYPE_BASE
);
267 png_write_info(png_ptr
, info_ptr
);
269 for (y
= 0; y
< height
; ++y
) {
270 qemu_pixman_linebuf_fill(linebuf
, image
, width
, 0, y
);
271 png_write_row(png_ptr
, buf
);
274 png_write_end(png_ptr
, NULL
);
276 png_destroy_write_struct(&png_ptr
, &info_ptr
);
278 if (fclose(f
) != 0) {
279 error_setg_errno(errp
, errno
,
280 "PNG creation failed. Unable to close file");
287 #else /* no png support */
289 static bool png_save(int fd
, pixman_image_t
*image
, Error
**errp
)
291 error_setg(errp
, "Enable PNG support with libpng for screendump");
295 #endif /* CONFIG_PNG */
297 static bool ppm_save(int fd
, pixman_image_t
*image
, Error
**errp
)
299 int width
= pixman_image_get_width(image
);
300 int height
= pixman_image_get_height(image
);
301 g_autoptr(Object
) ioc
= OBJECT(qio_channel_file_new_fd(fd
));
302 g_autofree
char *header
= NULL
;
303 g_autoptr(pixman_image_t
) linebuf
= NULL
;
306 trace_ppm_save(fd
, image
);
308 header
= g_strdup_printf("P6\n%d %d\n%d\n", width
, height
, 255);
309 if (qio_channel_write_all(QIO_CHANNEL(ioc
),
310 header
, strlen(header
), errp
) < 0) {
314 linebuf
= qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8
, width
);
315 for (y
= 0; y
< height
; y
++) {
316 qemu_pixman_linebuf_fill(linebuf
, image
, width
, 0, y
);
317 if (qio_channel_write_all(QIO_CHANNEL(ioc
),
318 (char *)pixman_image_get_data(linebuf
),
319 pixman_image_get_stride(linebuf
), errp
) < 0) {
327 /* Safety: coroutine-only, concurrent-coroutine safe, main thread only */
329 qmp_screendump(const char *filename
, const char *device
,
330 bool has_head
, int64_t head
,
331 bool has_format
, ImageFormat format
, Error
**errp
)
333 g_autoptr(pixman_image_t
) image
= NULL
;
335 DisplaySurface
*surface
;
339 con
= qemu_console_lookup_by_device_name(device
, has_head
? head
: 0,
346 error_setg(errp
, "'head' must be specified together with 'device'");
349 con
= qemu_console_lookup_by_index(0);
351 error_setg(errp
, "There is no console to take a screendump from");
356 qemu_console_co_wait_update(con
);
359 * All pending coroutines are woken up, while the BQL is held. No
360 * further graphic update are possible until it is released. Take
361 * an image ref before that.
363 surface
= qemu_console_surface(con
);
365 error_setg(errp
, "no surface");
368 image
= pixman_image_ref(surface
->image
);
370 fd
= qemu_open_old(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, 0666);
372 error_setg(errp
, "failed to open file '%s': %s", filename
,
378 * The image content could potentially be updated as the coroutine
379 * yields and releases the BQL. It could produce corrupted dump, but
380 * it should be otherwise safe.
382 if (has_format
&& format
== IMAGE_FORMAT_PNG
) {
383 /* PNG format specified for screendump */
384 if (!png_save(fd
, image
, errp
)) {
385 qemu_unlink(filename
);
388 /* PPM format specified/default for screendump */
389 if (!ppm_save(fd
, image
, errp
)) {
390 qemu_unlink(filename
);