User Networking: Enable removal of redirections
[qemu] / qemu-char.c
index 6f9861a..1c0c9f5 100644 (file)
@@ -23,6 +23,7 @@
  */
 #include "qemu-common.h"
 #include "net.h"
+#include "monitor.h"
 #include "console.h"
 #include "sysemu.h"
 #include "qemu-timer.h"
@@ -30,6 +31,7 @@
 #include "block.h"
 #include "hw/usb.h"
 #include "hw/baum.h"
+#include "hw/msmouse.h"
 
 #include <unistd.h>
 #include <fcntl.h>
 #include <dirent.h>
 #include <netdb.h>
 #include <sys/select.h>
-#ifdef _BSD
+#ifdef HOST_BSD
 #include <sys/stat.h>
 #ifdef __FreeBSD__
 #include <libutil.h>
+#include <dev/ppbus/ppi.h>
+#include <dev/ppbus/ppbconf.h>
+#elif defined(__DragonFly__)
+#include <libutil.h>
+#include <dev/misc/ppi/ppi.h>
+#include <bus/ppbus/ppbconf.h>
 #else
 #include <util.h>
 #endif
 /***********************************************************/
 /* character device */
 
+static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
+    TAILQ_HEAD_INITIALIZER(chardevs);
+static int initial_reset_issued;
+
 static void qemu_chr_event(CharDriverState *s, int event)
 {
     if (!s->chr_event)
@@ -115,12 +127,23 @@ static void qemu_chr_reset_bh(void *opaque)
 
 void qemu_chr_reset(CharDriverState *s)
 {
-    if (s->bh == NULL) {
+    if (s->bh == NULL && initial_reset_issued) {
        s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
        qemu_bh_schedule(s->bh);
     }
 }
 
+void qemu_chr_initial_reset(void)
+{
+    CharDriverState *chr;
+
+    initial_reset_issued = 1;
+
+    TAILQ_FOREACH(chr, &chardevs, next) {
+        qemu_chr_reset(chr);
+    }
+}
+
 int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
 {
     return s->chr_write(s, buf, len);
@@ -191,8 +214,6 @@ static CharDriverState *qemu_chr_open_null(void)
     CharDriverState *chr;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
     chr->chr_write = null_chr_write;
     return chr;
 }
@@ -209,12 +230,15 @@ typedef struct {
     IOEventHandler *chr_event[MAX_MUX];
     void *ext_opaque[MAX_MUX];
     CharDriverState *drv;
-    unsigned char buffer[MUX_BUFFER_SIZE];
-    int prod;
-    int cons;
     int mux_cnt;
     int term_got_escape;
     int max_size;
+    /* Intermediate input buffer allows to catch escape sequences even if the
+       currently active device is not accepting any input - but only until it
+       is full as well. */
+    unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
+    int prod[MAX_MUX];
+    int cons[MAX_MUX];
 } MuxDriver;
 
 
@@ -239,13 +263,13 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
                 if (term_timestamps_start == -1)
                     term_timestamps_start = ti;
                 ti -= term_timestamps_start;
-                secs = ti / 1000000000;
+                secs = ti / 1000;
                 snprintf(buf1, sizeof(buf1),
                          "[%02d:%02d:%02d.%03d] ",
                          secs / 3600,
                          (secs / 60) % 60,
                          secs % 60,
-                         (int)((ti / 1000000) % 1000));
+                         (int)(ti % 1000));
                 d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
             }
         }
@@ -290,6 +314,12 @@ static void mux_print_help(CharDriverState *chr)
     }
 }
 
+static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
+{
+    if (d->chr_event[mux_nr])
+        d->chr_event[mux_nr](d->ext_opaque[mux_nr], event);
+}
+
 static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
 {
     if (d->term_got_escape) {
@@ -321,9 +351,11 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
             break;
         case 'c':
             /* Switch to the next registered device */
+            mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_OUT);
             chr->focus++;
             if (chr->focus >= d->mux_cnt)
                 chr->focus = 0;
+            mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN);
             break;
        case 't':
            term_timestamps = !term_timestamps;
@@ -344,11 +376,11 @@ static void mux_chr_accept_input(CharDriverState *chr)
     int m = chr->focus;
     MuxDriver *d = chr->opaque;
 
