qdev: drop iobase properties from isa bus
[qemu] / qemu-char.c
index 26e8825..c25ed1c 100644 (file)
 #include <dirent.h>
 #include <netdb.h>
 #include <sys/select.h>
-#ifdef _BSD
+#ifdef CONFIG_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
@@ -164,6 +168,11 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
     s->chr_read(s->handler_opaque, buf, len);
 }
 
+int qemu_chr_get_msgfd(CharDriverState *s)
+{
+    return s->get_msgfd ? s->get_msgfd(s) : -1;
+}
+
 void qemu_chr_accept_input(CharDriverState *s)
 {
     if (s->chr_accept_input)
@@ -215,8 +224,6 @@ static CharDriverState *qemu_chr_open_null(void)
 }
 
 /* MUX driver for serial I/O splitting */
-static int term_timestamps;
-static int64_t term_timestamps_start;
 #define MAX_MUX 4
 #define MUX_BUFFER_SIZE 32     /* Must be a power of 2.  */
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
@@ -235,6 +242,9 @@ typedef struct {
     unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
     int prod[MAX_MUX];
     int cons[MAX_MUX];
+    int timestamps;
+    int linestart;
+    int64_t timestamps_start;
 } MuxDriver;
 
 
@@ -242,23 +252,22 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     MuxDriver *d = chr->opaque;
     int ret;
-    if (!term_timestamps) {
+    if (!d->timestamps) {
         ret = d->drv->chr_write(d->drv, buf, len);
     } else {
         int i;
 
         ret = 0;
-        for(i = 0; i < len; i++) {
-            ret += d->drv->chr_write(d->drv, buf+i, 1);
-            if (buf[i] == '\n') {
+        for (i = 0; i < len; i++) {
+            if (d->linestart) {
                 char buf1[64];
                 int64_t ti;
                 int secs;
 
                 ti = qemu_get_clock(rt_clock);
-                if (term_timestamps_start == -1)
-                    term_timestamps_start = ti;
-                ti -= term_timestamps_start;
+                if (d->timestamps_start == -1)
+                    d->timestamps_start = ti;
+                ti -= d->timestamps_start;
                 secs = ti / 1000;
                 snprintf(buf1, sizeof(buf1),
                          "[%02d:%02d:%02d.%03d] ",
@@ -267,6 +276,11 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
                          secs % 60,
                          (int)(ti % 1000));
                 d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
+                d->linestart = 0;
+            }
+            ret += d->drv->chr_write(d->drv, buf+i, 1);
+            if (buf[i] == '\n') {
+                d->linestart = 1;
             }
         }
     }
@@ -336,9 +350,9 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
             }
         case 's':
             {
-                int i;
-                for (i = 0; i < nb_drives; i++) {
-                        bdrv_commit(drives_table[i].bdrv);
+                DriveInfo *dinfo;
+                TAILQ_FOREACH(dinfo, &drives, next) {
+                    bdrv_commit(dinfo->bdrv);
                 }
             }
             break;
@@ -353,10 +367,11 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
                 chr->focus = 0;
             mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN);
             break;
-       case 't':
-           term_timestamps = !term_timestamps;
-           term_timestamps_start = -1;
-           break;
+        case 't':
+            d->timestamps = !d->timestamps;
+            d->timestamps_start = -1;
+            d->linestart = 0;
+            break;
         }
     } else if (ch == term_escape_char) {
         d->term_got_escape = 1;
@@ -555,6 +570,7 @@ 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);
         return;
     }
     if (size > 0) {
@@ -567,7 +583,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);
@@ -580,13 +596,14 @@ 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);
         }
     }
 
     qemu_free(s);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
 /* open a character device to a unix fd */
@@ -675,6 +692,7 @@ 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);
         return;
     }
     if (size > 0) {
@@ -710,7 +728,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;
@@ -750,8 +768,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;
@@ -791,7 +809,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);
@@ -806,7 +824,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;
@@ -925,7 +943,10 @@ 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);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
 static CharDriverState *qemu_chr_open_pty(void)
@@ -934,7 +955,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
@@ -1247,6 +1268,7 @@ static void pp_close(CharDriverState *chr)
     ioctl(fd, PPRELEASE);
     close(fd);
     qemu_free(drv);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
 static CharDriverState *qemu_chr_open_pp(const char *filename)
@@ -1280,7 +1302,7 @@ static CharDriverState *qemu_chr_open_pp(const char *filename)
 }
 #endif /* __linux__ */
 
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
     int fd = (int)chr->opaque;
@@ -1373,6 +1395,8 @@ static void win_chr_close(CharDriverState *chr)
         qemu_del_polling_cb(win_chr_pipe_poll, chr);
     else
         qemu_del_polling_cb(win_chr_poll, chr);
