]> git.proxmox.com Git - qemu.git/blobdiff - qemu-char.c
do not reset no_shutdown after we shutdown the vm
[qemu.git] / qemu-char.c
index 4169492213a6650e3983894d55f8bd0591976228..926987b98ada1029317c55fd1bb76ec8dfdf6c11 100644 (file)
@@ -28,7 +28,6 @@
 #include "sysemu.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
-#include "block.h"
 #include "hw/usb.h"
 #include "hw/baum.h"
 #include "hw/msmouse.h"
@@ -36,7 +35,6 @@
 
 #include <unistd.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <time.h>
 #include <errno.h>
 #include <sys/time.h>
@@ -98,6 +96,7 @@
 #endif
 
 #include "qemu_socket.h"
+#include "ui/qemu-spice.h"
 
 #define READ_BUF_LEN 4096
 
@@ -109,6 +108,16 @@ static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
 
 static void qemu_chr_event(CharDriverState *s, int event)
 {
+    /* Keep track if the char device is open */
+    switch (event) {
+        case CHR_EVENT_OPENED:
+            s->opened = 1;
+            break;
+        case CHR_EVENT_CLOSED:
+            s->opened = 0;
+            break;
+    }
+
     if (!s->chr_event)
         return;
     s->chr_event(s->handler_opaque, event);
@@ -182,17 +191,27 @@ void qemu_chr_send_event(CharDriverState *s, int event)
 }
 
 void qemu_chr_add_handlers(CharDriverState *s,
-                           IOCanRWHandler *fd_can_read,
+                           IOCanReadHandler *fd_can_read,
                            IOReadHandler *fd_read,
                            IOEventHandler *fd_event,
                            void *opaque)
 {
+    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+        /* chr driver being released. */
+        ++s->avail_connections;
+    }
     s->chr_can_read = fd_can_read;
     s->chr_read = fd_read;
     s->chr_event = fd_event;
     s->handler_opaque = opaque;
     if (s->chr_update_read_handler)
         s->chr_update_read_handler(s);
+
+    /* We're connecting to an already opened device, so let's make sure we
+       also get the open event */
+    if (s->opened) {
+        qemu_chr_generic_open(s);
+    }
 }
 
 static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
@@ -200,13 +219,15 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
+static int qemu_chr_open_null(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
     chr->chr_write = null_chr_write;
-    return chr;
+
+    *_chr= chr;
+    return 0;
 }
 
 /* MUX driver for serial I/O splitting */
@@ -214,7 +235,7 @@ static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
 #define MUX_BUFFER_SIZE 32     /* Must be a power of 2.  */
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
 typedef struct {
-    IOCanRWHandler *chr_can_read[MAX_MUX];
+    IOCanReadHandler *chr_can_read[MAX_MUX];
     IOReadHandler *chr_read[MAX_MUX];
     IOEventHandler *chr_event[MAX_MUX];
     void *ext_opaque[MAX_MUX];
@@ -251,7 +272,7 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
                 int64_t ti;
                 int secs;
 
-                ti = qemu_get_clock(rt_clock);
+                ti = qemu_get_clock_ms(rt_clock);
                 if (d->timestamps_start == -1)
                     d->timestamps_start = ti;
                 ti -= d->timestamps_start;
@@ -336,12 +357,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
                  break;
             }
         case 's':
-            {
-                DriveInfo *dinfo;
-                QTAILQ_FOREACH(dinfo, &drives, next) {
-                    bdrv_commit(dinfo->bdrv);
-                }
-            }
+            bdrv_commit_all();
             break;
         case 'b':
             qemu_chr_event(chr, CHR_EVENT_BREAK);
@@ -465,6 +481,13 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
     chr->chr_write = mux_chr_write;
     chr->chr_update_read_handler = mux_chr_update_read_handler;
     chr->chr_accept_input = mux_chr_accept_input;
+    /* Frontend guest-open / -close notification is not support with muxes */
+    chr->chr_guest_open = NULL;
+    chr->chr_guest_close = NULL;
+
+    /* Muxes are always open on creation */
+    qemu_chr_generic_open(chr);
+
     return chr;
 }
 
@@ -494,9 +517,10 @@ int send_all(int fd, const void *buf, int len1)
 
 #else
 
-static int unix_write(int fd, const uint8_t *buf, int len1)
+int send_all(int fd, const void *_buf, int len1)
 {
     int ret, len;
+    const uint8_t *buf = _buf;
 
     len = len1;
     while (len > 0) {
@@ -513,11 +537,6 @@ static int unix_write(int fd, const uint8_t *buf, int len1)
     }
     return len1 - len;
 }
