diff mbox

[6/7] qemu-char: Clean up error handling in qmp_chardev_add

Message ID 1393979937-9082-7-git-send-email-minyard@acm.org
State New
Headers show

Commit Message

Corey Minyard March 5, 2014, 12:38 a.m. UTC
From: Corey Minyard <cminyard@mvista.com>

The open functions called by qmp_chardev_add could either return NULL
or set errp to return an error.  Modify to just return errp, as that can
pass useful information where returning NULL cannot.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
 backends/baum.c         |   6 +-
 backends/msmouse.c      |   4 +-
 hw/misc/ivshmem.c       |  11 +-
 include/sysemu/char.h   |  10 +-
 include/ui/console.h    |   4 +-
 include/ui/qemu-spice.h |  15 ++-
 qemu-char.c             | 336 ++++++++++++++++++++++--------------------------
 spice-qemu-char.c       |  15 ++-
 ui/console.c            |  10 +-
 ui/gtk.c                |   4 +-
 10 files changed, 190 insertions(+), 225 deletions(-)
diff mbox

Patch

diff --git a/backends/baum.c b/backends/baum.c
index 9910a74..56cd00f 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -561,7 +561,7 @@  static void baum_close(struct CharDriverState *chr)
     g_free(baum);
 }
 
-CharDriverState *chr_baum_init(CharDriverState *chr)
+void chr_baum_init(CharDriverState *chr, Error **errp)
 {
     BaumDriverState *baum;
     brlapi_handle_t *handle;
@@ -610,15 +610,15 @@  CharDriverState *chr_baum_init(CharDriverState *chr)
 
     qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
 
-    return chr;
+    return;
 
 fail:
     timer_free(baum->cellCount_timer);
     brlapi__closeConnection(handle);
 fail_handle:
+    error_setg(errp, "Failed to initialize baum");
     g_free(handle);
     g_free(baum);
-    return NULL;
 }
 
 static void register_types(void)
diff --git a/backends/msmouse.c b/backends/msmouse.c
index b4e7a23..78998f9 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -63,15 +63,13 @@  static void msmouse_chr_close (struct CharDriverState *chr)
     g_free (chr);
 }
 
-CharDriverState *qemu_chr_open_msmouse(CharDriverState *chr)
+void qemu_chr_open_msmouse(CharDriverState *chr, Error **errp)
 {
     chr->chr_write = msmouse_chr_write;
     chr->chr_close = msmouse_chr_close;
     chr->explicit_be_open = true;
 
     qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse");
-
-    return chr;
 }
 
 static void register_types(void)
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 75e83c3..5813f79 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -291,20 +291,15 @@  static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
 {
     /* create a event character device based on the passed eventfd */
     IVShmemState *s = opaque;
-    CharDriverState *chr, *newchr;
+    CharDriverState *chr;
     int eventfd = event_notifier_get_fd(n);
 
-    newchr = g_malloc0(sizeof(*chr));
-    if (newchr == NULL) {
-        fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
-        exit(-1);
-    }
-    chr = qemu_chr_open_eventfd(newchr, eventfd);
+    chr = g_malloc0(sizeof(*chr));
     if (chr == NULL) {
-        g_free(newchr);
         fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
         exit(-1);
     }
+    qemu_chr_open_eventfd(chr, eventfd);
     qemu_chr_fe_claim_no_fail(chr);
 
     /* if MSI is supported we need multiple interrupts */
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 1800c54..8604041 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -306,22 +306,22 @@  CharDriverState *qemu_chr_find(const char *name);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
 void register_char_driver(const char *name,
-        CharDriverState *(*open)(CharDriverState *, QemuOpts *),
-        int (*recon_setup)(CharDriverState *));
+                          void (*open)(CharDriverState *, QemuOpts *, Error **),
+                          int (*recon_setup)(CharDriverState *));
 void register_char_driver_qapi(const char *name, ChardevBackendKind kind,
         void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp));
 
 /* add an eventfd to the qemu devices that are polled */
-CharDriverState *qemu_chr_open_eventfd(CharDriverState *chr, int eventfd);
+void qemu_chr_open_eventfd(CharDriverState *chr, int eventfd);
 
 extern int term_escape_char;
 
 CharDriverState *qemu_char_get_next_serial(void);
 
 /* msmouse */
-CharDriverState *qemu_chr_open_msmouse(CharDriverState *chr);
+void qemu_chr_open_msmouse(CharDriverState *chr, Error **errp);
 
 /* baum.c */
-CharDriverState *chr_baum_init(CharDriverState *chr);
+void chr_baum_init(CharDriverState *chr, Error **errp);
 
 #endif
diff --git a/include/ui/console.h b/include/ui/console.h
index 572a1ff..18776d6 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -299,9 +299,9 @@  void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
 DisplaySurface *qemu_console_surface(QemuConsole *con);
 DisplayState *qemu_console_displaystate(QemuConsole *console);
 
-typedef CharDriverState *(VcHandler)(CharDriverState *chr, ChardevVC *vc);
+typedef void (VcHandler)(CharDriverState *chr, ChardevVC *vc, Error **errp);
 
-CharDriverState *vc_init(CharDriverState *chr, ChardevVC *vc);
+void vc_init(CharDriverState *chr, ChardevVC *vc, Error **errp);
 void register_vc_handler(VcHandler *handler);
 
 /* sdl.c */
diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
index 15220a1..85b1be3 100644
--- a/include/ui/qemu-spice.h
+++ b/include/ui/qemu-spice.h
@@ -48,16 +48,17 @@  int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
 void do_info_spice_print(Monitor *mon, const QObject *data);
 void do_info_spice(Monitor *mon, QObject **ret_data);
 
-CharDriverState *qemu_chr_open_spice_vmc(CharDriverState *chr,
-                                         const char *type);
+void qemu_chr_open_spice_vmc(CharDriverState *chr, const char *type,
+                             Error **errp);
 #if SPICE_SERVER_VERSION >= 0x000c02
-CharDriverState *qemu_chr_open_spice_port(CharDriverState *chr,
-                                          const char *name);
+void qemu_chr_open_spice_port(CharDriverState *chr, const char *name,
+                              Error **errp);
 void qemu_spice_register_ports(void);
 #else
-static inline CharDriverState *qemu_chr_open_spice_port(CharDriverState *chr,
-                                                        const char *name)
-{ return NULL; }
+static inline void qemu_chr_open_spice_port(CharDriverState *chr,
+                                            const char *name,
+                                            Error **errp)
+{ error_setg(errp, "open spice port not supported"); }
 #endif
 
 #else  /* CONFIG_SPICE */
diff --git a/qemu-char.c b/qemu-char.c
index 427bb34..ae63836 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -560,8 +560,7 @@  static Notifier muxes_realize_notify = {
     .notify = muxes_realize_done,
 };
 
-static CharDriverState *qemu_chr_open_mux(CharDriverState *chr,
-                                          CharDriverState *drv)
+static void qemu_chr_open_mux(CharDriverState *chr, CharDriverState *drv)
 {
     MuxDriver *d;
 
@@ -580,8 +579,6 @@  static CharDriverState *qemu_chr_open_mux(CharDriverState *chr,
      */
     chr->explicit_be_open = muxes_realized ? 0 : 1;
     chr->is_mux = 1;
-
-    return chr;
 }
 
 
@@ -950,9 +947,8 @@  static void fd_chr_close(struct CharDriverState *chr)
 }
 
 /* open a character device to a unix fd */
-static CharDriverState *qemu_chr_open_fd(CharDriverState *chr,
-                                         int fd_in, int fd_out,
-                                         int close_fds_on_close)
+static void qemu_chr_open_fd(CharDriverState *chr, int fd_in, int fd_out,
+                             int close_fds_on_close)
 {
     FDCharDriver *s;
 
@@ -972,20 +968,18 @@  static CharDriverState *qemu_chr_open_fd(CharDriverState *chr,
     chr->chr_write = fd_chr_write;
     chr->chr_update_read_handler = fd_chr_update_read_handler;
     chr->chr_close = fd_chr_close;
-
-    return chr;
 }
 
-static CharDriverState *qemu_chr_open_pipe(CharDriverState *chr,
-                                           ChardevHostdev *opts)
+static void qemu_chr_open_pipe(CharDriverState *chr, ChardevHostdev *opts,
+                               Error **errp)
 {
     int fd_in, fd_out;
     char filename_in[256], filename_out[256];
     const char *filename = opts->device;
 
     if (filename == NULL) {
-        fprintf(stderr, "chardev: pipe: no filename given\n");
-        return NULL;
+        error_setg(errp, "chardev: pipe: no filename given");
+        return;
     }
 
     snprintf(filename_in, 256, "%s.in", filename);
@@ -999,10 +993,11 @@  static CharDriverState *qemu_chr_open_pipe(CharDriverState *chr,
 	    close(fd_out);
         TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
         if (fd_in < 0) {
-            return NULL;
+            error_setg_file_open(errp, errno, filename);
+            return;
         }
     }
-    return qemu_chr_open_fd(chr, fd_in, fd_out, TRUE);
+    qemu_chr_open_fd(chr, fd_in, fd_out, TRUE);
 }
 
 /* init terminal so that we can grab keys */
@@ -1043,12 +1038,12 @@  static void qemu_chr_close_stdio(struct CharDriverState *chr)
     fd_chr_close(chr);
 }
 
