@@ -86,6 +86,7 @@ struct CharDriverState {
guint fd_in_tag;
guint fd_hup_tag;
QemuOpts *opts;
+ bool replay;
QTAILQ_ENTRY(CharDriverState) next;
};
@@ -125,6 +126,8 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
*/
CharDriverState *qemu_chr_new(const char *label, const char *filename,
void (*init)(struct CharDriverState *s));
+CharDriverState *qemu_chr_new_replay(const char *label, const char *filename,
+ void (*init)(struct CharDriverState *s));
/**
* @qemu_chr_delete:
@@ -320,6 +323,7 @@ int qemu_chr_be_can_write(CharDriverState *s);
* @len the number of bytes to receive from the front end
*/
void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len);
+void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len);
/**
@@ -81,6 +81,7 @@
#include "qemu/sockets.h"
#include "ui/qemu-spice.h"
+#include "replay/replay.h"
#define READ_BUF_LEN 4096
#define READ_RETRIES 10
@@ -126,6 +127,9 @@ int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
qemu_mutex_lock(&s->chr_write_lock);
ret = s->chr_write(s, buf, len);
+ if (s->replay) {
+ replay_data_int(&ret);
+ }
qemu_mutex_unlock(&s->chr_write_lock);
return ret;
}
@@ -195,9 +199,18 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len)
int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
{
- if (!s->chr_ioctl)
- return -ENOTSUP;
- return s->chr_ioctl(s, cmd, arg);
+ int res;
+ if (!s->chr_ioctl) {
+ res = -ENOTSUP;
+ } else {
+ res = s->chr_ioctl(s, cmd, arg);
+ if (s->replay) {
+ fprintf(stderr, "Replay: ioctl is not supported for serial devices yet\n");
+ exit(1);
+ }
+ }
+
+ return res;
}
int qemu_chr_be_can_write(CharDriverState *s)
@@ -207,17 +220,34 @@ int qemu_chr_be_can_write(CharDriverState *s)
return s->chr_can_read(s->handler_opaque);
}
-void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len)
{
if (s->chr_read) {
s->chr_read(s->handler_opaque, buf, len);
}
}
+void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+{
+ if (s->replay) {
+ if (replay_mode == REPLAY_PLAY) {
+ fprintf(stderr, "Replay: calling qemu_chr_be_write in play mode\n");
+ exit(1);
+ }
+ replay_chr_be_write(s, buf, len);
+ } else {
+ qemu_chr_be_write_impl(s, buf, len);
+ }
+}
+
int qemu_chr_fe_get_msgfd(CharDriverState *s)
{
int fd;
- return (qemu_chr_fe_get_msgfds(s, &fd, 1) == 1) ? fd : -1;
+ int res = (qemu_chr_fe_get_msgfds(s, &fd, 1) == 1) ? fd : -1;
+ if (s->replay) {
+ replay_data_int(&res);
+ }
+ return res;
}
int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int len)
@@ -1923,6 +1953,8 @@ static int win_chr_pipe_poll(void *opaque)
if (size > 0) {
s->len = size;
win_chr_read_poll(chr);
+ if (s->max_size == 0)
+ return 0;
win_chr_read(chr);
return 1;
}
@@ -2034,19 +2066,41 @@ static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int
len)
{
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwSize;
- int len1;
+ int ret = 0;
+ CONSOLE_SCREEN_BUFFER_INFO info;
- len1 = len;
-
- while (len1 > 0) {
- if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
- break;
+ while (len > 0) {
+ if (len > 2 && buf[0] == '\033' && buf[1] == '[') {
+ switch (buf[2]) {
+ case 'D':
+ if (!WriteFile(hStdOut, "\b", 1, &dwSize, NULL)) {
+ return ret;
+ }
+ break;
+ case 'K':
+ if (!GetConsoleScreenBufferInfo(hStdOut, &info)) {
+ return ret;
+ }
+ if (!FillConsoleOutputCharacter(hStdOut, ' ',
+ info.dwSize.X - info.dwCursorPosition.X,
+ info.dwCursorPosition, &dwSize)) {
+ return ret;
+ }
+ break;
+ }
+ dwSize = 3;
+ } else {
+ if (!WriteFile(hStdOut, buf, 1, &dwSize, NULL)) {
+ return ret;
+ }
}
- buf += dwSize;
- len1 -= dwSize;
+
+ buf += dwSize;
+ len -= dwSize;
+ ret += dwSize;
}
- return len - len1;
+ return ret;
}
These files include the following changes: - Record/replay functions for COM ports added by -serial command-line option. - Implementation of stdio monitor for Win32. Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@gmail.com> --- static void win_stdio_wait_func(void *opaque) @@ -2170,19 +2224,24 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) { CharDriverState *chr; WinStdioCharState *stdio; + HANDLE hStdOut; DWORD dwMode; + DWORD dwOutMode; int is_console = 0; chr = qemu_chr_alloc(); stdio = g_malloc0(sizeof(WinStdioCharState)); stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); - if (stdio->hStdIn == INVALID_HANDLE_VALUE) { + hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (stdio->hStdIn == INVALID_HANDLE_VALUE + || hStdOut == INVALID_HANDLE_VALUE) { fprintf(stderr, "cannot open stdio: invalid handle\n"); exit(1); } is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; + GetConsoleMode(hStdOut, &dwOutMode); chr->opaque = stdio; chr->chr_write = win_stdio_write; @@ -2219,9 +2278,11 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) /* set the terminal in raw mode */ /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ dwMode |= ENABLE_PROCESSED_INPUT; + dwOutMode |= ENABLE_PROCESSED_OUTPUT; } SetConsoleMode(stdio->hStdIn, dwMode); + SetConsoleMode(hStdOut, dwOutMode); chr->chr_set_echo = qemu_chr_set_echo_win_stdio; qemu_chr_fe_set_echo(chr, false); @@ -3615,6 +3676,18 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in return chr; } +CharDriverState *qemu_chr_new_replay(const char *label, const char *filename, void (*init)(struct CharDriverState *s)) +{ + if (replay_mode == REPLAY_PLAY && (strcmp(filename, "null") && strcmp(filename, "vc:80Cx24C"))) { + fprintf(stderr, "Only \"-serial null\" can be used with replay\n"); + exit(1); + } + CharDriverState *chr = qemu_chr_new(label, filename, init); + if (strcmp(filename, "vc:80Cx24C")) + replay_register_char_driver(chr); + return chr; +} + void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo) { if (chr->chr_set_echo) {