-
-int send_all(int fd, const void *buf, int len1)
-{
-    return unix_write(fd, buf, len1);
-}
 #endif /* !_WIN32 */
 
 #ifndef _WIN32
@@ -617,18 +636,21 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
+static int qemu_chr_open_file_out(QemuOpts *opts, CharDriverState **_chr)
 {
     int fd_out;
 
     TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
                       O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
-    if (fd_out < 0)
-        return NULL;
-    return qemu_chr_open_fd(-1, fd_out);
+    if (fd_out < 0) {
+        return -errno;
+    }
+
+    *_chr = qemu_chr_open_fd(-1, fd_out);
+    return 0;
 }
 
-static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
+static int qemu_chr_open_pipe(QemuOpts *opts, CharDriverState **_chr)
 {
     int fd_in, fd_out;
     char filename_in[256], filename_out[256];
@@ -636,7 +658,7 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
 
     if (filename == NULL) {
         fprintf(stderr, "chardev: pipe: no filename given\n");
-        return NULL;
+        return -EINVAL;
     }
 
     snprintf(filename_in, 256, "%s.in", filename);
@@ -648,11 +670,14 @@ 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)
-            return NULL;
+        TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
+        if (fd_in < 0) {
+            return -errno;
+        }
     }
-    return qemu_chr_open_fd(fd_in, fd_out);
+
+    *_chr = qemu_chr_open_fd(fd_in, fd_out);
+    return 0;
 }
 
 
@@ -705,7 +730,7 @@ static void stdio_read(void *opaque)
 /* init terminal so that we can grab keys */
 static struct termios oldtty;
 static int old_fd0_flags;
-static int term_atexit_done;
+static bool stdio_allow_signal;
 
 static void term_exit(void)
 {
@@ -713,32 +738,26 @@ static void term_exit(void)
     fcntl(0, F_SETFL, old_fd0_flags);
 }
 
-static void term_init(QemuOpts *opts)
+static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo)
 {
     struct termios tty;
 
-    tcgetattr (0, &tty);
-    oldtty = tty;
-    old_fd0_flags = fcntl(0, F_GETFL);
-
-    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+    tty = oldtty;
+    if (!echo) {
+        tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                           |INLCR|IGNCR|ICRNL|IXON);
-    tty.c_oflag |= OPOST;
-    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+        tty.c_oflag |= OPOST;
+        tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+        tty.c_cflag &= ~(CSIZE|PARENB);
+        tty.c_cflag |= CS8;
+        tty.c_cc[VMIN] = 1;
+        tty.c_cc[VTIME] = 0;
+    }
     /* if graphical mode, we allow Ctrl-C handling */
-    if (!qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC))
+    if (!stdio_allow_signal)
         tty.c_lflag &= ~ISIG;
-    tty.c_cflag &= ~(CSIZE|PARENB);
-    tty.c_cflag |= CS8;
-    tty.c_cc[VMIN] = 1;
-    tty.c_cc[VTIME] = 0;
 
     tcsetattr (0, TCSANOW, &tty);
-
-    if (!term_atexit_done++)
-        atexit(term_exit);
-
-    fcntl(0, F_SETFL, O_NONBLOCK);
 }
 
 static void qemu_chr_close_stdio(struct CharDriverState *chr)
@@ -749,19 +768,32 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr)
     fd_chr_close(chr);
 }
 
-static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
+static int qemu_chr_open_stdio(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
 
-    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
-        return NULL;
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS) {
+        return -EBUSY;
+    }
+
+    if (stdio_nb_clients == 0) {
+        old_fd0_flags = fcntl(0, F_GETFL);
+        tcgetattr (0, &oldtty);
+        fcntl(0, F_SETFL, O_NONBLOCK);
+        atexit(term_exit);
+    }
+
     chr = qemu_chr_open_fd(0, 1);
     chr->chr_close = qemu_chr_close_stdio;
+    chr->chr_set_echo = qemu_chr_set_echo_stdio;
     qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
     stdio_nb_clients++;
-    term_init(opts);
+    stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
+                                           display_type != DT_NOGRAPHIC);
+    qemu_chr_set_echo(chr, false);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 
 #ifdef __sun__