-    while (d->prod != d->cons &&
+    while (d->prod[m] != d->cons[m] &&
            d->chr_can_read[m] &&
            d->chr_can_read[m](d->ext_opaque[m])) {
         d->chr_read[m](d->ext_opaque[m],
-                       &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1);
+                       &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
     }
 }
 
@@ -356,11 +388,12 @@ static int mux_chr_can_read(void *opaque)
 {
     CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;
+    int m = chr->focus;
 
-    if ((d->prod - d->cons) < MUX_BUFFER_SIZE)
+    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
         return 1;
-    if (d->chr_can_read[chr->focus])
-        return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
+    if (d->chr_can_read[m])
+        return d->chr_can_read[m](d->ext_opaque[m]);
     return 0;
 }
 
@@ -375,12 +408,12 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
 
     for(i = 0; i < size; i++)
         if (mux_proc_byte(chr, d, buf[i])) {
-            if (d->prod == d->cons &&
+            if (d->prod[m] == d->cons[m] &&
                 d->chr_can_read[m] &&
                 d->chr_can_read[m](d->ext_opaque[m]))
                 d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
             else
-                d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i];
+                d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
         }
 }
 
@@ -392,8 +425,7 @@ static void mux_chr_event(void *opaque, int event)
 
     /* Send the event to all registered listeners */
     for (i = 0; i < d->mux_cnt; i++)
-        if (d->chr_event[i])
-            d->chr_event[i](d->ext_opaque[i], event);
+        mux_chr_send_event(d, i, event);
 }
 
 static void mux_chr_update_read_handler(CharDriverState *chr)
@@ -423,13 +455,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
     MuxDriver *d;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
     d = qemu_mallocz(sizeof(MuxDriver));
-    if (!d) {
-        free(chr);
-        return NULL;
-    }
 
     chr->opaque = d;
     d->drv = drv;
