From f1a1a35638bf045a2b158c0cb23d92ef39c06792 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 10:33:56 +0100 Subject: chardev: add qmp hotplug commands, with null chardev support Add chardev-add and chardev-remove qmp commands. Hotplugging a null chardev is supported for now, more will be added later. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'qapi-schema.json') diff --git a/qapi-schema.json b/qapi-schema.json index 5dfa052391..462511e904 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3017,3 +3017,52 @@ # Since: 1.3.0 ## { 'command': 'nbd-server-stop' } + +## +# @ChardevBackend: +# +# Configuration info for the new chardev backend. +# +# Since: 1.4 +## +{ 'type': 'ChardevDummy', 'data': { } } + +{ 'union': 'ChardevBackend', 'data': { 'null' : 'ChardevDummy' } } + +## +# @ChardevReturn: +# +# Return info about the chardev backend just created. +# +# Since: 1.4 +## +{ 'type' : 'ChardevReturn', 'data': { } } + +## +# @chardev-add: +# +# Add a file chardev +# +# @id: the chardev's ID, must be unique +# @backend: backend type and parameters +# +# Returns: chardev info. +# +# Since: 1.4 +## +{ 'command': 'chardev-add', 'data': {'id' : 'str', + 'backend' : 'ChardevBackend' }, + 'returns': 'ChardevReturn' } + +## +# @chardev-remove: +# +# Remove a chardev +# +# @id: the chardev's ID, must exist and not be in use +# +# Returns: Nothing on success +# +# Since: 1.4 +## +{ 'command': 'chardev-remove', 'data': {'id': 'str'} } -- cgit v1.2.3-55-g7522 From ffbdbe59acc5f175d6c05a5d90f0b7c865fafd5b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 13:13:57 +0100 Subject: chardev: add file chardev support to chardev-add (qmp) Add support for file chardevs. Output file is mandatory, input file is optional. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 16 ++++++++++++++- qemu-char.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 8 +++++++- 3 files changed, 83 insertions(+), 2 deletions(-) (limited to 'qapi-schema.json') diff --git a/qapi-schema.json b/qapi-schema.json index 462511e904..c70c11840a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3018,6 +3018,19 @@ ## { 'command': 'nbd-server-stop' } +## +# @ChardevFile: +# +# Configuration info for file chardevs. +# +# @in: #optional The name of the input file +# @out: The name of the output file +# +# Since: 1.4 +## +{ 'type': 'ChardevFile', 'data': { '*in' : 'str', + 'out' : 'str' } } + ## # @ChardevBackend: # @@ -3027,7 +3040,8 @@ ## { 'type': 'ChardevDummy', 'data': { } } -{ 'union': 'ChardevBackend', 'data': { 'null' : 'ChardevDummy' } } +{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', + 'null' : 'ChardevDummy' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 73a5e37aa7..d447d96805 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3011,6 +3011,64 @@ QemuOptsList qemu_chardev_opts = { }, }; +#ifdef _WIN32 + +static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) +{ + HANDLE out; + + if (file->in) { + error_setg(errp, "input file not supported"); + return NULL; + } + + 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 qemu_chr_open_win_file(out); +} + +#else /* WIN32 */ + +static int qmp_chardev_open_file_source(char *src, int flags, + Error **errp) +{ + int fd = -1; + + TFR(fd = qemu_open(src, flags, 0666)); + if (fd == -1) { + error_setg(errp, "open %s: %s", src, strerror(errno)); + } + return fd; +} + +static CharDriverState *qmp_chardev_open_file(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; + } + + if (file->in) { + flags = O_RDONLY; + in = qmp_chardev_open_file_source(file->in, flags, errp); + if (error_is_set(errp)) { + qemu_close(out); + return NULL; + } + } + + return qemu_chr_open_fd(in, out); +} + +#endif /* WIN32 */ + ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { @@ -3025,6 +3083,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } switch (backend->kind) { + case CHARDEV_BACKEND_KIND_FILE: + chr = qmp_chardev_open_file(backend->file, errp); + break; case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; diff --git a/qmp-commands.hx b/qmp-commands.hx index c9ab37c9b9..4d382f4ffc 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2672,13 +2672,19 @@ Arguments: - "id": the chardev's ID, must be unique (json-string) - "backend": chardev backend type + parameters -Example: +Examples: -> { "execute" : "chardev-add", "arguments" : { "id" : "foo", "backend" : { "type" : "null", "data" : {} } } } <- { "return": {} } +-> { "execute" : "chardev-add", + "arguments" : { "id" : "bar", + "backend" : { "type" : "file", + "data" : { "out" : "/tmp/bar.log" } } } } +<- { "return": {} } + EQMP { -- cgit v1.2.3-55-g7522 From d59044ef74d577797d087bc6ffb156cec89ed39a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 13:50:29 +0100 Subject: chardev: add serial chardev support to chardev-add (qmp) Similar to file, except that no separate in/out files are supported because it's pointless for direct device access. Also the special tty ioctl hooks (pass through linespeed settings etc) are activated on Unix. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 17 ++++++++++++++++ qemu-char.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-------- qemu-options.hx | 9 ++++---- 3 files changed, 75 insertions(+), 13 deletions(-) (limited to 'qapi-schema.json') diff --git a/qapi-schema.json b/qapi-schema.json index c70c11840a..bbbbd33d75 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3031,6 +3031,22 @@ { 'type': 'ChardevFile', 'data': { '*in' : 'str', 'out' : 'str' } } +## +# @ChardevPort: +# +# Configuration info for device chardevs. +# +# @device: The name of the special file for the device, +# i.e. /dev/ttyS0 on Unix or COM1: on Windows +# @type: What kind of device this is. +# +# Since: 1.4 +## +{ 'enum': 'ChardevPortKind', 'data': [ 'serial' ] } + +{ 'type': 'ChardevPort', 'data': { 'device' : 'str', + 'type' : 'ChardevPortKind'} } + ## # @ChardevBackend: # @@ -3041,6 +3057,7 @@ { 'type': 'ChardevDummy', 'data': { } } { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', + 'port' : 'ChardevPort', 'null' : 'ChardevDummy' } } ## diff --git a/qemu-char.c b/qemu-char.c index d447d96805..839839892c 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1230,21 +1230,27 @@ static void qemu_chr_close_tty(CharDriverState *chr) } } +static CharDriverState *qemu_chr_open_tty_fd(int fd) +{ + CharDriverState *chr; + + tty_serial_init(fd, 115200, 'N', 8, 1); + chr = qemu_chr_open_fd(fd, fd); + chr->chr_ioctl = tty_serial_ioctl; + chr->chr_close = qemu_chr_close_tty; + return chr; +} + static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) { const char *filename = qemu_opt_get(opts, "path"); - CharDriverState *chr; int fd; TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK)); if (fd < 0) { return NULL; } - tty_serial_init(fd, 115200, 'N', 8, 1); - chr = qemu_chr_open_fd(fd, fd); - chr->chr_ioctl = tty_serial_ioctl; - chr->chr_close = qemu_chr_close_tty; - return chr; + return qemu_chr_open_tty_fd(fd); } #endif /* __linux__ || __sun__ */ @@ -1666,9 +1672,8 @@ static int win_chr_poll(void *opaque) return 0; } -static CharDriverState *qemu_chr_open_win(QemuOpts *opts) +static CharDriverState *qemu_chr_open_win_path(const char *filename) { - const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; WinCharState *s; @@ -1687,6 +1692,11 @@ static CharDriverState *qemu_chr_open_win(QemuOpts *opts) return chr; } +static CharDriverState *qemu_chr_open_win(QemuOpts *opts) +{ + return qemu_chr_open_win_path(qemu_opt_get(opts, "path")); +} + static int win_chr_pipe_poll(void *opaque) { CharDriverState *chr = opaque; @@ -2765,6 +2775,7 @@ static const struct { #endif #ifdef HAVE_CHARDEV_TTY { .name = "tty", .open = qemu_chr_open_tty }, + { .name = "serial", .open = qemu_chr_open_tty }, { .name = "pty", .open = qemu_chr_open_pty }, #endif #ifdef HAVE_CHARDEV_PARPORT @@ -3031,6 +3042,17 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_win_file(out); } +static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) +{ + switch (port->type) { + case CHARDEV_PORT_KIND_SERIAL: + return qemu_chr_open_win_path(port->device); + default: + error_setg(errp, "unknown chardev port (%d)", port->type); + return NULL; + } +} + #else /* WIN32 */ static int qmp_chardev_open_file_source(char *src, int flags, @@ -3067,6 +3089,27 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_fd(in, out); } +static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) +{ + int flags, fd; + + switch (port->type) { +#ifdef HAVE_CHARDEV_TTY + case CHARDEV_PORT_KIND_SERIAL: + flags = O_RDWR; + fd = qmp_chardev_open_file_source(port->device, flags, errp); + if (error_is_set(errp)) { + return NULL; + } + socket_set_nonblock(fd); + return qemu_chr_open_tty_fd(fd); +#endif + default: + error_setg(errp, "unknown chardev port (%d)", port->type); + return NULL; + } +} + #endif /* WIN32 */ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, @@ -3086,6 +3129,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_FILE: chr = qmp_chardev_open_file(backend->file, errp); break; + case CHARDEV_BACKEND_KIND_PORT: + chr = qmp_chardev_open_port(backend->port, errp); + break; case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; diff --git a/qemu-options.hx b/qemu-options.hx index 9df0cde64c..17cc1ad903 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1742,6 +1742,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #endif #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + "-chardev serial,id=id,path=path[,mux=on|off]\n" "-chardev tty,id=id,path=path[,mux=on|off]\n" #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) @@ -1910,8 +1911,8 @@ take any options. Send traffic from the guest to a serial device on the host. -@option{serial} is -only available on Windows hosts. +On Unix hosts serial will actually accept any tty device, +not only serial lines. @option{path} specifies the name of the serial device to open. @@ -1937,10 +1938,8 @@ Connect to a local BrlAPI server. @option{braille} does not take any options. @item -chardev tty ,id=@var{id} ,path=@var{path} -Connect to a local tty device. - @option{tty} is only available on Linux, Sun, FreeBSD, NetBSD, OpenBSD and -DragonFlyBSD hosts. +DragonFlyBSD hosts. It is an alias for -serial. @option{path} specifies the path to the tty. @option{path} is required. -- cgit v1.2.3-55-g7522 From 88a946d32dd9e4c6c0ad56e19f2822bd5c8b416e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 10 Jan 2013 14:20:58 +0100 Subject: chardev: add parallel chardev support to chardev-add (qmp) Also alias the old parport name to parallel for -chardev. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 3 ++- qemu-char.c | 44 ++++++++++++++++++++++++++++---------------- qemu-options.hx | 5 ++++- 3 files changed, 34 insertions(+), 18 deletions(-) (limited to 'qapi-schema.json') diff --git a/qapi-schema.json b/qapi-schema.json index bbbbd33d75..320fa6baf1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3042,7 +3042,8 @@ # # Since: 1.4 ## -{ 'enum': 'ChardevPortKind', 'data': [ 'serial' ] } +{ 'enum': 'ChardevPortKind', 'data': [ 'serial', + 'parallel' ] } { 'type': 'ChardevPort', 'data': { 'device' : 'str', 'type' : 'ChardevPortKind'} } diff --git a/qemu-char.c b/qemu-char.c index 839839892c..7091e05ee2 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1367,17 +1367,10 @@ static void pp_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pp_fd(int fd) { - const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; ParallelCharDriver *drv; - int fd; - - TFR(fd = qemu_open(filename, O_RDWR)); - if (fd < 0) { - return NULL; - } if (ioctl(fd, PPCLAIM) < 0) { close(fd); @@ -1441,16 +1434,9 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pp_fd(int fd) { - const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; - int fd; - - fd = qemu_open(filename, O_RDWR); - if (fd < 0) { - return NULL; - } chr = g_malloc0(sizeof(CharDriverState)); chr->opaque = (void *)(intptr_t)fd; @@ -2750,6 +2736,22 @@ fail: return NULL; } +#ifdef HAVE_CHARDEV_PARPORT + +static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) +{ + const char *filename = qemu_opt_get(opts, "path"); + int fd; + + fd = qemu_open(filename, O_RDWR); + if (fd < 0) { + return NULL; + } + return qemu_chr_open_pp_fd(fd); +} + +#endif + static const struct { const char *name; CharDriverState *(*open)(QemuOpts *opts); @@ -2779,6 +2781,7 @@ static const struct { { .name = "pty", .open = qemu_chr_open_pty }, #endif #ifdef HAVE_CHARDEV_PARPORT + { .name = "parallel", .open = qemu_chr_open_pp }, { .name = "parport", .open = qemu_chr_open_pp }, #endif #ifdef CONFIG_SPICE @@ -3103,6 +3106,15 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) } socket_set_nonblock(fd); return qemu_chr_open_tty_fd(fd); +#endif +#ifdef HAVE_CHARDEV_PARPORT + case CHARDEV_PORT_KIND_PARALLEL: + flags = O_RDWR; + fd = qmp_chardev_open_file_source(port->device, flags, errp); + if (error_is_set(errp)) { + return NULL; + } + return qemu_chr_open_pp_fd(fd); #endif default: error_setg(errp, "unknown chardev port (%d)", port->type); diff --git a/qemu-options.hx b/qemu-options.hx index 17cc1ad903..40cd68399d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1746,6 +1746,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev tty,id=id,path=path[,mux=on|off]\n" #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) + "-chardev parallel,id=id,path=path[,mux=on|off]\n" "-chardev parport,id=id,path=path[,mux=on|off]\n" #endif #if defined(CONFIG_SPICE) @@ -1776,6 +1777,7 @@ Backend is one of: @option{stdio}, @option{braille}, @option{tty}, +@option{parallel}, @option{parport}, @option{spicevmc}. @option{spiceport}. @@ -1943,9 +1945,10 @@ DragonFlyBSD hosts. It is an alias for -serial. @option{path} specifies the path to the tty. @option{path} is required. +@item -chardev parallel ,id=@var{id} ,path=@var{path} @item -chardev parport ,id=@var{id} ,path=@var{path} -@option{parport} is only available on Linux, FreeBSD and DragonFlyBSD hosts. +@option{parallel} is only available on Linux, FreeBSD and DragonFlyBSD hosts. Connect to a local parallel port. -- cgit v1.2.3-55-g7522 From f6bd5d6ec514939c421fcd411d1a39bc7dad0948 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 20 Dec 2012 13:53:12 +0100 Subject: chardev: add socket chardev support to chardev-add (qmp) qemu_chr_open_socket is split into two functions. All initialization after creating the socket file handler is split away into the new qemu_chr_open_socket_fd function. chr->filename doesn't get filled from QemuOpts any more. Qemu gathers the information using getsockname and getnameinfo instead. This way it will also work correctly for file handles passed via file descriptor passing. Finally qmp_chardev_open_socket() is the actual qmp hotplug implementation which basically just calls socket_listen or socket_connect and the new qemu_chr_open_socket_fd function. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 28 +++++++++- qemu-char.c | 166 +++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 138 insertions(+), 56 deletions(-) (limited to 'qapi-schema.json') diff --git a/qapi-schema.json b/qapi-schema.json index 320fa6baf1..5c3e3eb469 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3048,6 +3048,27 @@ { 'type': 'ChardevPort', 'data': { 'device' : 'str', 'type' : 'ChardevPortKind'} } +## +# @ChardevSocket: +# +# Configuration info for socket chardevs. +# +# @addr: socket address to listen on (server=true) +# or connect to (server=false) +# @server: #optional create server socket (default: true) +# @wait: #optional wait for connect (not used for server +# sockets, default: false) +# @nodelay: #optional set TCP_NODELAY socket option (default: false) +# @telnet: #optional enable telnet protocol (default: false) +# +# Since: 1.4 +## +{ 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress', + '*server' : 'bool', + '*wait' : 'bool', + '*nodelay' : 'bool', + '*telnet' : 'bool' } } + ## # @ChardevBackend: # @@ -3057,9 +3078,10 @@ ## { 'type': 'ChardevDummy', 'data': { } } -{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', - 'port' : 'ChardevPort', - 'null' : 'ChardevDummy' } } +{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', + 'port' : 'ChardevPort', + 'socket' : 'ChardevSocket', + 'null' : 'ChardevDummy' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 7091e05ee2..36d7e29953 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2438,10 +2438,88 @@ static void tcp_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) +static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, + bool is_listen, bool is_telnet, + bool is_waitconnect, + Error **errp) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; + char host[NI_MAXHOST], serv[NI_MAXSERV]; + const char *left = "", *right = ""; + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + + memset(&ss, 0, ss_len); + if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) != 0) { + error_setg(errp, "getsockname: %s", strerror(errno)); + return NULL; + } + + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(TCPCharDriver)); + + s->connected = 0; + s->fd = -1; + s->listen_fd = -1; + s->msgfd = -1; + + chr->filename = g_malloc(256); + switch (ss.ss_family) { +#ifndef _WIN32 + case AF_UNIX: + s->is_unix = 1; + snprintf(chr->filename, 256, "unix:%s%s", + ((struct sockaddr_un *)(&ss))->sun_path, + is_listen ? ",server" : ""); + break; +#endif + case AF_INET6: + left = "["; + right = "]"; + /* fall through */ + case AF_INET: + s->do_nodelay = do_nodelay; + getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host), + serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); + snprintf(chr->filename, 256, "%s:%s:%s%s%s%s", + is_telnet ? "telnet" : "tcp", + left, host, right, serv, + is_listen ? ",server" : ""); + break; + } + + chr->opaque = s; + chr->chr_write = tcp_chr_write; + chr->chr_close = tcp_chr_close; + chr->get_msgfd = tcp_get_msgfd; + chr->chr_add_client = tcp_chr_add_client; + + if (is_listen) { + s->listen_fd = fd; + qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); + if (is_telnet) { + s->do_telnetopt = 1; + } + } else { + s->connected = 1; + s->fd = fd; + socket_set_nodelay(fd); + tcp_chr_connect(chr); + } + + if (is_listen && is_waitconnect) { + printf("QEMU waiting for connection on: %s\n", + chr->filename); + tcp_chr_accept(chr); + socket_set_nonblock(s->listen_fd); + } + return chr; +} + +static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) +{ + CharDriverState *chr = NULL; Error *local_err = NULL; int fd = -1; int is_listen; @@ -2458,9 +2536,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (!is_listen) is_waitconnect = 0; - chr = g_malloc0(sizeof(CharDriverState)); - s = g_malloc0(sizeof(TCPCharDriver)); - if (is_unix) { if (is_listen) { fd = unix_listen_opts(opts, &local_err); @@ -2481,56 +2556,14 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (!is_waitconnect) socket_set_nonblock(fd); - s->connected = 0; - s->fd = -1; - s->listen_fd = -1; - s->msgfd = -1; - s->is_unix = is_unix; - s->do_nodelay = do_nodelay && !is_unix; - - chr->opaque = s; - chr->chr_write = tcp_chr_write; - chr->chr_close = tcp_chr_close; - chr->get_msgfd = tcp_get_msgfd; - chr->chr_add_client = tcp_chr_add_client; - - if (is_listen) { - s->listen_fd = fd; - qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); - if (is_telnet) - s->do_telnetopt = 1; - - } else { - s->connected = 1; - s->fd = fd; - socket_set_nodelay(fd); - tcp_chr_connect(chr); - } - - /* for "info chardev" monitor command */ - chr->filename = g_malloc(256); - if (is_unix) { - snprintf(chr->filename, 256, "unix:%s%s", - qemu_opt_get(opts, "path"), - qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); - } else if (is_telnet) { - snprintf(chr->filename, 256, "telnet:%s:%s%s", - qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), - qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); - } else { - snprintf(chr->filename, 256, "tcp:%s:%s%s", - qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), - qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); - } - - if (is_listen && is_waitconnect) { - printf("QEMU waiting for connection on: %s\n", - chr->filename); - tcp_chr_accept(chr); - socket_set_nonblock(s->listen_fd); + chr = qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, is_telnet, + is_waitconnect, &local_err); + if (error_is_set(&local_err)) { + goto fail; } return chr; + fail: if (local_err) { qerror_report_err(local_err); @@ -2539,8 +2572,10 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (fd >= 0) { closesocket(fd); } - g_free(s); - g_free(chr); + if (chr) { + g_free(chr->opaque); + g_free(chr); + } return NULL; } @@ -3124,6 +3159,28 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) #endif /* WIN32 */ +static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, + Error **errp) +{ + SocketAddress *addr = sock->addr; + bool do_nodelay = sock->has_nodelay ? sock->nodelay : false; + bool is_listen = sock->has_server ? sock->server : true; + bool is_telnet = sock->has_telnet ? sock->telnet : false; + bool is_waitconnect = sock->has_wait ? sock->wait : false; + int fd; + + if (is_listen) { + fd = socket_listen(addr, errp); + } else { + fd = socket_connect(addr, errp, NULL, NULL); + } + if (error_is_set(errp)) { + return NULL; + } + return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, + is_telnet, is_waitconnect, errp); +} + ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { @@ -3144,6 +3201,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_PORT: chr = qmp_chardev_open_port(backend->port, errp); break; + case CHARDEV_BACKEND_KIND_SOCKET: + chr = qmp_chardev_open_socket(backend->socket, errp); + break; case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; -- cgit v1.2.3-55-g7522 From 0a1a7fabda7f0fa05ef09051be29e92e81f929ad Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 20 Dec 2012 14:39:13 +0100 Subject: chardev: add pty chardev support to chardev-add (qmp) The ptsname is returned directly, so there is no need to use query-chardev to figure the pty device path. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 3 ++- qemu-char.c | 13 +++++++++++++ qmp-commands.hx | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'qapi-schema.json') diff --git a/qapi-schema.json b/qapi-schema.json index 5c3e3eb469..6d7252b9e8 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3081,6 +3081,7 @@ { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', 'port' : 'ChardevPort', 'socket' : 'ChardevSocket', + 'pty' : 'ChardevDummy', 'null' : 'ChardevDummy' } } ## @@ -3090,7 +3091,7 @@ # # Since: 1.4 ## -{ 'type' : 'ChardevReturn', 'data': { } } +{ 'type' : 'ChardevReturn', 'data': { '*pty' : 'str' } } ## # @chardev-add: diff --git a/qemu-char.c b/qemu-char.c index 36d7e29953..9ba0573c6a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3204,6 +3204,19 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_SOCKET: chr = qmp_chardev_open_socket(backend->socket, errp); break; +#ifdef HAVE_CHARDEV_TTY + case CHARDEV_BACKEND_KIND_PTY: + { + /* qemu_chr_open_pty sets "path" in opts */ + QemuOpts *opts; + opts = qemu_opts_create_nofail(qemu_find_opts("chardev")); + chr = qemu_chr_open_pty(opts); + ret->pty = g_strdup(qemu_opt_get(opts, "path")); + ret->has_pty = true; + qemu_opts_del(opts); + break; + } +#endif case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; diff --git a/qmp-commands.hx b/qmp-commands.hx index 4d382f4ffc..cbf12804be 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2685,6 +2685,11 @@ Examples: "data" : { "out" : "/tmp/bar.log" } } } } <- { "return": {} } +-> { "execute" : "chardev-add", + "arguments" : { "id" : "baz", + "backend" : { "type" : "pty", "data" : {} } } } +<- { "return": { "pty" : "/dev/pty/42" } } + EQMP { -- cgit v1.2.3-55-g7522