@@ -896,7 +928,7 @@ static void pty_chr_update_read_handler(CharDriverState *chr)
      * timeout to the normal (much longer) poll interval before the
      * timer triggers.
      */
-    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
+    qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 10);
 }
 
 static void pty_chr_state(CharDriverState *chr, int connected)
@@ -910,7 +942,7 @@ static void pty_chr_state(CharDriverState *chr, int connected)
         /* (re-)connect poll interval for idle guests: once per second.
          * We check more frequently in case the guests sends data to
          * the virtual device linked to our pty. */
-        qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
+        qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 1000);
     } else {
         if (!s->connected)
             qemu_chr_generic_open(chr);
@@ -948,7 +980,7 @@ static void pty_chr_close(struct CharDriverState *chr)
     qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr;
     PtyCharDriver *s;
@@ -966,7 +998,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
     s = qemu_mallocz(sizeof(PtyCharDriver));
 
     if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
-        return NULL;
+        return -errno;
     }
 
     /* Set raw attributes on the pty. */
@@ -986,9 +1018,10 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
     chr->chr_update_read_handler = pty_chr_update_read_handler;
     chr->chr_close = pty_chr_close;
 
-    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
+    s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 
 static void tty_serial_init(int fd, int speed,
@@ -1189,30 +1222,28 @@ static void qemu_chr_close_tty(CharDriverState *chr)
     }
 }
 
-static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
+static int qemu_chr_open_tty(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     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;
+        return -errno;
     }
     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;
+
+    *_chr = chr;
+    return 0;
 }
 #else  /* ! __linux__ && ! __sun__ */
-static CharDriverState *qemu_chr_open_pty(void)
+static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
 {
-    return NULL;
+    return -ENOTSUP;
 }
 #endif /* __linux__ || __sun__ */
 
@@ -1326,7 +1357,7 @@ static void pp_close(CharDriverState *chr)
     qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1334,12 +1365,13 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
     int fd;
 
     TFR(fd = open(filename, O_RDWR));
-    if (fd < 0)
-        return NULL;
+    if (fd < 0) {
+        return -errno;
+    }
 
     if (ioctl(fd, PPCLAIM) < 0) {
         close(fd);
-        return NULL;
+        return -errno;
     }
 
     drv = qemu_mallocz(sizeof(ParallelCharDriver));
@@ -1354,14 +1386,15 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
 
     qemu_chr_generic_open(chr);
 
-    return chr;
+    *_chr = chr;
+    return 0;
 }
 #endif /* __linux__ */
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    int fd = (int)chr->opaque;
+    int fd = (int)(intptr_t)chr->opaque;
     uint8_t b;
 
     switch(cmd) {
@@ -1396,21 +1429,24 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     int fd;
 
-    fd = open(filename, O_RDWR);
-    if (fd < 0)
-        return NULL;
+    fd = qemu_open(filename, O_RDWR);
+    if (fd < 0) {
+        return -errno;
+    }
 
     chr = qemu_mallocz(sizeof(CharDriverState));
-    chr->opaque = (void *)fd;
+    chr->opaque = (void *)(intptr_t)fd;
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 #endif
 
@@ -1616,7 +1652,7 @@ static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
+static int qemu_chr_open_win(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1631,10 +1667,12 @@ static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
     if (win_chr_init(chr, filename) < 0) {
         free(s);
         free(chr);
-        return NULL;
+        return -EIO;
     }
     qemu_chr_generic_open(chr);
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 
 static int win_chr_pipe_poll(void *opaque)
@@ -1716,7 +1754,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 }
 
 
-static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
+static int qemu_chr_open_win_pipe(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
@@ -1731,10 +1769,12 @@ static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
     if (win_chr_pipe_init(chr, filename) < 0) {
         free(s);
         free(chr);
-        return NULL;
+        return -EIO;
     }
     qemu_chr_generic_open(chr);
-    return chr;
+
+    *_chr = chr;
+    return 0;
 }
 
 static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
@@ -1751,22 +1791,23 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
     return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts)
+static int qemu_chr_open_win_con(QemuOpts *opts, CharDriverState **_chr)
 {
-    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE), chr);
 }
 
-static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
+static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr)
 {
     const char *file_out = qemu_opt_get(opts, "path");
     HANDLE fd_out;
 
     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (fd_out == INVALID_HANDLE_VALUE)
-        return NULL;
+    if (fd_out == INVALID_HANDLE_VALUE) {
+        return -EIO;
+    }
 
-    return qemu_chr_open_win_file(fd_out);
+    return qemu_chr_open_win_file(fd_out, _chr);
 }
 #endif /* !_WIN32 */
 
