X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/9196dd411d580c27f85daa209ff9a501d719ebc0..dc2c4eca89ec5ee7b7a4c2563c991a14a7c5ee84:/qemu-char.c diff --git a/qemu-char.c b/qemu-char.c index dd410ce40f..392de29a91 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -26,7 +26,7 @@ #include "ui/console.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" -#include "char/char.h" +#include "sysemu/char.h" #include "hw/usb.h" #include "qmp-commands.h" @@ -53,13 +53,6 @@ #include #ifdef CONFIG_BSD #include -#if defined(__GLIBC__) -#include -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#include -#else -#include -#endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include @@ -69,8 +62,6 @@ #endif #else #ifdef __linux__ -#include - #include #include #endif @@ -85,9 +76,6 @@ #include // must come after ip.h #include #include -#include -#include -#include #endif #endif #endif @@ -120,19 +108,9 @@ void qemu_chr_be_event(CharDriverState *s, int event) s->chr_event(s->handler_opaque, event); } -static gboolean qemu_chr_be_generic_open_bh(gpointer opaque) -{ - CharDriverState *s = opaque; - qemu_chr_be_event(s, CHR_EVENT_OPENED); - s->idle_tag = 0; - return FALSE; -} - void qemu_chr_be_generic_open(CharDriverState *s) { - if (s->idle_tag == 0) { - s->idle_tag = g_idle_add(qemu_chr_be_generic_open_bh, s); - } + qemu_chr_be_event(s, CHR_EVENT_OPENED); } int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len) @@ -257,6 +235,7 @@ static CharDriverState *qemu_chr_open_null(void) chr = g_malloc0(sizeof(CharDriverState)); chr->chr_write = null_chr_write; + chr->explicit_be_open = true; return chr; } @@ -514,9 +493,6 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) /* Frontend guest-open / -close notification is not support with muxes */ chr->chr_set_fe_open = NULL; - /* Muxes are always open on creation */ - qemu_chr_be_generic_open(chr); - return chr; } @@ -596,9 +572,11 @@ typedef struct IOWatchPoll { GSource parent; + GIOChannel *channel; GSource *src; IOCanReadHandler *fd_can_read; + GSourceFunc fd_read; void *opaque; } IOWatchPoll; @@ -611,15 +589,19 @@ static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_) { IOWatchPoll *iwp = io_watch_poll_from_source(source); bool now_active = iwp->fd_can_read(iwp->opaque) > 0; - bool was_active = g_source_get_context(iwp->src) != NULL; + bool was_active = iwp->src != NULL; if (was_active == now_active) { return FALSE; } if (now_active) { + iwp->src = g_io_create_watch(iwp->channel, G_IO_IN | G_IO_ERR | G_IO_HUP); + g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL); g_source_attach(iwp->src, NULL); } else { - g_source_remove(g_source_get_id(iwp->src)); + g_source_destroy(iwp->src); + g_source_unref(iwp->src); + iwp->src = NULL; } return FALSE; } @@ -637,8 +619,18 @@ static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback, static void io_watch_poll_finalize(GSource *source) { + /* Due to a glib bug, removing the last reference to a source + * inside a finalize callback causes recursive locking (and a + * deadlock). This is not a problem inside other callbacks, + * including dispatch callbacks, so we call io_remove_watch_poll + * to remove this source. At this point, iwp->src must + * be NULL, or we would leak it. + * + * This would be solved much more elegantly by child sources, + * but we support older glib versions that do not have them. + */ IOWatchPoll *iwp = io_watch_poll_from_source(source); - g_source_unref(iwp->src); + assert(iwp->src == NULL); } static GSourceFuncs io_watch_poll_funcs = { @@ -655,14 +647,37 @@ static guint io_add_watch_poll(GIOChannel *channel, gpointer user_data) { IOWatchPoll *iwp; + int tag; iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll)); iwp->fd_can_read = fd_can_read; iwp->opaque = user_data; - iwp->src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP); - g_source_set_callback(iwp->src, (GSourceFunc)fd_read, user_data, NULL); + iwp->channel = channel; + iwp->fd_read = (GSourceFunc) fd_read; + iwp->src = NULL; + + tag = g_source_attach(&iwp->parent, NULL); + g_source_unref(&iwp->parent); + return tag; +} + +static void io_remove_watch_poll(guint tag) +{ + GSource *source; + IOWatchPoll *iwp; + + g_return_if_fail (tag > 0); - return g_source_attach(&iwp->parent, NULL); + source = g_main_context_find_source_by_id(NULL, tag); + g_return_if_fail (source != NULL); + + iwp = io_watch_poll_from_source(source); + if (iwp->src) { + g_source_destroy(iwp->src); + g_source_unref(iwp->src); + iwp->src = NULL; + } + g_source_destroy(&iwp->parent); } #ifndef _WIN32 @@ -767,12 +782,16 @@ static gboolean fd_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) len = s->max_size; } if (len == 0) { - return FALSE; + return TRUE; } status = g_io_channel_read_chars(chan, (gchar *)buf, len, &bytes_read, NULL); if (status == G_IO_STATUS_EOF) { + if (s->fd_in_tag) { + io_remove_watch_poll(s->fd_in_tag); + s->fd_in_tag = 0; + } qemu_chr_be_event(chr, CHR_EVENT_CLOSED); return FALSE; } @@ -803,7 +822,8 @@ static void fd_chr_update_read_handler(CharDriverState *chr) FDCharDriver *s = chr->opaque; if (s->fd_in_tag) { - g_source_remove(s->fd_in_tag); + io_remove_watch_poll(s->fd_in_tag); + s->fd_in_tag = 0; } if (s->fd_in) { @@ -816,7 +836,7 @@ static void fd_chr_close(struct CharDriverState *chr) FDCharDriver *s = chr->opaque; if (s->fd_in_tag) { - g_source_remove(s->fd_in_tag); + io_remove_watch_poll(s->fd_in_tag); s->fd_in_tag = 0; } @@ -849,8 +869,6 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) chr->chr_update_read_handler = fd_chr_update_read_handler; chr->chr_close = fd_chr_close; - qemu_chr_be_generic_open(chr); - return chr; } @@ -946,63 +964,6 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) return chr; } -#ifdef __sun__ -/* Once Solaris has openpty(), this is going to be removed. */ -static int openpty(int *amaster, int *aslave, char *name, - struct termios *termp, struct winsize *winp) -{ - const char *slave; - int mfd = -1, sfd = -1; - - *amaster = *aslave = -1; - - mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); - if (mfd < 0) - goto err; - - if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) - goto err; - - if ((slave = ptsname(mfd)) == NULL) - goto err; - - if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) - goto err; - - if (ioctl(sfd, I_PUSH, "ptem") == -1 || - (termp != NULL && tcgetattr(sfd, termp) < 0)) - goto err; - - if (amaster) - *amaster = mfd; - if (aslave) - *aslave = sfd; - if (winp) - ioctl(sfd, TIOCSWINSZ, winp); - - return 0; - -err: - if (sfd != -1) - close(sfd); - close(mfd); - return -1; -} - -static void cfmakeraw (struct termios *termios_p) -{ - termios_p->c_iflag &= - ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); - termios_p->c_oflag &= ~OPOST; - termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - termios_p->c_cflag &= ~(CSIZE|PARENB); - termios_p->c_cflag |= CS8; - - termios_p->c_cc[VMIN] = 0; - termios_p->c_cc[VTIME] = 0; -} -#endif - #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ || defined(__GLIBC__) @@ -1013,7 +974,6 @@ typedef struct { GIOChannel *fd; guint fd_tag; int connected; - int polling; int read_bytes; guint timer_tag; } PtyCharDriver; @@ -1029,17 +989,12 @@ static gboolean pty_chr_timer(gpointer opaque) if (s->connected) { goto out; } - if (s->polling) { - /* If we arrive here without polling being cleared due - * read returning -EIO, then we are (re-)connected */ - pty_chr_state(chr, 1); - goto out; - } /* Next poll ... */ pty_chr_update_read_handler(chr); out: + s->timer_tag = 0; return FALSE; } @@ -1097,8 +1052,9 @@ static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) len = sizeof(buf); if (len > s->read_bytes) len = s->read_bytes; - if (len == 0) - return FALSE; + if (len == 0) { + return TRUE; + } status = g_io_channel_read_chars(s->fd, (gchar *)buf, len, &size, NULL); if (status != G_IO_STATUS_NORMAL) { pty_chr_state(chr, 0); @@ -1113,22 +1069,17 @@ static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) static void pty_chr_update_read_handler(CharDriverState *chr) { PtyCharDriver *s = chr->opaque; + GPollFD pfd; - if (s->fd_tag) { - g_source_remove(s->fd_tag); - } - - s->fd_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr); - s->polling = 1; - /* - * Short timeout here: just need wait long enougth that qemu makes - * it through the poll loop once. When reconnected we want a - * short timeout so we notice it almost instantly. Otherwise - * read() gives us -EIO instantly, making pty_chr_state() reset the - * timeout to the normal (much longer) poll interval before the - * timer triggers. - */ - pty_chr_rearm_timer(chr, 10); + pfd.fd = g_io_channel_unix_get_fd(s->fd); + pfd.events = G_IO_OUT; + pfd.revents = 0; + g_poll(&pfd, 1, 0); + if (pfd.revents & G_IO_HUP) { + pty_chr_state(chr, 0); + } else { + pty_chr_state(chr, 1); + } } static void pty_chr_state(CharDriverState *chr, int connected) @@ -1136,18 +1087,25 @@ static void pty_chr_state(CharDriverState *chr, int connected) PtyCharDriver *s = chr->opaque; if (!connected) { - g_source_remove(s->fd_tag); - s->fd_tag = 0; + if (s->fd_tag) { + io_remove_watch_poll(s->fd_tag); + s->fd_tag = 0; + } s->connected = 0; - s->polling = 0; /* (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. */ pty_chr_rearm_timer(chr, 1000); } else { - if (!s->connected) + if (s->timer_tag) { + g_source_remove(s->timer_tag); + s->timer_tag = 0; + } + if (!s->connected) { qemu_chr_be_generic_open(chr); - s->connected = 1; + s->connected = 1; + s->fd_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr); + } } } @@ -1158,13 +1116,15 @@ static void pty_chr_close(struct CharDriverState *chr) int fd; if (s->fd_tag) { - g_source_remove(s->fd_tag); + io_remove_watch_poll(s->fd_tag); + s->fd_tag = 0; } fd = g_io_channel_unix_get_fd(s->fd); g_io_channel_unref(s->fd); close(fd); if (s->timer_tag) { g_source_remove(s->timer_tag); + s->timer_tag = 0; } g_free(s); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); @@ -1175,34 +1135,24 @@ static CharDriverState *qemu_chr_open_pty(const char *id, { CharDriverState *chr; PtyCharDriver *s; - struct termios tty; int master_fd, slave_fd; -#if defined(__OpenBSD__) || defined(__DragonFly__) char pty_name[PATH_MAX]; -#define q_ptsname(x) pty_name -#else - char *pty_name = NULL; -#define q_ptsname(x) ptsname(x) -#endif - if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) { + master_fd = qemu_openpty_raw(&slave_fd, pty_name); + if (master_fd < 0) { return NULL; } - /* Set raw attributes on the pty. */ - tcgetattr(slave_fd, &tty); - cfmakeraw(&tty); - tcsetattr(slave_fd, TCSAFLUSH, &tty); close(slave_fd); chr = g_malloc0(sizeof(CharDriverState)); - chr->filename = g_strdup_printf("pty:%s", q_ptsname(master_fd)); - ret->pty = g_strdup(q_ptsname(master_fd)); + chr->filename = g_strdup_printf("pty:%s", pty_name); + ret->pty = g_strdup(pty_name); ret->has_pty = true; fprintf(stderr, "char device redirected to %s (label %s)\n", - q_ptsname(master_fd), id); + pty_name, id); s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; @@ -1210,6 +1160,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id, chr->chr_update_read_handler = pty_chr_update_read_handler; chr->chr_close = pty_chr_close; chr->chr_add_watch = pty_chr_add_watch; + chr->explicit_be_open = true; s->fd = io_channel_from_fd(master_fd); s->timer_tag = 0; @@ -1562,8 +1513,6 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) chr->chr_close = pp_close; chr->opaque = drv; - qemu_chr_be_generic_open(chr); - return chr; } #endif /* __linux__ */ @@ -1617,6 +1566,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) chr->opaque = (void *)(intptr_t)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; + chr->explicit_be_open = true; return chr; } #endif @@ -1847,7 +1797,6 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename) g_free(chr); return NULL; } - qemu_chr_be_generic_open(chr); return chr; } @@ -1947,7 +1896,6 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) g_free(chr); return NULL; } - qemu_chr_be_generic_open(chr); return chr; } @@ -1961,7 +1909,6 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; - qemu_chr_be_generic_open(chr); return chr; } @@ -2226,13 +2173,18 @@ static gboolean udp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) gsize bytes_read = 0; GIOStatus status; - if (s->max_size == 0) - return FALSE; + if (s->max_size == 0) { + return TRUE; + } status = g_io_channel_read_chars(s->chan, (gchar *)s->buf, sizeof(s->buf), &bytes_read, NULL); s->bufcnt = bytes_read; s->bufptr = s->bufcnt; if (status != G_IO_STATUS_NORMAL) { + if (s->tag) { + io_remove_watch_poll(s->tag); + s->tag = 0; + } return FALSE; } @@ -2251,7 +2203,7 @@ static void udp_chr_update_read_handler(CharDriverState *chr) NetCharDriver *s = chr->opaque; if (s->tag) { - g_source_remove(s->tag); + io_remove_watch_poll(s->tag); s->tag = 0; } @@ -2264,7 +2216,8 @@ static void udp_chr_close(CharDriverState *chr) { NetCharDriver *s = chr->opaque; if (s->tag) { - g_source_remove(s->tag); + io_remove_watch_poll(s->tag); + s->tag = 0; } if (s->chan) { g_io_channel_unref(s->chan); @@ -2290,6 +2243,8 @@ static CharDriverState *qemu_chr_open_udp_fd(int fd) chr->chr_write = udp_chr_write; chr->chr_update_read_handler = udp_chr_update_read_handler; chr->chr_close = udp_chr_close; + /* be isn't opened until we get a connection */ + chr->explicit_be_open = true; return chr; } @@ -2484,7 +2439,7 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) int len, size; if (!s->connected || s->max_size <= 0) { - return FALSE; + return TRUE; } len = sizeof(buf); if (len > s->max_size) @@ -2496,8 +2451,10 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) if (s->listen_chan) { s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr); } - g_source_remove(s->tag); - s->tag = 0; + if (s->tag) { + io_remove_watch_poll(s->tag); + s->tag = 0; + } g_io_channel_unref(s->chan); s->chan = NULL; closesocket(s->fd); @@ -2558,8 +2515,10 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd) socket_set_nodelay(fd); s->fd = fd; s->chan = io_channel_from_socket(fd); - g_source_remove(s->listen_tag); - s->listen_tag = 0; + if (s->listen_tag) { + g_source_remove(s->listen_tag); + s->listen_tag = 0; + } tcp_chr_connect(chr); return 0; @@ -2590,6 +2549,7 @@ static gboolean tcp_chr_accept(GIOChannel *channel, GIOCondition cond, void *opa } fd = qemu_accept(s->listen_fd, addr, &len); if (fd < 0 && errno != EINTR) { + s->listen_tag = 0; return FALSE; } else if (fd >= 0) { if (s->do_telnetopt) @@ -2608,7 +2568,8 @@ static void tcp_chr_close(CharDriverState *chr) TCPCharDriver *s = chr->opaque; if (s->fd >= 0) { if (s->tag) { - g_source_remove(s->tag); + io_remove_watch_poll(s->tag); + s->tag = 0; } if (s->chan) { g_io_channel_unref(s->chan); @@ -2618,6 +2579,7 @@ static void tcp_chr_close(CharDriverState *chr) if (s->listen_fd >= 0) { if (s->listen_tag) { g_source_remove(s->listen_tag); + s->listen_tag = 0; } if (s->listen_chan) { g_io_channel_unref(s->listen_chan); @@ -2642,7 +2604,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, memset(&ss, 0, ss_len); if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) != 0) { - error_setg(errp, "getsockname: %s", strerror(errno)); + error_setg_errno(errp, errno, "getsockname"); return NULL; } @@ -2685,6 +2647,8 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, chr->get_msgfd = tcp_get_msgfd; chr->chr_add_client = tcp_chr_add_client; chr->chr_add_watch = tcp_chr_add_watch; + /* be isn't opened until we get a connection */ + chr->explicit_be_open = true; if (is_listen) { s->listen_fd = fd; @@ -2702,8 +2666,8 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, } if (is_listen && is_waitconnect) { - printf("QEMU waiting for connection on: %s\n", - chr->filename); + fprintf(stderr, "QEMU waiting for connection on: %s\n", + chr->filename); tcp_chr_accept(s->listen_chan, G_IO_IN, chr); qemu_set_nonblock(s->listen_fd); } @@ -2715,19 +2679,12 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) CharDriverState *chr = NULL; Error *local_err = NULL; int fd = -1; - int is_listen; - int is_waitconnect; - int do_nodelay; - int is_unix; - int is_telnet; - is_listen = qemu_opt_get_bool(opts, "server", 0); - is_waitconnect = qemu_opt_get_bool(opts, "wait", 1); - is_telnet = qemu_opt_get_bool(opts, "telnet", 0); - do_nodelay = !qemu_opt_get_bool(opts, "delay", 1); - is_unix = qemu_opt_get(opts, "path") != NULL; - if (!is_listen) - is_waitconnect = 0; + bool is_listen = qemu_opt_get_bool(opts, "server", false); + bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true); + bool is_telnet = qemu_opt_get_bool(opts, "telnet", false); + bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true); + bool is_unix = qemu_opt_get(opts, "path") != NULL; if (is_unix) { if (is_listen) { @@ -2829,8 +2786,8 @@ static void ringbuf_chr_close(struct CharDriverState *chr) chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, - Error **errp) +static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts, + Error **errp) { CharDriverState *chr; RingBufCharDriver *d; @@ -2842,7 +2799,7 @@ static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, /* The size must be power of 2 */ if (d->size & (d->size - 1)) { - error_setg(errp, "size of ringbuf chardev must be power of two"); + error_setg(errp, "size of memory chardev must be power of two"); goto fail; } @@ -2874,7 +2831,7 @@ void qmp_ringbuf_write(const char *device, const char *data, CharDriverState *chr; const uint8_t *write_data; int ret; - size_t write_count; + gsize write_count; chr = qemu_chr_find(device); if (!chr) { @@ -3144,12 +3101,12 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, backend->pipe->device = g_strdup(device); } -static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, - Error **errp) +static void qemu_chr_parse_memory(QemuOpts *opts, ChardevBackend *backend, + Error **errp) { int val; - backend->memory = g_new0(ChardevRingbuf, 1); + backend->memory = g_new0(ChardevMemory, 1); val = qemu_opt_get_number(opts, "size", 0); if (val != 0) { @@ -3163,7 +3120,7 @@ typedef struct CharDriver { /* old, pre qapi */ CharDriverState *(*open)(QemuOpts *opts); /* new, qapi-based */ - int kind; + ChardevBackendKind kind; void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp); } CharDriver; @@ -3180,7 +3137,7 @@ void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *) backends = g_slist_append(backends, s); } -void register_char_driver_qapi(const char *name, int kind, +void register_char_driver_qapi(const char *name, ChardevBackendKind kind, void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp)) { CharDriver *s; @@ -3221,7 +3178,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, if (i == NULL) { error_setg(errp, "chardev: backend \"%s\" not found", qemu_opt_get(opts, "backend")); - return NULL; + goto err; } if (!cd->open) { @@ -3229,7 +3186,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, ChardevBackend *backend = g_new0(ChardevBackend, 1); ChardevReturn *ret = NULL; const char *id = qemu_opts_id(opts); - const char *bid = NULL; + char *bid = NULL; if (qemu_opt_get_bool(opts, "mux", 0)) { bid = g_strdup_printf("%s-base", id); @@ -3256,9 +3213,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, backend->kind = CHARDEV_BACKEND_KIND_MUX; backend->mux->chardev = g_strdup(bid); ret = qmp_chardev_add(id, backend, errp); - if (error_is_set(errp)) { - goto qapi_out; - } + assert(!error_is_set(errp)); } chr = qemu_chr_find(id); @@ -3266,6 +3221,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, qapi_out: qapi_free_ChardevBackend(backend); qapi_free_ChardevReturn(ret); + g_free(bid); return chr; } @@ -3279,6 +3235,12 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, if (!chr->filename) chr->filename = g_strdup(qemu_opt_get(opts, "backend")); chr->init = init; + /* if we didn't create the chardev via qmp_chardev_add, we + * need to send the OPENED event here + */ + if (!chr->explicit_be_open) { + qemu_chr_be_event(chr, CHR_EVENT_OPENED); + } QTAILQ_INSERT_TAIL(&chardevs, chr, next); if (qemu_opt_get_bool(opts, "mux", 0)) { @@ -3530,7 +3492,7 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) { HANDLE out; - if (file->in) { + if (file->has_in) { error_setg(errp, "input file not supported"); return NULL; } @@ -3566,7 +3528,7 @@ static int qmp_chardev_open_file_source(char *src, int flags, TFR(fd = qemu_open(src, flags, 0666)); if (fd == -1) { - error_setg(errp, "open %s: %s", src, strerror(errno)); + error_setg_file_open(errp, errno, src); } return fd; } @@ -3581,7 +3543,7 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return NULL; } - if (file->in) { + if (file->has_in) { flags = O_RDONLY; in = qmp_chardev_open_file_source(file->in, flags, errp); if (error_is_set(errp)) { @@ -3652,12 +3614,12 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, is_telnet, is_waitconnect, errp); } -static CharDriverState *qmp_chardev_open_dgram(ChardevDgram *dgram, - Error **errp) +static CharDriverState *qmp_chardev_open_udp(ChardevUdp *udp, + Error **errp) { int fd; - fd = socket_dgram(dgram->remote, dgram->local, errp); + fd = socket_dgram(udp->remote, udp->local, errp); if (error_is_set(errp)) { return NULL; } @@ -3693,8 +3655,8 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_SOCKET: chr = qmp_chardev_open_socket(backend->socket, errp); break; - case CHARDEV_BACKEND_KIND_DGRAM: - chr = qmp_chardev_open_dgram(backend->dgram, errp); + case CHARDEV_BACKEND_KIND_UDP: + chr = qmp_chardev_open_udp(backend->udp, errp); break; #ifdef HAVE_CHARDEV_TTY case CHARDEV_BACKEND_KIND_PTY: @@ -3741,7 +3703,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, chr = vc_init(backend->vc); break; case CHARDEV_BACKEND_KIND_MEMORY: - chr = qemu_chr_open_ringbuf(backend->memory, errp); + chr = qemu_chr_open_memory(backend->memory, errp); break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); @@ -3755,6 +3717,12 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, chr->label = g_strdup(id); chr->avail_connections = (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1; + if (!chr->filename) { + chr->filename = g_strdup(ChardevBackendKind_lookup[backend->kind]); + } + if (!chr->explicit_be_open) { + qemu_chr_be_event(chr, CHR_EVENT_OPENED); + } QTAILQ_INSERT_TAIL(&chardevs, chr, next); return ret; } else { @@ -3786,7 +3754,7 @@ static void register_types(void) register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY, - qemu_chr_parse_ringbuf); + qemu_chr_parse_memory); register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE, qemu_chr_parse_file_out); register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO,