X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/da7d998bbb80f141ed5743418a4dfa5c1409e75f..56116a14699b9d898a8d6581a58ec81e4abae6e6:/qemu-char.c diff --git a/qemu-char.c b/qemu-char.c index 5e04a20b8c..bb9e3f50a8 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -31,11 +31,10 @@ #include "hw/usb.h" #include "hw/baum.h" #include "hw/msmouse.h" -#include "qemu-objects.h" +#include "qmp-commands.h" #include #include -#include #include #include #include @@ -107,7 +106,7 @@ static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = QTAILQ_HEAD_INITIALIZER(chardevs); -static void qemu_chr_event(CharDriverState *s, int event) +void qemu_chr_be_event(CharDriverState *s, int event) { /* Keep track if the char device is open */ switch (event) { @@ -127,7 +126,7 @@ static void qemu_chr_event(CharDriverState *s, int event) static void qemu_chr_generic_open_bh(void *opaque) { CharDriverState *s = opaque; - qemu_chr_event(s, CHR_EVENT_OPENED); + qemu_chr_be_event(s, CHR_EVENT_OPENED); qemu_bh_delete(s->bh); s->bh = NULL; } @@ -140,57 +139,56 @@ void qemu_chr_generic_open(CharDriverState *s) } } -int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) +int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len) { return s->chr_write(s, buf, len); } -int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) +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 qemu_chr_can_read(CharDriverState *s) +int qemu_chr_be_can_write(CharDriverState *s) { if (!s->chr_can_read) return 0; return s->chr_can_read(s->handler_opaque); } -void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) +void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len) { s->chr_read(s->handler_opaque, buf, len); } -int qemu_chr_get_msgfd(CharDriverState *s) +int qemu_chr_fe_get_msgfd(CharDriverState *s) { return s->get_msgfd ? s->get_msgfd(s) : -1; } +int qemu_chr_add_client(CharDriverState *s, int fd) +{ + return s->chr_add_client ? s->chr_add_client(s, fd) : -1; +} + void qemu_chr_accept_input(CharDriverState *s) { if (s->chr_accept_input) s->chr_accept_input(s); } -void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) +void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) { char buf[READ_BUF_LEN]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); - qemu_chr_write(s, (uint8_t *)buf, strlen(buf)); + qemu_chr_fe_write(s, (uint8_t *)buf, strlen(buf)); va_end(ap); } -void qemu_chr_send_event(CharDriverState *s, int event) -{ - if (s->chr_send_event) - s->chr_send_event(s, event); -} - void qemu_chr_add_handlers(CharDriverState *s, IOCanReadHandler *fd_can_read, IOReadHandler *fd_read, @@ -224,7 +222,7 @@ static CharDriverState *qemu_chr_open_null(QemuOpts *opts) { CharDriverState *chr; - chr = qemu_mallocz(sizeof(CharDriverState)); + chr = g_malloc0(sizeof(CharDriverState)); chr->chr_write = null_chr_write; return chr; } @@ -359,7 +357,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) bdrv_commit_all(); break; case 'b': - qemu_chr_event(chr, CHR_EVENT_BREAK); + qemu_chr_be_event(chr, CHR_EVENT_BREAK); break; case 'c': /* Switch to the next registered device */ @@ -471,8 +469,8 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) CharDriverState *chr; MuxDriver *d; - chr = qemu_mallocz(sizeof(CharDriverState)); - d = qemu_mallocz(sizeof(MuxDriver)); + chr = g_malloc0(sizeof(CharDriverState)); + d = g_malloc0(sizeof(MuxDriver)); chr->opaque = d; d->drv = drv; @@ -538,6 +536,9 @@ int send_all(int fd, const void *_buf, int len1) } #endif /* !_WIN32 */ +#define STDIO_MAX_CLIENTS 1 +static int stdio_nb_clients; + #ifndef _WIN32 typedef struct { @@ -545,8 +546,6 @@ typedef struct { int max_size; } FDCharDriver; -#define STDIO_MAX_CLIENTS 1 -static int stdio_nb_clients = 0; static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { @@ -559,7 +558,7 @@ static int fd_chr_read_poll(void *opaque) CharDriverState *chr = opaque; FDCharDriver *s = chr->opaque; - s->max_size = qemu_chr_can_read(chr); + s->max_size = qemu_chr_be_can_write(chr); return s->max_size; } @@ -579,11 +578,11 @@ static void fd_chr_read(void *opaque) if (size == 0) { /* FD has been closed. Remove it from the active list. */ qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); return; } if (size > 0) { - qemu_chr_read(chr, buf, size); + qemu_chr_be_write(chr, buf, size); } } @@ -611,8 +610,8 @@ static void fd_chr_close(struct CharDriverState *chr) } } - qemu_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + g_free(s); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } /* open a character device to a unix fd */ @@ -621,8 +620,8 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) CharDriverState *chr; FDCharDriver *s; - chr = qemu_mallocz(sizeof(CharDriverState)); - s = qemu_mallocz(sizeof(FDCharDriver)); + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(FDCharDriver)); s->fd_in = fd_in; s->fd_out = fd_out; chr->opaque = s; @@ -641,8 +640,9 @@ static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"), O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); - if (fd_out < 0) + if (fd_out < 0) { return NULL; + } return qemu_chr_open_fd(-1, fd_out); } @@ -666,9 +666,10 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) close(fd_in); if (fd_out >= 0) close(fd_out); - TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY)); - if (fd_in < 0) + TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY)); + if (fd_in < 0) { return NULL; + } } return qemu_chr_open_fd(fd_in, fd_out); } @@ -687,8 +688,8 @@ static int stdio_read_poll(void *opaque) CharDriverState *chr = opaque; /* try to flush the queue if needed */ - if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { - qemu_chr_read(chr, term_fifo, 1); + if (term_fifo_size != 0 && qemu_chr_be_can_write(chr) > 0) { + qemu_chr_be_write(chr, term_fifo, 1); term_fifo_size = 0; } /* see if we can absorb more chars */ @@ -708,12 +709,12 @@ static void stdio_read(void *opaque) if (size == 0) { /* stdin has been closed. Remove it from the active list. */ qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); return; } if (size > 0) { - if (qemu_chr_can_read(chr) > 0) { - qemu_chr_read(chr, buf, 1); + if (qemu_chr_be_can_write(chr) > 0) { + qemu_chr_be_write(chr, buf, 1); } else if (term_fifo_size == 0) { term_fifo[term_fifo_size++] = buf[0]; } @@ -765,8 +766,9 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) { CharDriverState *chr; - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) + if (stdio_nb_clients >= STDIO_MAX_CLIENTS) { return NULL; + } if (stdio_nb_clients == 0) { old_fd0_flags = fcntl(0, F_GETFL); tcgetattr (0, &oldtty); @@ -781,7 +783,7 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) stdio_nb_clients++; stdio_allow_signal = qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC); - qemu_chr_set_echo(chr, false); + qemu_chr_fe_set_echo(chr, false); return chr; } @@ -875,7 +877,7 @@ static int pty_chr_read_poll(void *opaque) CharDriverState *chr = opaque; PtyCharDriver *s = chr->opaque; - s->read_bytes = qemu_chr_can_read(chr); + s->read_bytes = qemu_chr_be_can_write(chr); return s->read_bytes; } @@ -899,7 +901,7 @@ static void pty_chr_read(void *opaque) } if (size > 0) { pty_chr_state(chr, 1); - qemu_chr_read(chr, buf, size); + qemu_chr_be_write(chr, buf, size); } } @@ -966,8 +968,8 @@ static void pty_chr_close(struct CharDriverState *chr) close(s->fd); qemu_del_timer(s->timer); qemu_free_timer(s->timer); - qemu_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + g_free(s); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) @@ -975,7 +977,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) CharDriverState *chr; PtyCharDriver *s; struct termios tty; - int slave_fd, len; + int master_fd, slave_fd, len; #if defined(__OpenBSD__) || defined(__DragonFly__) char pty_name[PATH_MAX]; #define q_ptsname(x) pty_name @@ -984,10 +986,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) #define q_ptsname(x) ptsname(x) #endif - chr = qemu_mallocz(sizeof(CharDriverState)); - s = qemu_mallocz(sizeof(PtyCharDriver)); - - if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) { + if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) { return NULL; } @@ -997,17 +996,21 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) tcsetattr(slave_fd, TCSAFLUSH, &tty); close(slave_fd); - len = strlen(q_ptsname(s->fd)) + 5; - chr->filename = qemu_malloc(len); - snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd)); - qemu_opt_set(opts, "path", q_ptsname(s->fd)); - fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd)); + chr = g_malloc0(sizeof(CharDriverState)); + len = strlen(q_ptsname(master_fd)) + 5; + chr->filename = g_malloc(len); + snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd)); + qemu_opt_set(opts, "path", q_ptsname(master_fd)); + fprintf(stderr, "char device redirected to %s\n", q_ptsname(master_fd)); + + s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; chr->chr_write = pty_chr_write; chr->chr_update_read_handler = pty_chr_update_read_handler; chr->chr_close = pty_chr_close; + s->fd = master_fd; s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr); return chr; @@ -1217,16 +1220,12 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) CharDriverState *chr; int fd; - TFR(fd = open(filename, O_RDWR | O_NONBLOCK)); + TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK)); if (fd < 0) { return NULL; } tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd); - if (!chr) { - close(fd); - return NULL; - } chr->chr_ioctl = tty_serial_ioctl; chr->chr_close = qemu_chr_close_tty; return chr; @@ -1344,8 +1343,8 @@ static void pp_close(CharDriverState *chr) pp_hw_mode(drv, IEEE1284_MODE_COMPAT); ioctl(fd, PPRELEASE); close(fd); - qemu_free(drv); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + g_free(drv); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) @@ -1355,20 +1354,21 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) ParallelCharDriver *drv; int fd; - TFR(fd = open(filename, O_RDWR)); - if (fd < 0) + TFR(fd = qemu_open(filename, O_RDWR)); + if (fd < 0) { return NULL; + } if (ioctl(fd, PPCLAIM) < 0) { close(fd); return NULL; } - drv = qemu_mallocz(sizeof(ParallelCharDriver)); + drv = g_malloc0(sizeof(ParallelCharDriver)); drv->fd = fd; drv->mode = IEEE1284_MODE_COMPAT; - chr = qemu_mallocz(sizeof(CharDriverState)); + chr = g_malloc0(sizeof(CharDriverState)); chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; chr->chr_close = pp_close; @@ -1424,11 +1424,12 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) CharDriverState *chr; int fd; - fd = open(filename, O_RDWR); - if (fd < 0) + fd = qemu_open(filename, O_RDWR); + if (fd < 0) { return NULL; + } - chr = qemu_mallocz(sizeof(CharDriverState)); + chr = g_malloc0(sizeof(CharDriverState)); chr->opaque = (void *)(intptr_t)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; @@ -1438,6 +1439,8 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) #else /* _WIN32 */ +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; + typedef struct { int max_size; HANDLE hcom, hrecv, hsend; @@ -1446,6 +1449,14 @@ typedef struct { DWORD len; } WinCharState; +typedef struct { + HANDLE hStdIn; + HANDLE hInputReadyEvent; + HANDLE hInputDoneEvent; + HANDLE hInputThread; + uint8_t win_stdio_buf; +} WinStdioCharState; + #define NSENDBUF 2048 #define NRECVBUF 2048 #define MAXCONNECT 1 @@ -1475,7 +1486,7 @@ static void win_chr_close(CharDriverState *chr) else qemu_del_polling_cb(win_chr_poll, chr); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static int win_chr_init(CharDriverState *chr, const char *filename) @@ -1583,7 +1594,7 @@ static int win_chr_read_poll(CharDriverState *chr) { WinCharState *s = chr->opaque; - s->max_size = qemu_chr_can_read(chr); + s->max_size = qemu_chr_be_can_write(chr); return s->max_size; } @@ -1605,7 +1616,7 @@ static void win_chr_readfile(CharDriverState *chr) } if (size > 0) { - qemu_chr_read(chr, buf, size); + qemu_chr_be_write(chr, buf, size); } } @@ -1644,15 +1655,15 @@ static CharDriverState *qemu_chr_open_win(QemuOpts *opts) CharDriverState *chr; WinCharState *s; - chr = qemu_mallocz(sizeof(CharDriverState)); - s = qemu_mallocz(sizeof(WinCharState)); + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(WinCharState)); chr->opaque = s; chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; if (win_chr_init(chr, filename) < 0) { - free(s); - free(chr); + g_free(s); + g_free(chr); return NULL; } qemu_chr_generic_open(chr); @@ -1744,15 +1755,15 @@ static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts) CharDriverState *chr; WinCharState *s; - chr = qemu_mallocz(sizeof(CharDriverState)); - s = qemu_mallocz(sizeof(WinCharState)); + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(WinCharState)); chr->opaque = s; chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; if (win_chr_pipe_init(chr, filename) < 0) { - free(s); - free(chr); + g_free(s); + g_free(chr); return NULL; } qemu_chr_generic_open(chr); @@ -1764,8 +1775,8 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) CharDriverState *chr; WinCharState *s; - chr = qemu_mallocz(sizeof(CharDriverState)); - s = qemu_mallocz(sizeof(WinCharState)); + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(WinCharState)); s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; @@ -1785,11 +1796,221 @@ static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts) fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd_out == INVALID_HANDLE_VALUE) + if (fd_out == INVALID_HANDLE_VALUE) { return NULL; + } return qemu_chr_open_win_file(fd_out); } + +static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwSize; + int len1; + + len1 = len; + + while (len1 > 0) { + if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) { + break; + } + buf += dwSize; + len1 -= dwSize; + } + + return len - len1; +} + +static void win_stdio_wait_func(void *opaque) +{ + CharDriverState *chr = opaque; + WinStdioCharState *stdio = chr->opaque; + INPUT_RECORD buf[4]; + int ret; + DWORD dwSize; + int i; + + ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf), + &dwSize); + + if (!ret) { + /* Avoid error storm */ + qemu_del_wait_object(stdio->hStdIn, NULL, NULL); + return; + } + + for (i = 0; i < dwSize; i++) { + KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent; + + if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) { + int j; + if (kev->uChar.AsciiChar != 0) { + for (j = 0; j < kev->wRepeatCount; j++) { + if (qemu_chr_be_can_write(chr)) { + uint8_t c = kev->uChar.AsciiChar; + qemu_chr_be_write(chr, &c, 1); + } + } + } + } + } +} + +static DWORD WINAPI win_stdio_thread(LPVOID param) +{ + CharDriverState *chr = param; + WinStdioCharState *stdio = chr->opaque; + int ret; + DWORD dwSize; + + while (1) { + + /* Wait for one byte */ + ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL); + + /* Exit in case of error, continue if nothing read */ + if (!ret) { + break; + } + if (!dwSize) { + continue; + } + + /* Some terminal emulator returns \r\n for Enter, just pass \n */ + if (stdio->win_stdio_buf == '\r') { + continue; + } + + /* Signal the main thread and wait until the byte was eaten */ + if (!SetEvent(stdio->hInputReadyEvent)) { + break; + } + if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE) + != WAIT_OBJECT_0) { + break; + } + } + + qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); + return 0; +} + +static void win_stdio_thread_wait_func(void *opaque) +{ + CharDriverState *chr = opaque; + WinStdioCharState *stdio = chr->opaque; + + if (qemu_chr_be_can_write(chr)) { + qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1); + } + + SetEvent(stdio->hInputDoneEvent); +} + +static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo) +{ + WinStdioCharState *stdio = chr->opaque; + DWORD dwMode = 0; + + GetConsoleMode(stdio->hStdIn, &dwMode); + + if (echo) { + SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT); + } else { + SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT); + } +} + +static void win_stdio_close(CharDriverState *chr) +{ + WinStdioCharState *stdio = chr->opaque; + + if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) { + CloseHandle(stdio->hInputReadyEvent); + } + if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) { + CloseHandle(stdio->hInputDoneEvent); + } + if (stdio->hInputThread != INVALID_HANDLE_VALUE) { + TerminateThread(stdio->hInputThread, 0); + } + + g_free(chr->opaque); + g_free(chr); + stdio_nb_clients--; +} + +static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) +{ + CharDriverState *chr; + WinStdioCharState *stdio; + DWORD dwMode; + int is_console = 0; + + if (stdio_nb_clients >= STDIO_MAX_CLIENTS + || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { + return NULL; + } + + chr = g_malloc0(sizeof(CharDriverState)); + stdio = g_malloc0(sizeof(WinStdioCharState)); + + stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); + if (stdio->hStdIn == INVALID_HANDLE_VALUE) { + fprintf(stderr, "cannot open stdio: invalid handle\n"); + exit(1); + } + + is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; + + chr->opaque = stdio; + chr->chr_write = win_stdio_write; + chr->chr_close = win_stdio_close; + + if (stdio_nb_clients == 0) { + if (is_console) { + if (qemu_add_wait_object(stdio->hStdIn, + win_stdio_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); + } + } else { + DWORD dwId; + + stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, + chr, 0, &dwId); + + if (stdio->hInputThread == INVALID_HANDLE_VALUE + || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE + || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { + fprintf(stderr, "cannot create stdio thread or event\n"); + exit(1); + } + if (qemu_add_wait_object(stdio->hInputReadyEvent, + win_stdio_thread_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); + } + } + } + + dwMode |= ENABLE_LINE_INPUT; + + stdio_clients[stdio_nb_clients++] = chr; + if (stdio_nb_clients == 1 && is_console) { + /* set the terminal in raw mode */ + /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ + dwMode |= ENABLE_PROCESSED_INPUT; + } + + SetConsoleMode(stdio->hStdIn, dwMode); + + chr->chr_set_echo = qemu_chr_set_echo_win_stdio; + qemu_chr_fe_set_echo(chr, false); + + return chr; +} #endif /* !_WIN32 */ /***********************************************************/ @@ -1815,15 +2036,15 @@ static int udp_chr_read_poll(void *opaque) CharDriverState *chr = opaque; NetCharDriver *s = chr->opaque; - s->max_size = qemu_chr_can_read(chr); + s->max_size = qemu_chr_be_can_write(chr); /* If there were any stray characters in the queue process them * first */ while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_read(chr, &s->buf[s->bufptr], 1); + qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); s->bufptr++; - s->max_size = qemu_chr_can_read(chr); + s->max_size = qemu_chr_be_can_write(chr); } return s->max_size; } @@ -1835,16 +2056,16 @@ static void udp_chr_read(void *opaque) if (s->max_size == 0) return; - s->bufcnt = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0); + s->bufcnt = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0); s->bufptr = s->bufcnt; if (s->bufcnt <= 0) return; s->bufptr = 0; while (s->max_size > 0 && s->bufptr < s->bufcnt) { - qemu_chr_read(chr, &s->buf[s->bufptr], 1); + qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); s->bufptr++; - s->max_size = qemu_chr_can_read(chr); + s->max_size = qemu_chr_be_can_write(chr); } } @@ -1862,11 +2083,11 @@ static void udp_chr_close(CharDriverState *chr) { NetCharDriver *s = chr->opaque; if (s->fd >= 0) { - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); } - qemu_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + g_free(s); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) @@ -1875,8 +2096,8 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) NetCharDriver *s = NULL; int fd = -1; - chr = qemu_mallocz(sizeof(CharDriverState)); - s = qemu_mallocz(sizeof(NetCharDriver)); + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(NetCharDriver)); fd = inet_dgram_opts(opts); if (fd < 0) { @@ -1894,12 +2115,11 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) return chr; return_err: - if (chr) - free(chr); - if (s) - free(s); - if (fd >= 0) + g_free(chr); + g_free(s); + if (fd >= 0) { closesocket(fd); + } return NULL; } @@ -1935,7 +2155,7 @@ static int tcp_chr_read_poll(void *opaque) TCPCharDriver *s = chr->opaque; if (!s->connected) return 0; - s->max_size = qemu_chr_can_read(chr); + s->max_size = qemu_chr_be_can_write(chr); return s->max_size; } @@ -1968,7 +2188,7 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, } else { if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { /* Handle IAC break commands by sending a serial break */ - qemu_chr_event(chr, CHR_EVENT_BREAK); + qemu_chr_be_event(chr, CHR_EVENT_BREAK); s->do_telnetopt++; } s->do_telnetopt++; @@ -2050,7 +2270,7 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) { TCPCharDriver *s = chr->opaque; - return recv(s->fd, buf, len, 0); + return qemu_recv(s->fd, buf, len, 0); } #endif @@ -2071,17 +2291,17 @@ static void tcp_chr_read(void *opaque) /* connection closed */ s->connected = 0; if (s->listen_fd >= 0) { - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); } - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); s->fd = -1; - qemu_chr_event(chr, CHR_EVENT_CLOSED); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } else if (size > 0) { if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); if (size > 0) - qemu_chr_read(chr, buf, size); + qemu_chr_be_write(chr, buf, size); } } @@ -2124,6 +2344,22 @@ static void socket_set_nodelay(int fd) setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); } +static int tcp_chr_add_client(CharDriverState *chr, int fd) +{ + TCPCharDriver *s = chr->opaque; + if (s->fd != -1) + return -1; + + socket_set_nonblock(fd); + if (s->do_nodelay) + socket_set_nodelay(fd); + s->fd = fd; + qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL); + tcp_chr_connect(chr); + + return 0; +} + static void tcp_chr_accept(void *opaque) { CharDriverState *chr = opaque; @@ -2156,27 +2392,23 @@ static void tcp_chr_accept(void *opaque) break; } } - socket_set_nonblock(fd); - if (s->do_nodelay) - socket_set_nodelay(fd); - s->fd = fd; - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); - tcp_chr_connect(chr); + if (tcp_chr_add_client(chr, fd) < 0) + close(fd); } static void tcp_chr_close(CharDriverState *chr) { TCPCharDriver *s = chr->opaque; if (s->fd >= 0) { - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); } if (s->listen_fd >= 0) { - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL); closesocket(s->listen_fd); } - qemu_free(s); - qemu_chr_event(chr, CHR_EVENT_CLOSED); + g_free(s); + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) @@ -2198,8 +2430,8 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (!is_listen) is_waitconnect = 0; - chr = qemu_mallocz(sizeof(CharDriverState)); - s = qemu_mallocz(sizeof(TCPCharDriver)); + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(TCPCharDriver)); if (is_unix) { if (is_listen) { @@ -2214,8 +2446,9 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) fd = inet_connect_opts(opts); } } - if (fd < 0) + if (fd < 0) { goto fail; + } if (!is_waitconnect) socket_set_nonblock(fd); @@ -2231,10 +2464,11 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) chr->chr_write = tcp_chr_write; chr->chr_close = tcp_chr_close; chr->get_msgfd = tcp_get_msgfd; + chr->chr_add_client = tcp_chr_add_client; if (is_listen) { s->listen_fd = fd; - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); if (is_telnet) s->do_telnetopt = 1; @@ -2246,7 +2480,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) } /* for "info chardev" monitor command */ - chr->filename = qemu_malloc(256); + chr->filename = g_malloc(256); if (is_unix) { snprintf(chr->filename, 256, "unix:%s%s", qemu_opt_get(opts, "path"), @@ -2272,8 +2506,8 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) fail: if (fd >= 0) closesocket(fd); - qemu_free(s); - qemu_free(chr); + g_free(s); + g_free(chr); return NULL; } @@ -2295,7 +2529,7 @@ static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) /* grow outbuf */ d->outbuf_capacity += len; d->outbuf_capacity *= 2; - d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity); + d->outbuf = g_realloc(d->outbuf, d->outbuf_capacity); } memcpy(d->outbuf + d->outbuf_size, buf, len); @@ -2308,10 +2542,10 @@ void qemu_chr_init_mem(CharDriverState *chr) { MemoryDriver *d; - d = qemu_malloc(sizeof(*d)); + d = g_malloc(sizeof(*d)); d->outbuf_size = 0; d->outbuf_capacity = 4096; - d->outbuf = qemu_mallocz(d->outbuf_capacity); + d->outbuf = g_malloc0(d->outbuf_capacity); memset(chr, 0, sizeof(*chr)); chr->opaque = d; @@ -2324,13 +2558,13 @@ QString *qemu_chr_mem_to_qs(CharDriverState *chr) return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1); } -/* NOTE: this driver can not be closed with qemu_chr_close()! */ +/* NOTE: this driver can not be closed with qemu_chr_delete()! */ void qemu_chr_close_mem(CharDriverState *chr) { MemoryDriver *d = chr->opaque; - qemu_free(d->outbuf); - qemu_free(chr->opaque); + g_free(d->outbuf); + g_free(chr->opaque); chr->opaque = NULL; chr->chr_write = NULL; } @@ -2479,6 +2713,7 @@ static const struct { { .name = "pipe", .open = qemu_chr_open_win_pipe }, { .name = "console", .open = qemu_chr_open_win_con }, { .name = "serial", .open = qemu_chr_open_win }, + { .name = "stdio", .open = qemu_chr_open_win_stdio }, #else { .name = "file", .open = qemu_chr_open_file_out }, { .name = "pipe", .open = qemu_chr_open_pipe }, @@ -2502,7 +2737,7 @@ static const struct { #endif }; -CharDriverState *qemu_chr_open_opts(QemuOpts *opts, +CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s)) { CharDriverState *chr; @@ -2536,14 +2771,14 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, } if (!chr->filename) - chr->filename = qemu_strdup(qemu_opt_get(opts, "backend")); + chr->filename = g_strdup(qemu_opt_get(opts, "backend")); chr->init = init; QTAILQ_INSERT_TAIL(&chardevs, chr, next); if (qemu_opt_get_bool(opts, "mux", 0)) { CharDriverState *base = chr; int len = strlen(qemu_opts_id(opts)) + 6; - base->label = qemu_malloc(len); + base->label = g_malloc(len); snprintf(base->label, len, "%s-base", qemu_opts_id(opts)); chr = qemu_chr_open_mux(base); chr->filename = base->filename; @@ -2552,11 +2787,11 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, } else { chr->avail_connections = 1; } - chr->label = qemu_strdup(qemu_opts_id(opts)); + chr->label = g_strdup(qemu_opts_id(opts)); return chr; } -CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s)) +CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s)) { const char *p; CharDriverState *chr; @@ -2570,7 +2805,7 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i if (!opts) return NULL; - chr = qemu_chr_open_opts(opts, init); + chr = qemu_chr_new_from_opts(opts, init); if (chr && qemu_opt_get_bool(opts, "mux", 0)) { monitor_init(chr, MONITOR_USE_READLINE); } @@ -2578,66 +2813,53 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i return chr; } -void qemu_chr_set_echo(struct CharDriverState *chr, bool echo) +void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo) { if (chr->chr_set_echo) { chr->chr_set_echo(chr, echo); } } -void qemu_chr_guest_open(struct CharDriverState *chr) +void qemu_chr_fe_open(struct CharDriverState *chr) { if (chr->chr_guest_open) { chr->chr_guest_open(chr); } } -void qemu_chr_guest_close(struct CharDriverState *chr) +void qemu_chr_fe_close(struct CharDriverState *chr) { if (chr->chr_guest_close) { chr->chr_guest_close(chr); } } -void qemu_chr_close(CharDriverState *chr) +void qemu_chr_delete(CharDriverState *chr) { QTAILQ_REMOVE(&chardevs, chr, next); if (chr->chr_close) chr->chr_close(chr); - qemu_free(chr->filename); - qemu_free(chr->label); - qemu_free(chr); + g_free(chr->filename); + g_free(chr->label); + g_free(chr); } -static void qemu_chr_qlist_iter(QObject *obj, void *opaque) +ChardevInfoList *qmp_query_chardev(Error **errp) { - QDict *chr_dict; - Monitor *mon = opaque; - - chr_dict = qobject_to_qdict(obj); - monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"), - qdict_get_str(chr_dict, "filename")); -} - -void qemu_chr_info_print(Monitor *mon, const QObject *ret_data) -{ - qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon); -} - -void qemu_chr_info(Monitor *mon, QObject **ret_data) -{ - QList *chr_list; + ChardevInfoList *chr_list = NULL; CharDriverState *chr; - chr_list = qlist_new(); - QTAILQ_FOREACH(chr, &chardevs, next) { - QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }", - chr->label, chr->filename); - qlist_append_obj(chr_list, obj); + ChardevInfoList *info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + info->value->label = g_strdup(chr->label); + info->value->filename = g_strdup(chr->filename); + + info->next = chr_list; + chr_list = info; } - *ret_data = QOBJECT(chr_list); + return chr_list; } CharDriverState *qemu_chr_find(const char *name) @@ -2651,3 +2873,13 @@ CharDriverState *qemu_chr_find(const char *name) } return NULL; } + +/* Get a character (serial) device interface. */ +CharDriverState *qemu_char_get_next_serial(void) +{ + static int next_serial; + + /* FIXME: This function needs to go away: use chardev properties! */ + return serial_hds[next_serial++]; +} +