+
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
 static int win_chr_init(CharDriverState *chr, const char *filename)
@@ -1702,7 +1726,7 @@ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     NetCharDriver *s = chr->opaque;
 
-    return sendto(s->fd, buf, len, 0,
+    return sendto(s->fd, (const void *)buf, len, 0,
                   (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
 }
 
@@ -1731,7 +1755,7 @@ static void udp_chr_read(void *opaque)
 
     if (s->max_size == 0)
         return;
-    s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);
+    s->bufcnt = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
     s->bufptr = s->bufcnt;
     if (s->bufcnt <= 0)
         return;
@@ -1754,6 +1778,17 @@ 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);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
+}
+
 static CharDriverState *qemu_chr_open_udp(const char *def)
 {
     CharDriverState *chr = NULL;
@@ -1787,6 +1822,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:
@@ -1809,6 +1845,7 @@ typedef struct {
     int do_telnetopt;
     int do_nodelay;
     int is_unix;
+    int msgfd;
 } TCPCharDriver;
 
 static void tcp_chr_accept(void *opaque);
@@ -1884,6 +1921,70 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
     *size = j;
 }
 
+static int tcp_get_msgfd(CharDriverState *chr)
+{
+    TCPCharDriver *s = chr->opaque;
+
+    return s->msgfd;
+}
+
+#ifndef _WIN32
+static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
+{
+    TCPCharDriver *s = chr->opaque;
+    struct cmsghdr *cmsg;
+
+    for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+        int fd;
+
+        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+            cmsg->cmsg_level != SOL_SOCKET ||
+            cmsg->cmsg_type != SCM_RIGHTS)
+            continue;
+
+        fd = *((int *)CMSG_DATA(cmsg));
+        if (fd < 0)
+            continue;
+
+        if (s->msgfd != -1)
+            close(s->msgfd);
+        s->msgfd = fd;
+    }
+}
+
+static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+{
+    TCPCharDriver *s = chr->opaque;
+    struct msghdr msg = { NULL, };
+    struct iovec iov[1];
+    union {
+        struct cmsghdr cmsg;
+        char control[CMSG_SPACE(sizeof(int))];
+    } msg_control;
+    ssize_t ret;
+
+    iov[0].iov_base = buf;
+    iov[0].iov_len = len;
+
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &msg_control;
+    msg.msg_controllen = sizeof(msg_control);
+
+    ret = recvmsg(s->fd, &msg, 0);
+    if (ret > 0 && s->is_unix)
+        unix_process_msgfd(chr, &msg);
+
+    return ret;
+}
+#else
+static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+{
+    TCPCharDriver *s = chr->opaque;
+    return recv(s->fd, buf, len, 0);
+}
+#endif
+
 static void tcp_chr_read(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -1896,7 +1997,7 @@ static void tcp_chr_read(void *opaque)
     len = sizeof(buf);
     if (len > s->max_size)
         len = s->max_size;
-    size = recv(s->fd, buf, len, 0);
+    size = tcp_chr_recv(chr, (void *)buf, len);
     if (size == 0) {
         /* connection closed */
         s->connected = 0;
@@ -1906,11 +2007,16 @@ static void tcp_chr_read(void *opaque)
         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
         closesocket(s->fd);
         s->fd = -1;
+        qemu_chr_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);
+        if (s->msgfd != -1) {
+            close(s->msgfd);
+            s->msgfd = -1;
+        }
     }
 }
 
@@ -1989,11 +2095,16 @@ 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);
+    qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
 static CharDriverState *qemu_chr_open_tcp(const char *host_str,
@@ -2068,12 +2179,14 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
     s->connected = 0;
     s->fd = -1;
     s->listen_fd = -1;
+    s->msgfd = -1;
     s->is_unix = is_unix;
     s->do_nodelay = do_nodelay && !is_unix;
 
     chr->opaque = s;
     chr->chr_write = tcp_chr_write;
     chr->chr_close = tcp_chr_close;
+    chr->get_msgfd = tcp_get_msgfd;
 
     if (is_listen) {
         s->listen_fd = fd;
@@ -2109,7 +2222,7 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i
     CharDriverState *chr;
 
     if (!strcmp(filename, "vc")) {
-        chr = text_console_init(0);
+        chr = text_console_init(NULL);
     } else
     if (strstart(filename, "vc:", &p)) {
         chr = text_console_init(p);
@@ -2153,13 +2266,13 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i
     if (strstart(filename, "/dev/parport", NULL)) {
         chr = qemu_chr_open_pp(filename);
     } else
-#elif defined(__FreeBSD__)
+#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