X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qga%2Fchannel-posix.c;h=5a925a9818430eff0ebe5a3b68de555196dfd93c;hb=HEAD;hp=50d9dd374758387d97ae8cddf525352eebdfd52f;hpb=f74df9bfce6d133fc64d6b878327849ed2b89b4b;p=mirror_qemu.git diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 50d9dd3747..465d688ecb 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -1,13 +1,10 @@ -#include -#include -#include -#include -#include -#include -#include #include "qemu/osdep.h" +#include "qemu/cutils.h" +#include +#include "qapi/error.h" #include "qemu/sockets.h" -#include "qga/channel.h" +#include "channel.h" +#include "cutils.h" #ifdef CONFIG_SOLARIS #include @@ -31,18 +28,15 @@ static gboolean ga_channel_listen_accept(GIOChannel *channel, GAChannel *c = data; int ret, client_fd; bool accepted = false; - struct sockaddr_un addr; - socklen_t addrlen = sizeof(addr); g_assert(channel != NULL); - client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), - (struct sockaddr *)&addr, &addrlen); + client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), NULL, NULL); if (client_fd == -1) { g_warning("error converting fd to gsocket: %s", strerror(errno)); goto out; } - qemu_set_nonblock(client_fd); + qemu_socket_set_nonblock(client_fd); ret = ga_channel_client_add(c, client_fd); if (ret) { g_warning("error setting up connection"); @@ -69,7 +63,6 @@ static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create) static void ga_channel_listen_close(GAChannel *c) { - g_assert(c->method == GA_CHANNEL_UNIX_LISTEN); g_assert(c->listen_channel); g_io_channel_shutdown(c->listen_channel, true, NULL); g_io_channel_unref(c->listen_channel); @@ -85,7 +78,7 @@ static void ga_channel_client_close(GAChannel *c) g_io_channel_shutdown(c->client_channel, true, NULL); g_io_channel_unref(c->client_channel); c->client_channel = NULL; - if (c->method == GA_CHANNEL_UNIX_LISTEN && c->listen_channel) { + if (c->listen_channel) { ga_channel_listen_add(c, 0, false); } } @@ -127,34 +120,57 @@ static int ga_channel_client_add(GAChannel *c, int fd) return 0; } -static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod method) +static gboolean ga_channel_open(GAChannel *c, const gchar *path, + GAChannelMethod method, int fd, Error **errp) { int ret; c->method = method; switch (c->method) { case GA_CHANNEL_VIRTIO_SERIAL: { - int fd = qemu_open(path, O_RDWR | O_NONBLOCK + assert(fd < 0); + fd = qga_open_cloexec( + path, #ifndef CONFIG_SOLARIS - | O_ASYNC + O_ASYNC | #endif - ); + O_RDWR | O_NONBLOCK, + 0 + ); if (fd == -1) { - g_critical("error opening channel: %s", strerror(errno)); + error_setg_errno(errp, errno, "error opening channel '%s'", path); return false; } #ifdef CONFIG_SOLARIS ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI); if (ret == -1) { - g_critical("error setting event mask for channel: %s", - strerror(errno)); + error_setg_errno(errp, errno, "error setting event mask for channel"); close(fd); return false; } #endif +#ifdef __FreeBSD__ + /* + * In the default state channel sends echo of every command to a + * client. The client program doesn't expect this and raises an + * error. Suppress echo by resetting ECHO terminal flag. + */ + struct termios tio; + if (tcgetattr(fd, &tio) < 0) { + error_setg_errno(errp, errno, "error getting channel termios attrs"); + close(fd); + return false; + } + tio.c_lflag &= ~ECHO; + if (tcsetattr(fd, TCSAFLUSH, &tio) < 0) { + error_setg_errno(errp, errno, "error setting channel termios attrs"); + close(fd); + return false; + } +#endif /* __FreeBSD__ */ ret = ga_channel_client_add(c, fd); if (ret) { - g_critical("error adding channel to main loop"); + error_setg(errp, "error adding channel to main loop"); close(fd); return false; } @@ -162,9 +178,11 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod } case GA_CHANNEL_ISA_SERIAL: { struct termios tio; - int fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); + + assert(fd < 0); + fd = qga_open_cloexec(path, O_RDWR | O_NOCTTY | O_NONBLOCK, 0); if (fd == -1) { - g_critical("error opening channel: %s", strerror(errno)); + error_setg_errno(errp, errno, "error opening channel '%s'", path); return false; } tcgetattr(fd, &tio); @@ -185,25 +203,45 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod tcsetattr(fd, TCSANOW, &tio); ret = ga_channel_client_add(c, fd); if (ret) { - g_critical("error adding channel to main loop"); + error_setg(errp, "error adding channel to main loop"); close(fd); return false; } break; } case GA_CHANNEL_UNIX_LISTEN: { - Error *local_err = NULL; - int fd = unix_listen(path, NULL, strlen(path), &local_err); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); - return false; + if (fd < 0) { + fd = unix_listen(path, errp); + if (fd < 0) { + return false; + } + } + ga_channel_listen_add(c, fd, true); + break; + } + case GA_CHANNEL_VSOCK_LISTEN: { + if (fd < 0) { + SocketAddress *addr; + char *addr_str; + + addr_str = g_strdup_printf("vsock:%s", path); + addr = socket_parse(addr_str, errp); + g_free(addr_str); + if (!addr) { + return false; + } + + fd = socket_listen(addr, 1, errp); + qapi_free_SocketAddress(addr); + if (fd < 0) { + return false; + } } ga_channel_listen_add(c, fd, true); break; } default: - g_critical("error binding/listening to specified socket"); + error_setg(errp, "error binding/listening to specified socket"); return false; } @@ -246,14 +284,16 @@ GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count) } GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, - GAChannelCallback cb, gpointer opaque) + int listen_fd, GAChannelCallback cb, gpointer opaque) { + Error *err = NULL; GAChannel *c = g_new0(GAChannel, 1); c->event_cb = cb; c->user_data = opaque; - if (!ga_channel_open(c, path, method)) { - g_critical("error opening channel"); + if (!ga_channel_open(c, path, method, listen_fd, &err)) { + g_critical("%s", error_get_pretty(err)); + error_free(err); ga_channel_free(c); return NULL; } @@ -263,8 +303,7 @@ GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, void ga_channel_free(GAChannel *c) { - if (c->method == GA_CHANNEL_UNIX_LISTEN - && c->listen_channel) { + if (c->listen_channel) { ga_channel_listen_close(c); } if (c->client_channel) {