@@ -1847,11 +1888,12 @@ static void udp_chr_close(CharDriverState *chr)
     qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
+static int qemu_chr_open_udp(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;
     int fd = -1;
+    int ret;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
     s = qemu_mallocz(sizeof(NetCharDriver));
@@ -1859,6 +1901,7 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
     fd = inet_dgram_opts(opts);
     if (fd < 0) {
         fprintf(stderr, "inet_dgram_opts failed\n");
+        ret = -errno;
         goto return_err;
     }
 
@@ -1869,16 +1912,17 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
     chr->chr_write = udp_chr_write;
     chr->chr_update_read_handler = udp_chr_update_read_handler;
     chr->chr_close = udp_chr_close;
-    return chr;
+
+    *_chr = chr;
+    return 0;
 
 return_err:
-    if (chr)
-        free(chr);
-    if (s)
-        free(s);
-    if (fd >= 0)
+    qemu_free(chr);
+    qemu_free(s);
+    if (fd >= 0) {
         closesocket(fd);
-    return NULL;
+    }
+    return ret;
 }
 
 /***********************************************************/
@@ -1970,8 +2014,9 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
 static int tcp_get_msgfd(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
-
-    return s->msgfd;
+    int fd = s->msgfd;
+    s->msgfd = -1;
+    return fd;
 }
 
 #ifndef _WIN32
@@ -2059,13 +2104,16 @@ static void tcp_chr_read(void *opaque)
             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;
-        }
     }
 }
 
+#ifndef _WIN32
+CharDriverState *qemu_chr_open_eventfd(int eventfd)
+{
+    return qemu_chr_open_fd(eventfd, eventfd);
+}
+#endif
+
 static void tcp_chr_connect(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2153,7 +2201,7 @@ static void tcp_chr_close(CharDriverState *chr)
     qemu_chr_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
+static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
 {
     CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;
@@ -2163,6 +2211,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     int do_nodelay;
     int is_unix;
     int is_telnet;
+    int ret;
 
     is_listen      = qemu_opt_get_bool(opts, "server", 0);
     is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
@@ -2188,8 +2237,10 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
             fd = inet_connect_opts(opts);
         }
     }
-    if (fd < 0)
+    if (fd < 0) {
+        ret = -errno;
         goto fail;
+    }
 
     if (!is_waitconnect)
         socket_set_nonblock(fd);
@@ -2241,14 +2292,80 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
         tcp_chr_accept(chr);
         socket_set_nonblock(s->listen_fd);
     }
-    return chr;
+
+    *_chr = chr;
+    return 0;
 
  fail:
     if (fd >= 0)
         closesocket(fd);
     qemu_free(s);
     qemu_free(chr);
-    return NULL;
+    return ret;
+}
+
+/***********************************************************/
+/* Memory chardev */
+typedef struct {
+    size_t outbuf_size;
+    size_t outbuf_capacity;
+    uint8_t *outbuf;
+} MemoryDriver;
+
+static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MemoryDriver *d = chr->opaque;
+
+    /* TODO: the QString implementation has the same code, we should
+     * introduce a generic way to do this in cutils.c */
+    if (d->outbuf_capacity < d->outbuf_size + len) {
+        /* grow outbuf */
+        d->outbuf_capacity += len;
+        d->outbuf_capacity *= 2;
+        d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity);
+    }
+
+    memcpy(d->outbuf + d->outbuf_size, buf, len);
+    d->outbuf_size += len;
+
+    return len;
+}
+
+void qemu_chr_init_mem(CharDriverState *chr)
+{
+    MemoryDriver *d;
+
+    d = qemu_malloc(sizeof(*d));
+    d->outbuf_size = 0;
+    d->outbuf_capacity = 4096;
+    d->outbuf = qemu_mallocz(d->outbuf_capacity);
+
+    memset(chr, 0, sizeof(*chr));
+    chr->opaque = d;
+    chr->chr_write = mem_chr_write;
+}
+
+QString *qemu_chr_mem_to_qs(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
+}
+
+/* NOTE: this driver can not be closed with qemu_chr_close()! */
+void qemu_chr_close_mem(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+
+    qemu_free(d->outbuf);
+    qemu_free(chr->opaque);
+    chr->opaque = NULL;
+    chr->chr_write = NULL;
+}
+
+size_t qemu_chr_mem_osize(const CharDriverState *chr)
+{
+    const MemoryDriver *d = chr->opaque;
+    return d->outbuf_size;
 }
 
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
@@ -2258,7 +2375,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
     const char *p;
     QemuOpts *opts;
 