-static CharDriverState *qemu_chr_open_stdio(CharDriverState *chr,
-                                            ChardevStdio *opts)
+static void qemu_chr_open_stdio(CharDriverState *chr, ChardevStdio *opts,
+                                Error **errp)
 {
     if (is_daemonized()) {
-        error_report("cannot use stdio with -daemonize");
-        return NULL;
+        error_setg(errp, "cannot use stdio with -daemonize");
+        return;
     }
     old_fd0_flags = fcntl(0, F_GETFL);
     tcgetattr (0, &oldtty);
@@ -1062,8 +1057,6 @@  static CharDriverState *qemu_chr_open_stdio(CharDriverState *chr,
         stdio_allow_signal = opts->signal;
     }
     qemu_chr_fe_set_echo(chr, false);
-
-    return chr;
 }
 
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
@@ -1222,9 +1215,8 @@  static void pty_chr_close(struct CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pty(CharDriverState *chr,
-                                          const char *id,
-                                          ChardevReturn *ret)
+static void qemu_chr_open_pty(CharDriverState *chr, const char *id,
+                              ChardevReturn *ret, Error **errp)
 {
     PtyCharDriver *s;
     int master_fd, slave_fd;
@@ -1232,7 +1224,8 @@  static CharDriverState *qemu_chr_open_pty(CharDriverState *chr,
 
     master_fd = qemu_openpty_raw(&slave_fd, pty_name);
     if (master_fd < 0) {
-        return NULL;
+        error_setg_errno(errp, errno, "getsockname");
+        return;
     }
 
     close(slave_fd);
@@ -1254,8 +1247,6 @@  static CharDriverState *qemu_chr_open_pty(CharDriverState *chr,
 
     s->fd = io_channel_from_fd(master_fd);
     s->timer_tag = 0;
-
-    return chr;
 }
 
 static void tty_serial_init(int fd, int speed,
@@ -1581,13 +1572,14 @@  static void pp_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pp_fd(CharDriverState *chr, int fd)
+static void qemu_chr_open_pp_fd(CharDriverState *chr, int fd, Error **errp)
 {
     ParallelCharDriver *drv;
 
     if (ioctl(fd, PPCLAIM) < 0) {
+        error_setg_errno(errp, errno, "ioctl");
         close(fd);
-        return NULL;
+        return;
     }
 
     drv = g_malloc0(sizeof(ParallelCharDriver));
@@ -1598,8 +1590,6 @@  static CharDriverState *qemu_chr_open_pp_fd(CharDriverState *chr, int fd)
     chr->chr_ioctl = pp_ioctl;
     chr->chr_close = pp_close;
     chr->opaque = drv;
-
-    return chr;
 }
 #endif /* __linux__ */
 
@@ -1644,13 +1634,12 @@  static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_pp_fd(CharDriverState *chr, int fd)
+static void qemu_chr_open_pp_fd(CharDriverState *chr, int fd, Error **errp)
 {
     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
 
@@ -1704,7 +1693,8 @@  static void win_chr_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static int win_chr_init(CharDriverState *chr, const char *filename)
+static int win_chr_init(CharDriverState *chr, const char *filename,
+                        Error **errp)
 {
     WinCharState *s = chr->opaque;
     COMMCONFIG comcfg;
@@ -1715,25 +1705,25 @@  static int win_chr_init(CharDriverState *chr, const char *filename)
 
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!s->hsend) {
-        fprintf(stderr, "Failed CreateEvent\n");
+        error_setg(errp, "Failed CreateEvent");
         goto fail;
     }
     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!s->hrecv) {
-        fprintf(stderr, "Failed CreateEvent\n");
+        error_setg(errp, "Failed CreateEvent");
         goto fail;
     }
 
     s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
                       OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
     if (s->hcom == INVALID_HANDLE_VALUE) {
-        fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
+        error_setg(errp, "Failed CreateFile (%lu)", GetLastError());
         s->hcom = NULL;
         goto fail;
     }
 
     if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
-        fprintf(stderr, "Failed SetupComm\n");
+        error_setg(errp, "Failed SetupComm");
         goto fail;
     }
 
@@ -1744,23 +1734,23 @@  static int win_chr_init(CharDriverState *chr, const char *filename)
     CommConfigDialog(filename, NULL, &comcfg);
 
     if (!SetCommState(s->hcom, &comcfg.dcb)) {
-        fprintf(stderr, "Failed SetCommState\n");
+        error_setg(errp, "Failed SetCommState");
         goto fail;
     }
 
     if (!SetCommMask(s->hcom, EV_ERR)) {
-        fprintf(stderr, "Failed SetCommMask\n");
+        error_setg(errp, "Failed SetCommMask");
         goto fail;
     }
 
     cto.ReadIntervalTimeout = MAXDWORD;
     if (!SetCommTimeouts(s->hcom, &cto)) {
-        fprintf(stderr, "Failed SetCommTimeouts\n");
+        error_setg(errp, "Failed SetCommTimeouts");
         goto fail;
     }
 
     if (!ClearCommError(s->hcom, &err, &comstat)) {
-        fprintf(stderr, "Failed ClearCommError\n");
+        error_setg(errp, "Failed ClearCommError");
         goto fail;
     }
     qemu_add_polling_cb(win_chr_poll, chr);
@@ -1864,8 +1854,8 @@  static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_win_path(CharDriverState *chr,
-                                               const char *filename)
+static void qemu_chr_open_win_path(CharDriverState *chr, const char *filename,
+                                   Error **errp)
 {
     WinCharState *s;
 
@@ -1874,11 +1864,10 @@  static CharDriverState *qemu_chr_open_win_path(CharDriverState *chr,
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
 
-    if (win_chr_init(chr, filename) < 0) {
+    if (win_chr_init(chr, filename, errp) < 0) {
         g_free(s);
-        return NULL;
+        return;
     }
-    return chr;
 }
 
 static int win_chr_pipe_poll(void *opaque)
@@ -1897,7 +1886,8 @@  static int win_chr_pipe_poll(void *opaque)
     return 0;
 }
 
-static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
+static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
+                             Error **errp)
 {
     WinCharState *s = chr->opaque;
     OVERLAPPED ov;
@@ -1909,12 +1899,12 @@  static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!s->hsend) {
-        fprintf(stderr, "Failed CreateEvent\n");
+        error_setg(errp, "Failed CreateEvent");
         goto fail;
     }
     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!s->hrecv) {
-        fprintf(stderr, "Failed CreateEvent\n");
+        error_setg(errp, "Failed CreateEvent");
         goto fail;
     }
 
@@ -1924,7 +1914,7 @@  static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
                               PIPE_WAIT,
                               MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
     if (s->hcom == INVALID_HANDLE_VALUE) {
-        fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
+        error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError());
         s->hcom = NULL;
         goto fail;
     }
@@ -1933,13 +1923,13 @@  static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
     ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
     ret = ConnectNamedPipe(s->hcom, &ov);
     if (ret) {
-        fprintf(stderr, "Failed ConnectNamedPipe\n");
+        error_setg(errp, "Failed ConnectNamedPipe");
         goto fail;
     }
 
     ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
     if (!ret) {
-        fprintf(stderr, "Failed GetOverlappedResult\n");
+        error_setg(errp, "Failed GetOverlappedResult");
         if (ov.hEvent) {
             CloseHandle(ov.hEvent);
             ov.hEvent = NULL;
@@ -1960,8 +1950,8 @@  static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 }
 
 
-static CharDriverState *qemu_chr_open_pipe(CharDriverState *chr,
-                                           ChardevHostdev *opts)
+static void qemu_chr_open_pipe(CharDriverState *chr, ChardevHostdev *opts,
+                               Error **errp)
 {
     const char *filename = opts->device;
     WinCharState *s;
@@ -1971,15 +1961,13 @@  static CharDriverState *qemu_chr_open_pipe(CharDriverState *chr,
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
 
-    if (win_chr_pipe_init(chr, filename) < 0) {
+    if (win_chr_pipe_init(chr, filename, errp) < 0) {
         g_free(s);
-        return NULL;
+        return;
     }
-    return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_file(CharDriverState *chr,
-                                               HANDLE fd_out)
+static voidqemu_chr_open_win_file(CharDriverState *chr, HANDLE fd_out)
 {
     WinCharState *s;
 
@@ -1987,12 +1975,11 @@  static CharDriverState *qemu_chr_open_win_file(CharDriverState *chr,
     s->hcom = fd_out;
     chr->opaque = s;
     chr->chr_write = win_chr_write;
-    return chr;
 }
 
-static CharDriverState *qemu_chr_open_win_con(CharDriverState *chr)
+static void qemu_chr_open_win_con(CharDriverState *chr)
 {
-    return qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
+    qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
 }
 
 static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
@@ -2293,7 +2280,7 @@  static void udp_chr_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_udp_fd(CharDriverState *chr, int fd)
+static void qemu_chr_open_udp_fd(CharDriverState *chr, int fd, Error **errp)
 {
     NetCharDriver *s = NULL;
 
@@ -2309,21 +2296,18 @@  static CharDriverState *qemu_chr_open_udp_fd(CharDriverState *chr, int fd)
     chr->chr_close = udp_chr_close;
     /* be isn't opened until we get a connection */
     chr->explicit_be_open = true;
-    return chr;
 }
 
-static CharDriverState *qemu_chr_open_udp(CharDriverState *chr, QemuOpts *opts)
+static void qemu_chr_open_udp(CharDriverState *chr, QemuOpts *opts,
+                              Error **errp)
 {
-    Error *local_err = NULL;
     int fd = -1;
 
-    fd = inet_dgram_opts(opts, &local_err);
+    fd = inet_dgram_opts(opts, errp);
     if (fd < 0) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-        return NULL;
+        return;
     }
-    return qemu_chr_open_udp_fd(chr, fd);
+    qemu_chr_open_udp_fd(chr, fd, errp);
 }
 
 /***********************************************************/
@@ -2535,9 +2519,9 @@  static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
 }
 
 #ifndef _WIN32
-CharDriverState *qemu_chr_open_eventfd(CharDriverState *chr, int eventfd)
+void qemu_chr_open_eventfd(CharDriverState *chr, int eventfd)
 {
-    return qemu_chr_open_fd(chr, eventfd, eventfd, FALSE);
+    qemu_chr_open_fd(chr, eventfd, eventfd, FALSE);
 }
 #endif
 
@@ -2684,11 +2668,10 @@  static void tcp_chr_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_socket_fd(CharDriverState *chr,
-                                                int fd, bool do_nodelay,
-                                                bool is_listen, bool is_telnet,
-                                                bool is_waitconnect,
-                                                Error **errp)
+static void qemu_chr_open_socket_fd(CharDriverState *chr,
+                                    int fd, bool do_nodelay,
+                                    bool is_listen, bool is_telnet,
+                                    bool is_waitconnect, Error **errp)
 {
     TCPCharDriver *s = NULL;
     char host[NI_MAXHOST], serv[NI_MAXSERV];
@@ -2699,7 +2682,7 @@  static CharDriverState *qemu_chr_open_socket_fd(CharDriverState *chr,
     memset(&ss, 0, ss_len);
     if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) != 0) {
         error_setg_errno(errp, errno, "getsockname");
-        return NULL;
+        return;
     }
 
     s = g_malloc0(sizeof(TCPCharDriver));
@@ -2761,13 +2744,11 @@  static CharDriverState *qemu_chr_open_socket_fd(CharDriverState *chr,
         tcp_chr_accept(s->listen_chan, G_IO_IN, chr);
         qemu_set_nonblock(s->listen_fd);
     }
-    return chr;
 }
 
-static CharDriverState *qemu_chr_open_socket(CharDriverState *chr,
-                                             QemuOpts *opts)
+static void qemu_chr_open_socket(CharDriverState *chr,
+                                 QemuOpts *opts, Error **errp)
 {
-    Error *local_err = NULL;
     int fd = -1;
 
     bool is_listen      = qemu_opt_get_bool(opts, "server", false);
@@ -2781,15 +2762,15 @@  static CharDriverState *qemu_chr_open_socket(CharDriverState *chr,
 
     if (is_unix) {
         if (is_listen) {
-            fd = unix_listen_opts(opts, &local_err);
+            fd = unix_listen_opts(opts, errp);
         } else {
-            fd = unix_connect_opts(opts, &local_err, NULL, NULL);
+            fd = unix_connect_opts(opts, errp, NULL, NULL);
         }
     } else {
         if (is_listen) {
-            fd = inet_listen_opts(opts, 0, &local_err);
+            fd = inet_listen_opts(opts, 0, errp);
         } else {
-            fd = inet_connect_opts(opts, &local_err, NULL, NULL);
+            fd = inet_connect_opts(opts, errp, NULL, NULL);
         }
     }
     if (fd < 0) {
@@ -2800,18 +2781,12 @@  static CharDriverState *qemu_chr_open_socket(CharDriverState *chr,
         qemu_set_nonblock(fd);
 
     qemu_chr_open_socket_fd(chr, fd, do_nodelay, is_listen, is_telnet,
-                            is_waitconnect, &local_err);
-    if (local_err) {
-        goto fail;
+                            is_waitconnect, errp);
+    if (!error_is_set(errp)) {
+        return;
     }
-    return chr;
-
 
  fail:
-    if (local_err) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-    }
     if (fd >= 0) {
         closesocket(fd);
     }
@@ -2819,7 +2794,6 @@  static CharDriverState *qemu_chr_open_socket(CharDriverState *chr,
         g_free(chr->opaque);
         chr->opaque = NULL;
     }
-    return NULL;
 }
 
 /*********************************************************/
@@ -2879,9 +2853,8 @@  static void ringbuf_chr_close(struct CharDriverState *chr)
     chr->opaque = NULL;
 }
 
-static CharDriverState *qemu_chr_open_ringbuf(struct CharDriverState *chr,
-                                              ChardevRingbuf *opts,
-                                              Error **errp)
+static void qemu_chr_open_ringbuf(struct CharDriverState *chr,
+                                  ChardevRingbuf *opts, Error **errp)
 {
     RingBufCharDriver *d;
 
@@ -2892,7 +2865,8 @@  static CharDriverState *qemu_chr_open_ringbuf(struct CharDriverState *chr,
     /* 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");
-        goto fail;
+        g_free(d);
+        return;
     }
 
     d->prod = 0;
@@ -2902,12 +2876,6 @@  static CharDriverState *qemu_chr_open_ringbuf(struct CharDriverState *chr,
     chr->opaque = d;
     chr->chr_write = ringbuf_chr_write;
     chr->chr_close = ringbuf_chr_close;
-
-    return chr;
-
-fail:
-    g_free(d);
-    return NULL;
 }
 
 static bool chr_is_ringbuf(const CharDriverState *chr)
@@ -3230,7 +3198,7 @@  typedef struct CharDriver {
     const char *name;
     int (*recon_setup)(CharDriverState *);
     /* old, pre qapi */
-    CharDriverState *(*open)(CharDriverState *chr, QemuOpts *opts);
+    void (*open)(CharDriverState *chr, QemuOpts *opts, Error **errp);
     /* new, qapi-based */
     ChardevBackendKind kind;
     void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
@@ -3239,7 +3207,7 @@  typedef struct CharDriver {
 static GSList *backends;
 
 void register_char_driver(const char *name,
-                          CharDriverState *(*open)(CharDriverState*,QemuOpts *),
+                          void (*open)(CharDriverState *, QemuOpts *, Error **),
                           int (*recon_setup)(CharDriverState *))
 {
     CharDriver *s;
@@ -3271,12 +3239,20 @@  static void generic_recon_state_change(void *opaque, int is_open)
 
     if (!is_open) {
         struct CharDriver *cd = chr->backend->data;
+        Error *local_err = NULL;
 
         if (chr->be_open) {
             return;
         }
 
-        cd->open(chr, chr->opts);
+        cd->open(chr, chr->opts, &local_err);
+        if (error_is_set(&local_err)) {
+            fprintf(stderr, "chardev: opening backend \"%s\" failed: %s."
+                    " Will retry in %llu seconds\n",
+                    chr->label, error_get_pretty(local_err),
+                    (unsigned long long) chr->recon->recon_time);
+            error_free(local_err);
+        }
     } else {
         void (*chr_close)(struct CharDriverState *chr) = chr->chr_close;
 
@@ -3313,6 +3289,7 @@  CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
                                     void (*init)(struct CharDriverState *s),
                                     Error **errp)
 {
+    Error *local_err = NULL;
     CharDriver *cd;
     CharDriverState *chr;
     GSList *i;
@@ -3419,14 +3396,21 @@  CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         }
     }
 
-    if (!cd->open(chr, opts)) {
-        if (!chr->recon) {
+    cd->open(chr, opts, &local_err);
+    if (error_is_set(&local_err)) {
+        if (chr->recon) {
+            fprintf(stderr, "chardev: opening backend \"%s\" failed: %s."
+                    " Will retry in %llu seconds\n",
+                    qemu_opts_id(opts), error_get_pretty(local_err),
+                    (unsigned long long) chr->recon->recon_time);
+        } else {
             /* Reconnect is not enabled, give up */
-            fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
-                    qemu_opt_get(opts, "backend"));
+            error_setg(errp, "chardev: opening backend \"%s\" failed: %s",
+                       qemu_opts_id(opts), error_get_pretty(local_err));
             g_free(chr);
             return NULL;
         }
+        error_free(local_err);
     }
 
     if (!chr->filename)
@@ -3724,38 +3708,35 @@  QemuOptsList qemu_chardev_opts = {
 
 #ifdef _WIN32
 
-static CharDriverState *qmp_chardev_open_file(CharDriverState *chr,
-                                              ChardevFile *file, Error **errp)
+static void qmp_chardev_open_file(CharDriverState *chr,
+                                  ChardevFile *file, Error **errp)
 {
     HANDLE out;
 
     if (file->has_in) {
         error_setg(errp, "input file not supported");
-        return NULL;
+        return;
     }
 
     out = CreateFile(file->out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                      OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     if (out == INVALID_HANDLE_VALUE) {
         error_setg(errp, "open %s failed", file->out);
-        return NULL;
+        return;
     }
-    return qemu_chr_open_win_file(out);
+    qemu_chr_open_win_file(out);
 }
 
-static CharDriverState *qmp_chardev_open_serial(CharDriverState *chr,
-                                                ChardevHostdev *serial,
-                                                Error **errp)
+static void qmp_chardev_open_serial(CharDriverState *chr,
+                                    ChardevHostdev *serial, Error **errp)
 {
-    return qemu_chr_open_win_path(serial->device);
+    qemu_chr_open_win_path(serial->device, errp);
 }
 
-static CharDriverState *qmp_chardev_open_parallel(CharDriverState *chr,
-                                                  ChardevHostdev *parallel,
-                                                  Error **errp)
+static void qmp_chardev_open_parallel(CharDriverState *chr,
+                                      ChardevHostdev *parallel, Error **errp)
 {
     error_setg(errp, "character device backend type 'parallel' not supported");
-    return NULL;
 }
 
 #else /* WIN32 */
@@ -3772,15 +3753,15 @@  static int qmp_chardev_open_file_source(char *src, int flags,
     return fd;
 }
 
-static CharDriverState *qmp_chardev_open_file(CharDriverState *chr,
-                                              ChardevFile *file, Error **errp)
+static void qmp_chardev_open_file(CharDriverState *chr,
+                                  ChardevFile *file, Error **errp)
 {
     int flags, in = -1, out = -1;
 
     flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY;
     out = qmp_chardev_open_file_source(file->out, flags, errp);
     if (error_is_set(errp)) {
-        return NULL;
+        return;
     }
 
     if (file->has_in) {
@@ -3788,55 +3769,50 @@  static CharDriverState *qmp_chardev_open_file(CharDriverState *chr,
         in = qmp_chardev_open_file_source(file->in, flags, errp);
         if (error_is_set(errp)) {
             qemu_close(out);
-            return NULL;
+            return;
         }
     }
 
-    return qemu_chr_open_fd(chr, in, out, TRUE);
+    qemu_chr_open_fd(chr, in, out, TRUE);
 }
 
-static CharDriverState *qmp_chardev_open_serial(CharDriverState *chr,
-                                                ChardevHostdev *serial,
-                                                Error **errp)
+static void qmp_chardev_open_serial(CharDriverState *chr,
+                                    ChardevHostdev *serial, Error **errp)
 {
 #ifdef HAVE_CHARDEV_TTY
     int fd;
 
     fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
     if (error_is_set(errp)) {
-        return NULL;
+        return;
     }
     qemu_set_nonblock(fd);
-    return qemu_chr_open_tty_fd(chr, fd);
+    qemu_chr_open_tty_fd(chr, fd);
 #else
     error_setg(errp, "character device backend type 'serial' not supported");
-    return NULL;
 #endif
 }
 
-static CharDriverState *qmp_chardev_open_parallel(CharDriverState *chr,
-                                                  ChardevHostdev *parallel,
-                                                  Error **errp)
+static void qmp_chardev_open_parallel(CharDriverState *chr,
+                                      ChardevHostdev *parallel, Error **errp)
 {
 #ifdef HAVE_CHARDEV_PARPORT
     int fd;
 
     fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
     if (error_is_set(errp)) {
-        return NULL;
+        return;
     }
-    return qemu_chr_open_pp_fd(chr, fd);
+    qemu_chr_open_pp_fd(chr, fd, errp);
 #else
     error_setg(errp, "character device backend type 'parallel' not supported");
-    return NULL;
 #endif
 }
 
 #endif /* WIN32 */
 
-static CharDriverState *qmp_chardev_open_socket(CharDriverState *chr,
-                                                ChardevSocket *sock,
-                                                Error **errp)
+static void qmp_chardev_open_socket(CharDriverState *chr,
+                                    ChardevSocket *sock, Error **errp)
 {
     SocketAddress *addr = sock->addr;
     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
@@ -3851,30 +3827,29 @@  static CharDriverState *qmp_chardev_open_socket(CharDriverState *chr,
         fd = socket_connect(addr, errp, NULL, NULL);
     }
     if (error_is_set(errp)) {
-        return NULL;
+        return;
     }
-    return qemu_chr_open_socket_fd(chr, fd, do_nodelay, is_listen,
-                                   is_telnet, is_waitconnect, errp);
+    qemu_chr_open_socket_fd(chr, fd, do_nodelay, is_listen,
+                            is_telnet, is_waitconnect, errp);
 }
 
-static CharDriverState *qmp_chardev_open_udp(CharDriverState *chr,
-                                             ChardevUdp *udp,
-                                             Error **errp)
+static void qmp_chardev_open_udp(CharDriverState *chr,
+                                 ChardevUdp *udp, Error **errp)
 {
     int fd;
 
     fd = socket_dgram(udp->remote, udp->local, errp);
     if (error_is_set(errp)) {
-        return NULL;
+        return;
     }
-    return qemu_chr_open_udp_fd(chr, fd);
+    qemu_chr_open_udp_fd(chr, fd, errp);
 }
 
 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                                Error **errp)
 {
     ChardevReturn *ret = g_new0(ChardevReturn, 1);
-    CharDriverState *base, *chr, *newchr;
+    CharDriverState *base, *chr;
 
     chr = qemu_chr_find(id);
     if (chr) {
@@ -3883,34 +3858,34 @@  ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         return NULL;
     }
 
-    newchr = g_malloc0(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(CharDriverState));
 
     switch (backend->kind) {
     case CHARDEV_BACKEND_KIND_FILE:
-        chr = qmp_chardev_open_file(newchr, backend->file, errp);
+        qmp_chardev_open_file(chr, backend->file, errp);
         break;
     case CHARDEV_BACKEND_KIND_SERIAL:
-        chr = qmp_chardev_open_serial(newchr, backend->serial, errp);
+        qmp_chardev_open_serial(chr, backend->serial, errp);
         break;
     case CHARDEV_BACKEND_KIND_PARALLEL:
-        chr = qmp_chardev_open_parallel(newchr, backend->parallel, errp);
+        qmp_chardev_open_parallel(chr, backend->parallel, errp);
         break;
     case CHARDEV_BACKEND_KIND_PIPE:
-        chr = qemu_chr_open_pipe(newchr, backend->pipe);
+        qemu_chr_open_pipe(chr, backend->pipe, errp);
         break;
     case CHARDEV_BACKEND_KIND_SOCKET:
-        chr = qmp_chardev_open_socket(newchr, backend->socket, errp);
+        qmp_chardev_open_socket(chr, backend->socket, errp);
         break;
     case CHARDEV_BACKEND_KIND_UDP:
-        chr = qmp_chardev_open_udp(newchr, backend->udp, errp);
+        qmp_chardev_open_udp(chr, backend->udp, errp);
         break;
 #ifdef HAVE_CHARDEV_TTY
     case CHARDEV_BACKEND_KIND_PTY:
-        chr = qemu_chr_open_pty(newchr, id, ret);
+        qemu_chr_open_pty(chr, id, ret, errp);
         break;
 #endif
     case CHARDEV_BACKEND_KIND_NULL:
-        chr = qemu_chr_open_null(newchr);
+        chr = qemu_chr_open_null(chr);
         break;
     case CHARDEV_BACKEND_KIND_MUX:
         base = qemu_chr_find(backend->mux->chardev);
@@ -3919,48 +3894,45 @@  ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                        backend->mux->chardev);
             break;
         }
-        chr = qemu_chr_open_mux(newchr, base);
+        qemu_chr_open_mux(chr, base);
         break;
     case CHARDEV_BACKEND_KIND_MSMOUSE:
-        chr = qemu_chr_open_msmouse(newchr);
+        qemu_chr_open_msmouse(chr, errp);
         break;
 #ifdef CONFIG_BRLAPI
     case CHARDEV_BACKEND_KIND_BRAILLE:
-        chr = chr_baum_init(newchr);
+        chr_baum_init(chr, errp);
         break;
 #endif
     case CHARDEV_BACKEND_KIND_STDIO:
-        chr = qemu_chr_open_stdio(newchr, backend->stdio);
+        qemu_chr_open_stdio(chr, backend->stdio, errp);
         break;
 #ifdef _WIN32
     case CHARDEV_BACKEND_KIND_CONSOLE:
-        chr = qemu_chr_open_win_con(newchr);
+        qemu_chr_open_win_con(chr);
         break;
 #endif
 #ifdef CONFIG_SPICE
     case CHARDEV_BACKEND_KIND_SPICEVMC:
-        chr = qemu_chr_open_spice_vmc(newchr, backend->spicevmc->type);
+        qemu_chr_open_spice_vmc(chr, backend->spicevmc->type, errp);
         break;
     case CHARDEV_BACKEND_KIND_SPICEPORT:
-        chr = qemu_chr_open_spice_port(newchr, backend->spiceport->fqdn);
+        qemu_chr_open_spice_port(chr, backend->spiceport->fqdn, errp);
         break;
 #endif
     case CHARDEV_BACKEND_KIND_VC:
-        chr = vc_init(newchr, backend->vc);
+        vc_init(chr, backend->vc, errp);
         break;
     case CHARDEV_BACKEND_KIND_RINGBUF:
     case CHARDEV_BACKEND_KIND_MEMORY:
-        chr = qemu_chr_open_ringbuf(newchr, backend->ringbuf, errp);
+        qemu_chr_open_ringbuf(chr, backend->ringbuf, errp);
         break;
     default:
         error_setg(errp, "unknown chardev backend (%d)", backend->kind);
         break;
     }
 
-    if (chr == NULL && !error_is_set(errp)) {
-        error_setg(errp, "Failed to create chardev");
-    }
-    if (chr) {
+    if (!error_is_set(errp)) {
         chr->label = g_strdup(id);
         chr->avail_connections =
             (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
@@ -3971,12 +3943,12 @@  ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
             qemu_chr_be_event(chr, CHR_EVENT_OPENED);
         }
         QTAILQ_INSERT_TAIL(&chardevs, chr, next);
-        return ret;
     } else {
-        g_free(newchr);
+        g_free(chr);
         g_free(ret);
-        return NULL;
+        ret = NULL;
     }
+    return ret;
 }
 
 void qmp_chardev_remove(const char *id, Error **errp)
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index c2f5375..8d999f1 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -261,8 +261,8 @@  static void print_allowed_subtypes(void)
     fprintf(stderr, "\n");
 }
 
-static CharDriverState *chr_open(CharDriverState *chr, const char *subtype,
-    void (*set_fe_open)(struct CharDriverState *, int))
+static void chr_open(CharDriverState *chr, const char *subtype,
+                     void (*set_fe_open)(struct CharDriverState *, int))
 {
     SpiceCharDriver *s;
 
@@ -279,18 +279,18 @@  static CharDriverState *chr_open(CharDriverState *chr, const char *subtype,
     chr->chr_fe_event = spice_chr_fe_event;
 
     QLIST_INSERT_HEAD(&spice_chars, s, next);
-
-    return chr;
 }
 
-CharDriverState *qemu_chr_open_spice_vmc(CharDriverState *chr, const char *type)
+void qemu_chr_open_spice_vmc(CharDriverState *chr, const char *type,
+                             Error *errp)
 {
     const char **psubtype = spice_server_char_device_recognized_subtypes();
 
     if (type == NULL) {
         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
         print_allowed_subtypes();
-        return NULL;
+        error_setg(errp, "open spice vmc failed");
+        return;
     }
     for (; *psubtype != NULL; ++psubtype) {
         if (strcmp(type, *psubtype) == 0) {
@@ -300,7 +300,8 @@  CharDriverState *qemu_chr_open_spice_vmc(CharDriverState *chr, const char *type)
     if (*psubtype == NULL) {
         fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
         print_allowed_subtypes();
-        return NULL;
+        error_setg(errp, "open spice vmc failed");
+        return;
     }
 
     return chr_open(chr, type, spice_vmc_set_fe_open);
diff --git a/ui/console.c b/ui/console.c
index 0ac45c5..a204ce2 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1724,7 +1724,7 @@  static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         chr->init(chr);
 }
 
-static CharDriverState *text_console_init(CharDriverState *chr, ChardevVC *vc)
+static void text_console_init(CharDriverState *chr, ChardevVC *vc, Error **errp)
 {
     QemuConsole *s;
     unsigned width = 0;
@@ -1751,7 +1751,8 @@  static CharDriverState *text_console_init(CharDriverState *chr, ChardevVC *vc)
     }
 
     if (!s) {
-        return NULL;
+        error_setg(errp, "Unable to create a new vc console");
+        return;
     }
 
     s->chr = chr;
@@ -1765,14 +1766,13 @@  static CharDriverState *text_console_init(CharDriverState *chr, ChardevVC *vc)
     if (display_state) {
         text_console_do_init(chr, display_state);
     }
-    return chr;
 }
 
 static VcHandler *vc_handler = text_console_init;
 
-CharDriverState *vc_init(CharDriverState *chr, ChardevVC *vc)
+void vc_init(CharDriverState *chr, ChardevVC *vc, Error **errp)
 {
-    return vc_handler(chr, vc);
+    vc_handler(chr, vc, errp);
 }
 
 void register_vc_handler(VcHandler *handler)
diff --git a/ui/gtk.c b/ui/gtk.c
index 0ecc26a..a970860 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1125,15 +1125,13 @@  static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 static int nb_vcs;
 static CharDriverState *vcs[MAX_VCS];
 
-static CharDriverState *gd_vc_handler(CharDriverState *chr, ChardevVC *unused)
+static void gd_vc_handler(CharDriverState *chr, ChardevVC *unused, Error **errp)
 {
     chr->chr_write = gd_vc_chr_write;
     /* defer OPENED events until our vc is fully initialized */
     chr->explicit_be_open = true;
 
     vcs[nb_vcs++] = chr;
-
-    return chr;
 }
 
 void early_gtk_display_init(void)