@@ -450,7 +476,6 @@ int send_all(int fd, const void *buf, int len1)
     while (len > 0) {
         ret = send(fd, buf, len, 0);
         if (ret < 0) {
-            int errno;
             errno = WSAGetLastError();
             if (errno != WSAEWOULDBLOCK) {
                 return -1;
@@ -546,7 +571,7 @@ static void fd_chr_update_read_handler(CharDriverState *chr)
     FDCharDriver *s = chr->opaque;
 
     if (s->fd_in >= 0) {
-        if (nographic && s->fd_in == 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
         } else {
             qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
                                  fd_chr_read, NULL, chr);
@@ -559,7 +584,7 @@ static void fd_chr_close(struct CharDriverState *chr)
     FDCharDriver *s = chr->opaque;
 
     if (s->fd_in >= 0) {
-        if (nographic && s->fd_in == 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
         } else {
             qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
         }
@@ -575,13 +600,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     FDCharDriver *s;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
     s = qemu_mallocz(sizeof(FDCharDriver));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
     s->fd_in = fd_in;
     s->fd_out = fd_out;
     chr->opaque = s;
@@ -695,7 +714,7 @@ static void term_init(void)
     tty.c_oflag |= OPOST;
     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
     /* if graphical mode, we allow Ctrl-C handling */
-    if (nographic)
+    if (display_type == DT_NOGRAPHIC)
         tty.c_lflag &= ~ISIG;
     tty.c_cflag &= ~(CSIZE|PARENB);
     tty.c_cflag |= CS8;
@@ -735,8 +754,8 @@ static CharDriverState *qemu_chr_open_stdio(void)
 
 #ifdef __sun__
 /* Once Solaris has openpty(), this is going to be removed. */
-int openpty(int *amaster, int *aslave, char *name,
-            struct termios *termp, struct winsize *winp)
+static int openpty(int *amaster, int *aslave, char *name,
+                   struct termios *termp, struct winsize *winp)
 {
         const char *slave;
         int mfd = -1, sfd = -1;
@@ -776,7 +795,7 @@ err:
         return -1;
 }
 
-void cfmakeraw (struct termios *termios_p)
+static void cfmakeraw (struct termios *termios_p)
 {
         termios_p->c_iflag &=
                 ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
@@ -791,7 +810,7 @@ void cfmakeraw (struct termios *termios_p)
 #endif
 
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__)
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
 
 typedef struct {
     int fd;
@@ -910,6 +929,8 @@ static void pty_chr_close(struct CharDriverState *chr)
 
     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
     close(s->fd);
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
     qemu_free(s);
 }
 
@@ -919,7 +940,7 @@ static CharDriverState *qemu_chr_open_pty(void)
     PtyCharDriver *s;
     struct termios tty;
     int slave_fd, len;
-#if defined(__OpenBSD__)
+#if defined(__OpenBSD__) || defined(__DragonFly__)
     char pty_name[PATH_MAX];
 #define q_ptsname(x) pty_name
 #else
@@ -928,19 +949,14 @@ static CharDriverState *qemu_chr_open_pty(void)
 #endif
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
     s = qemu_mallocz(sizeof(PtyCharDriver));
-    if (!s) {
-        qemu_free(chr);
-        return NULL;
-    }
 
     if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
         return NULL;
     }
 
     /* Set raw attributes on the pty. */
+    tcgetattr(slave_fd, &tty);
     cfmakeraw(&tty);
     tcsetattr(slave_fd, TCSAFLUSH, &tty);
     close(slave_fd);
@@ -1065,17 +1081,17 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
             int *targ = (int *)arg;
             ioctl(s->fd_in, TIOCMGET, &sarg);
             *targ = 0;
-            if (sarg | TIOCM_CTS)
+            if (sarg & TIOCM_CTS)
                 *targ |= CHR_TIOCM_CTS;
-            if (sarg | TIOCM_CAR)
+            if (sarg & TIOCM_CAR)
                 *targ |= CHR_TIOCM_CAR;
-            if (sarg | TIOCM_DSR)
+            if (sarg & TIOCM_DSR)
                 *targ |= CHR_TIOCM_DSR;
-            if (sarg | TIOCM_RI)
+            if (sarg & TIOCM_RI)
                 *targ |= CHR_TIOCM_RI;
-            if (sarg | TIOCM_DTR)
+            if (sarg & TIOCM_DTR)
                 *targ |= CHR_TIOCM_DTR;
-            if (sarg | TIOCM_RTS)
+            if (sarg & TIOCM_RTS)
                 *targ |= CHR_TIOCM_RTS;
         }
         break;
@@ -1083,9 +1099,20 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
         {
             int sarg = *(int *)arg;
             int targ = 0;
-            if (sarg | CHR_TIOCM_DTR)
+            ioctl(s->fd_in, TIOCMGET, &targ);
+            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
+                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
+            if (sarg & CHR_TIOCM_CTS)
+                targ |= TIOCM_CTS;
+            if (sarg & CHR_TIOCM_CAR)
+                targ |= TIOCM_CAR;
+            if (sarg & CHR_TIOCM_DSR)
+                targ |= TIOCM_DSR;
+            if (sarg & CHR_TIOCM_RI)
+                targ |= TIOCM_RI;
+            if (sarg & CHR_TIOCM_DTR)
                 targ |= TIOCM_DTR;
-            if (sarg | CHR_TIOCM_RTS)
+            if (sarg & CHR_TIOCM_RTS)
                 targ |= TIOCM_RTS;
             ioctl(s->fd_in, TIOCMSET, &targ);
         }
@@ -1244,19 +1271,10 @@ static CharDriverState *qemu_chr_open_pp(const char *filename)
     }
 
     drv = qemu_mallocz(sizeof(ParallelCharDriver));
-    if (!drv) {
-        close(fd);
-        return NULL;
-    }
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr) {
-       qemu_free(drv);
-        close(fd);
-        return NULL;
-    }
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
     chr->chr_close = pp_close;
@@ -1268,6 +1286,61 @@ static CharDriverState *qemu_chr_open_pp(const char *filename)
 }
 #endif /* __linux__ */
 
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    int fd = (int)chr->opaque;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPIGDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPIGCTRL, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISCTRL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPIGSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    fd = open(filename, O_RDWR);
+    if (fd < 0)
+        return NULL;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->opaque = (void *)fd;
+    chr->chr_write = null_chr_write;
+    chr->chr_ioctl = pp_ioctl;
+    return chr;
+}
+#endif
+
 #else /* _WIN32 */
 
 typedef struct {
@@ -1474,13 +1547,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename)
     WinCharState *s;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
     s = qemu_mallocz(sizeof(WinCharState));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
@@ -1579,13 +1646,7 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename)
     WinCharState *s;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
     s = qemu_mallocz(sizeof(WinCharState));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
@@ -1605,13 +1666,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
     WinCharState *s;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
     s = qemu_mallocz(sizeof(WinCharState));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
     s->hcom = fd_out;
     chr->opaque = s;
     chr->chr_write = win_chr_write;
@@ -1705,6 +1760,16 @@ static void udp_chr_update_read_handler(CharDriverState *chr)
     }
 }
 
+static void udp_chr_close(CharDriverState *chr)
+{
+    NetCharDriver *s = chr->opaque;
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+    }
+    qemu_free(s);
+}
+
 static CharDriverState *qemu_chr_open_udp(const char *def)
 {
     CharDriverState *chr = NULL;
@@ -1713,11 +1778,7 @@ static CharDriverState *qemu_chr_open_udp(const char *def)
     struct sockaddr_in saddr;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        goto return_err;
     s = qemu_mallocz(sizeof(NetCharDriver));
-    if (!s)
-        goto return_err;
 
     fd = socket(PF_INET, SOCK_DGRAM, 0);
     if (fd < 0) {
@@ -1742,6 +1803,7 @@ static CharDriverState *qemu_chr_open_udp(const char *def)
     chr->opaque = s;
     chr->chr_write = udp_chr_write;
     chr->chr_update_read_handler = udp_chr_update_read_handler;
+    chr->chr_close = udp_chr_close;
     return chr;
 
 return_err:
@@ -1944,10 +2006,14 @@ static void tcp_chr_accept(void *opaque)
 static void tcp_chr_close(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
-    if (s->fd >= 0)
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
         closesocket(s->fd);
-    if (s->listen_fd >= 0)
+    }
+    if (s->listen_fd >= 0) {
+        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
         closesocket(s->listen_fd);
+    }
     qemu_free(s);
 }
 
@@ -1957,32 +2023,11 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
 {
     CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;
-    int fd = -1, ret, err, val;
+    int fd = -1, offset = 0;
     int is_listen = 0;
     int is_waitconnect = 1;
     int do_nodelay = 0;
     const char *ptr;
-    struct sockaddr_in saddr;
-#ifndef _WIN32
-    struct sockaddr_un uaddr;
-#endif
-    struct sockaddr *addr;
-    socklen_t addrlen;
-
-#ifndef _WIN32
-    if (is_unix) {
-       addr = (struct sockaddr *)&uaddr;
-       addrlen = sizeof(uaddr);
-       if (parse_unix_path(&uaddr, host_str) < 0)
-           goto fail;
-    } else
-#endif
-    {
-       addr = (struct sockaddr *)&saddr;
-       addrlen = sizeof(saddr);
-       if (parse_host_port(&saddr, host_str) < 0)
-           goto fail;
-    }
 
     ptr = host_str;
     while((ptr = strchr(ptr,','))) {
@@ -1993,6 +2038,12 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
             is_waitconnect = 0;
         } else if (!strncmp(ptr,"nodelay",6)) {
             do_nodelay = 1;
+        } else if (!strncmp(ptr,"to=",3)) {
+            /* nothing, inet_listen() parses this one */;
+        } else if (!strncmp(ptr,"ipv4",4)) {
+            /* nothing, inet_connect() and inet_listen() parse this one */;
+        } else if (!strncmp(ptr,"ipv6",4)) {
+            /* nothing, inet_connect() and inet_listen() parse this one */;
         } else {
             printf("Unknown option: %s\n", ptr);
             goto fail;
@@ -2002,19 +2053,33 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
         is_waitconnect = 0;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        goto fail;
     s = qemu_mallocz(sizeof(TCPCharDriver));
-    if (!s)
-        goto fail;
-
-#ifndef _WIN32
-    if (is_unix)
-       fd = socket(PF_UNIX, SOCK_STREAM, 0);
-    else
-#endif
-       fd = socket(PF_INET, SOCK_STREAM, 0);
 
+    if (is_listen) {
+        chr->filename = qemu_malloc(256);
+        if (is_unix) {
+            pstrcpy(chr->filename, 256, "unix:");
+        } else if (is_telnet) {
+            pstrcpy(chr->filename, 256, "telnet:");
+        } else {
+            pstrcpy(chr->filename, 256, "tcp:");
+        }
+        offset = strlen(chr->filename);
+    }
+    if (is_unix) {
+        if (is_listen) {
+            fd = unix_listen(host_str, chr->filename + offset, 256 - offset);
+        } else {
+            fd = unix_connect(host_str);
+        }
+    } else {
+        if (is_listen) {
+            fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
+                             SOCK_STREAM, 0);
+        } else {
+            fd = inet_connect(host_str, SOCK_STREAM);
+        }
+    }
     if (fd < 0)
         goto fail;
 
@@ -2032,61 +2097,20 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
     chr->chr_close = tcp_chr_close;
 
     if (is_listen) {
-        /* allow fast reuse */
-#ifndef _WIN32
-       if (is_unix) {
-           char path[109];
-           pstrcpy(path, sizeof(path), uaddr.sun_path);
-           unlink(path);
-       } else
-#endif
-       {
-           val = 1;
-           setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
-       }
-
-        ret = bind(fd, addr, addrlen);
-        if (ret < 0)
-            goto fail;
-
-        ret = listen(fd, 0);
-        if (ret < 0)
-            goto fail;
-
         s->listen_fd = fd;
         qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
         if (is_telnet)
             s->do_telnetopt = 1;
     } else {
-        for(;;) {
-            ret = connect(fd, addr, addrlen);
-            if (ret < 0) {
-                err = socket_error();
-                if (err == EINTR || err == EWOULDBLOCK) {
-                } else if (err == EINPROGRESS) {
-                    break;
-#ifdef _WIN32
-                } else if (err == WSAEALREADY) {
-                    break;
-#endif
-                } else {
-                    goto fail;
-                }
-            } else {
-                s->connected = 1;
-                break;
-            }
-        }
+        s->connected = 1;
         s->fd = fd;
         socket_set_nodelay(fd);
-        if (s->connected)
-            tcp_chr_connect(chr);
-        else
-            qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
+        tcp_chr_connect(chr);
     }
 
     if (is_listen && is_waitconnect) {
-        printf("QEMU waiting for connection on: %s\n", host_str);
+        printf("QEMU waiting for connection on: %s\n",
+               chr->filename ? chr->filename : host_str);
         tcp_chr_accept(chr);
         socket_set_nonblock(s->listen_fd);
     }
@@ -2100,19 +2124,16 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
     return NULL;
 }
 
-static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs
-= TAILQ_HEAD_INITIALIZER(chardevs);
-
-CharDriverState *qemu_chr_open(const char *label, const char *filename)
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
 {
     const char *p;
     CharDriverState *chr;
 
     if (!strcmp(filename, "vc")) {
-        chr = text_console_init(&display_state, 0);
+        chr = text_console_init(0);
     } else
     if (strstart(filename, "vc:", &p)) {
-        chr = text_console_init(&display_state, p);
+        chr = text_console_init(p);
     } else
     if (!strcmp(filename, "null")) {
         chr = qemu_chr_open_null();
@@ -2127,13 +2148,15 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename)
         chr = qemu_chr_open_udp(p);
     } else
     if (strstart(filename, "mon:", &p)) {
-        chr = qemu_chr_open(label, p);
+        chr = qemu_chr_open(label, p, NULL);
         if (chr) {
             chr = qemu_chr_open_mux(chr);
-            monitor_init(chr, !nographic);
+            monitor_init(chr, MONITOR_USE_READLINE);
         } else {
             printf("Unable to open driver: %s\n", p);
         }
+    } else if (!strcmp(filename, "msmouse")) {
+        chr = qemu_chr_open_msmouse();
     } else
 #ifndef _WIN32
     if (strstart(filename, "unix:", &p)) {
@@ -2151,9 +2174,13 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename)
     if (strstart(filename, "/dev/parport", NULL)) {
         chr = qemu_chr_open_pp(filename);
     } else
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+    if (strstart(filename, "/dev/ppi", NULL)) {
+        chr = qemu_chr_open_pp(filename);
+    } else
 #endif
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__)
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
     if (strstart(filename, "/dev/", NULL)) {
         chr = qemu_chr_open_tty(filename);
     } else
@@ -2184,6 +2211,7 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename)
     if (chr) {
         if (!chr->filename)
             chr->filename = qemu_strdup(filename);
+        chr->init = init;
         chr->label = qemu_strdup(label);
         TAILQ_INSERT_TAIL(&chardevs, chr, next);
     }
@@ -2200,11 +2228,11 @@ void qemu_chr_close(CharDriverState *chr)
     qemu_free(chr);
 }
 
-void qemu_chr_info(void)
+void qemu_chr_info(Monitor *mon)
 {
     CharDriverState *chr;
 
     TAILQ_FOREACH(chr, &chardevs, next) {
-        term_printf("%s: filename=%s\n", chr->label, chr->filename);
+        monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename);
     }
 }