-    opts = qemu_opts_create(&qemu_chardev_opts, label, 1);
+    opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1);
     if (NULL == opts)
         return NULL;
 
@@ -2333,8 +2450,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
         qemu_opt_set(opts, "backend", "udp");
         if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
             host[0] = 0;
-            if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
-                fprintf(stderr, "udp #1\n");
+            if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
                 goto fail;
             }
         }
@@ -2345,7 +2461,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
             if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
                 host[0] = 0;
                 if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
-                    fprintf(stderr, "udp #2\n");
                     goto fail;
                 }
             }
@@ -2373,14 +2488,13 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
     }
 
 fail:
-    fprintf(stderr, "%s: fail on \"%s\"\n", __FUNCTION__, filename);
     qemu_opts_del(opts);
     return NULL;
 }
 
 static const struct {
     const char *name;
-    CharDriverState *(*open)(QemuOpts *opts);
+    int (*open)(QemuOpts *opts, CharDriverState **chr);
 } backend_table[] = {
     { .name = "null",      .open = qemu_chr_open_null },
     { .name = "socket",    .open = qemu_chr_open_socket },
@@ -2410,6 +2524,9 @@ static const struct {
     || defined(__FreeBSD_kernel__)
     { .name = "parport",   .open = qemu_chr_open_pp },
 #endif
+#ifdef CONFIG_SPICE
+    { .name = "spicevmc",     .open = qemu_chr_open_spice },
+#endif
 };
 
 CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
@@ -2417,12 +2534,18 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
 {
     CharDriverState *chr;
     int i;
+    int ret;
 
     if (qemu_opts_id(opts) == NULL) {
         fprintf(stderr, "chardev: no id specified\n");
         return NULL;
     }
 
+    if (qemu_opt_get(opts, "backend") == NULL) {
+        fprintf(stderr, "chardev: \"%s\" missing backend\n",
+                qemu_opts_id(opts));
+        return NULL;
+    }
     for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
         if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
             break;
@@ -2433,10 +2556,10 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
         return NULL;
     }
 
-    chr = backend_table[i].open(opts);
-    if (!chr) {
-        fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
-                qemu_opt_get(opts, "backend"));
+    ret = backend_table[i].open(opts, &chr);
+    if (ret < 0) {
+        fprintf(stderr, "chardev: opening backend \"%s\" failed: %s\n",
+                qemu_opt_get(opts, "backend"), strerror(-ret));
         return NULL;
     }
 
@@ -2452,7 +2575,10 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
         snprintf(base->label, len, "%s-base", qemu_opts_id(opts));
         chr = qemu_chr_open_mux(base);
         chr->filename = base->filename;
+        chr->avail_connections = MAX_MUX;
         QTAILQ_INSERT_TAIL(&chardevs, chr, next);
+    } else {
+        chr->avail_connections = 1;
     }
     chr->label = qemu_strdup(qemu_opts_id(opts));
     return chr;
@@ -2476,9 +2602,31 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i
     if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
         monitor_init(chr, MONITOR_USE_READLINE);
     }
+    qemu_opts_del(opts);
     return chr;
 }
 
+void qemu_chr_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)
+{
+    if (chr->chr_guest_open) {
+        chr->chr_guest_open(chr);
+    }
+}
+
+void qemu_chr_guest_close(struct CharDriverState *chr)
+{
+    if (chr->chr_guest_close) {
+        chr->chr_guest_close(chr);
+    }
+}
+
 void qemu_chr_close(CharDriverState *chr)
 {
     QTAILQ_REMOVE(&chardevs, chr, next);
@@ -2504,22 +2652,6 @@ void qemu_chr_info_print(Monitor *mon, const QObject *ret_data)
     qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon);
 }
 
-/**
- * qemu_chr_info(): Character devices information
- *
- * Each device is represented by a QDict. The returned QObject is a QList
- * of all devices.
- *
- * The QDict contains the following:
- *
- * - "label": device's label
- * - "filename": device's file
- *
- * Example:
- *
- * [ { "label": "monitor", "filename", "stdio" },
- *   { "label": "serial0", "filename": "vc" } ]
- */
 void qemu_chr_info(Monitor *mon, QObject **ret_data)
 {
     QList *chr_list;