2008-10-31 19:49:55 +01:00
|
|
|
/*
|
|
|
|
* QEMU System Emulator
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
2016-01-29 18:50:05 +01:00
|
|
|
#include "qemu/osdep.h"
|
2008-10-31 19:49:55 +01:00
|
|
|
#include "qemu-common.h"
|
2016-03-20 18:16:19 +01:00
|
|
|
#include "qemu/cutils.h"
|
2012-12-17 18:19:49 +01:00
|
|
|
#include "monitor/monitor.h"
|
2012-12-17 18:20:04 +01:00
|
|
|
#include "sysemu/sysemu.h"
|
2016-03-16 19:54:32 +01:00
|
|
|
#include "sysemu/block-backend.h"
|
2015-03-17 18:29:20 +01:00
|
|
|
#include "qemu/error-report.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/timer.h"
|
2013-04-08 16:55:25 +02:00
|
|
|
#include "sysemu/char.h"
|
2008-11-01 01:53:09 +01:00
|
|
|
#include "hw/usb.h"
|
2011-09-14 21:05:49 +02:00
|
|
|
#include "qmp-commands.h"
|
2016-06-09 18:48:45 +02:00
|
|
|
#include "qapi/clone-visitor.h"
|
2014-10-02 18:17:35 +02:00
|
|
|
#include "qapi-visit.h"
|
2015-11-23 16:29:59 +01:00
|
|
|
#include "qemu/base64.h"
|
2016-01-19 12:14:29 +01:00
|
|
|
#include "io/channel-socket.h"
|
|
|
|
#include "io/channel-file.h"
|
char: introduce support for TLS encrypted TCP chardev backend
This integrates support for QIOChannelTLS object in the TCP
chardev backend. If the 'tls-creds=NAME' option is passed with
the '-chardev tcp' argument, then it will setup the chardev
such that the client is required to establish a TLS handshake
when connecting. There is no support for checking the client
certificate against ACLs in this initial patch. This is pending
work to QOM-ify the ACL object code.
A complete invocation to run QEMU as the server for a TLS
encrypted serial dev might be
$ qemu-system-x86_64 \
-nodefconfig -nodefaults -device sga -display none \
-chardev socket,id=s0,host=127.0.0.1,port=9000,tls-creds=tls0,server \
-device isa-serial,chardev=s0 \
-object tls-creds-x509,id=tls0,endpoint=server,verify-peer=off,\
dir=/home/berrange/security/qemutls
To test with the gnutls-cli tool as the client:
$ gnutls-cli --priority=NORMAL -p 9000 \
--x509cafile=/home/berrange/security/qemutls/ca-cert.pem \
127.0.0.1
If QEMU was told to use 'anon' credential type, then use the
priority string 'NORMAL:+ANON-DH' with gnutls-cli
Alternatively, if setting up a chardev to operate as a client,
then the TLS credentials registered must be for the client
endpoint. First a TLS server must be setup, which can be done
with the gnutls-serv tool
$ gnutls-serv --priority=NORMAL -p 9000 --echo \
--x509cafile=/home/berrange/security/qemutls/ca-cert.pem \
--x509certfile=/home/berrange/security/qemutls/server-cert.pem \
--x509keyfile=/home/berrange/security/qemutls/server-key.pem
Then QEMU can connect with
$ qemu-system-x86_64 \
-nodefconfig -nodefaults -device sga -display none \
-chardev socket,id=s0,host=127.0.0.1,port=9000,tls-creds=tls0 \
-device isa-serial,chardev=s0 \
-object tls-creds-x509,id=tls0,endpoint=client,\
dir=/home/berrange/security/qemutls
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1453202071-10289-5-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-19 12:14:31 +01:00
|
|
|
#include "io/channel-tls.h"
|
2016-03-14 08:44:36 +01:00
|
|
|
#include "sysemu/replay.h"
|
2016-08-16 19:13:52 +02:00
|
|
|
#include "qemu/help_option.h"
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
#include <zlib.h>
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <sys/times.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <termios.h>
|
|
|
|
#include <sys/ioctl.h>
|
2008-11-07 17:55:48 +01:00
|
|
|
#include <sys/resource.h>
|
2008-10-31 19:49:55 +01:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
2008-11-07 17:55:48 +01:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <arpa/inet.h>
|
2008-10-31 19:49:55 +01:00
|
|
|
#include <netdb.h>
|
|
|
|
#include <sys/select.h>
|
2009-07-27 16:12:56 +02:00
|
|
|
#ifdef CONFIG_BSD
|
do not include <libutil.h> needlessly or if it doesn't exist
<libutil.h> and <util.h> on *BSD (some have one, some another)
were #included just for openpty() declaration. The only file
where this function is actually used is qemu-char.c.
In vl.c and net/tap-bsd.c, none of functions declared in libutil.h
(login logout logwtmp timdomain openpty forkpty uu_lock realhostname
fparseln and a few others depending on version) are used.
Initially the code which is currently in qemu-char.c was in vl.c,
it has been removed into separate file in commit 0e82f34d077dc2542
Fri Oct 31 18:44:40 2008, but the #includes were left in vl.c.
So with vl.c, we just remove includes - libutil.h, util.h and
pty.h (which declares only openpty() and forkpty()) from there.
The code in net/tap-bsd.c, which come from net/tap.c, had this
commit 5281d757efa6e40d74ce124be048b08d43887555
Author: Mark McLoughlin <markmc@redhat.com>
Date: Thu Oct 22 17:49:07 2009 +0100
net: split all the tap code out into net/tap.c
Note this commit not only moved stuff out of net.c to net/tap.c,
but also rewrote large portions of the tap code, and added these
completely unnecessary #includes -- as usual, I question why such
a misleading commit messages are allowed.
Again, no functions defined in libutil.h or util.h on *BSD are
used by neither net/tap.c nor net/tap-bsd.c. Removing them.
And finally, the only real user for these #includes, qemu-char.c,
which actually uses openpty(). There, the #ifdef logic is wrong.
A GLIBC-based system has <pty.h>, even if it is a variant of *BSD.
So __GLIBC__ should be checked first, and instead of trying to
include <libutil.h> or <util.h>, we include <pty.h>. If it is not
GLIBC-based, we check for variations between <*util.h> as before.
This patch fixes build of qemu 1.1 on Debian/kFreebsd (well, one
of the two problems): it is a distribution with a FreeBSD kernel,
so it #defines at least __FreeBSD_kernel__, but since it is based
on GLIBC, it has <pty.h>, but current version does not have neither
<util.h> nor <libutil.h>, which the code tries to include 3 times
but uses only once.
Signed-off-By: Michael Tokarev <mjt@tls.msk.ru>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2012-06-02 21:43:33 +02:00
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
|
|
#include <dev/ppbus/ppi.h>
|
|
|
|
#include <dev/ppbus/ppbconf.h>
|
2009-03-07 21:06:23 +01:00
|
|
|
#elif defined(__DragonFly__)
|
|
|
|
#include <dev/misc/ppi/ppi.h>
|
|
|
|
#include <bus/ppbus/ppbconf.h>
|
2008-10-31 19:49:55 +01:00
|
|
|
#endif
|
2009-11-30 15:42:59 +01:00
|
|
|
#else
|
2008-10-31 19:49:55 +01:00
|
|
|
#ifdef __linux__
|
|
|
|
#include <linux/ppdev.h>
|
|
|
|
#include <linux/parport.h>
|
|
|
|
#endif
|
|
|
|
#ifdef __sun__
|
|
|
|
#include <sys/ethernet.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <netinet/arp.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip_icmp.h> // must come after ip.h
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/sockets.h"
|
2011-01-19 09:49:50 +01:00
|
|
|
#include "ui/qemu-spice.h"
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2016-12-12 13:06:14 +01:00
|
|
|
#include "char-mux.h"
|
2016-12-12 15:08:59 +01:00
|
|
|
#include "char-fd.h"
|
2016-12-12 15:07:52 +01:00
|
|
|
#include "char-io.h"
|
2016-12-12 15:38:21 +01:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include "char-win.h"
|
|
|
|
#endif
|
2016-12-12 13:06:14 +01:00
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
/***********************************************************/
|
|
|
|
/* character device */
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
|
2009-09-12 09:36:22 +02:00
|
|
|
QTAILQ_HEAD_INITIALIZER(chardevs);
|
2009-03-05 23:59:58 +01:00
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
void qemu_chr_be_event(Chardev *s, int event)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-10-22 11:53:01 +02:00
|
|
|
CharBackend *be = s->be;
|
|
|
|
|
2010-04-01 18:42:39 +02:00
|
|
|
/* Keep track if the char device is open */
|
|
|
|
switch (event) {
|
|
|
|
case CHR_EVENT_OPENED:
|
2013-03-26 11:07:53 +01:00
|
|
|
s->be_open = 1;
|
2010-04-01 18:42:39 +02:00
|
|
|
break;
|
|
|
|
case CHR_EVENT_CLOSED:
|
2013-03-26 11:07:53 +01:00
|
|
|
s->be_open = 0;
|
2010-04-01 18:42:39 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:53:01 +02:00
|
|
|
if (!be || !be->chr_event) {
|
2008-10-31 19:49:55 +01:00
|
|
|
return;
|
2016-10-22 11:53:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
be->chr_event(be->opaque, event);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
void qemu_chr_be_generic_open(Chardev *s)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
qemu-char: don't issue CHR_EVENT_OPEN in a BH
When CHR_EVENT_OPENED was initially added, it was CHR_EVENT_RESET,
and it was issued as a bottom-half:
86e94dea5b740dad65446c857f6959eae43e0ba6
Which we basically used to print out a greeting/prompt for the
monitor.
AFAICT the only reason this was ever done in a BH was because in
some cases we'd modify the chr_write handler for a new chardev
backend *after* the site where we issued the reset (see:
86e94d:qemu_chr_open_stdio())
At some point this event was renamed to CHR_EVENT_OPENED, and we've
maintained the use of this BH ever since.
However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
the BH via g_idle_add(), which is causing events to sometimes be
delivered after we've already begun processing data from backends,
leading to:
known bugs:
QMP:
session negotation resets with OPENED event, in some cases this
is causing new sessions to get sporadically reset
potential bugs:
hw/usb/redirect.c:
can_read handler checks for dev->parser != NULL, which may be
true if CLOSED BH has not been executed yet. In the past, OPENED
quiesced outstanding CLOSED events prior to us reading client
data. If it's delayed, our check may allow reads to occur even
though we haven't processed the OPENED event yet, and when we
do finally get the OPENED event, our state may get reset.
qtest.c:
can begin session before OPENED event is processed, leading to
a spurious reset of the system and irq_levels
gdbstub.c:
may start a gdb session prior to the machine being paused
To fix these, let's just drop the BH.
Since the initial reasoning for using it still applies to an extent,
work around that by deferring the delivery of CHR_EVENT_OPENED until
after the chardevs have been fully initialized, toward the end of
qmp_chardev_add() (or some cases, qemu_chr_new_from_opts()). This
defers delivery long enough that we can be assured a CharDriverState
is fully initialized before CHR_EVENT_OPENED is sent.
Also, rather than requiring each chardev to do an explicit open, do it
automatically, and allow the small few who don't desire such behavior to
suppress the OPENED-on-init behavior by setting a 'explicit_be_open'
flag.
We additionally add missing OPENED events for stdio backends on w32,
which were previously not being issued, causing us to not recieve the
banner and initial prompts for qmp/hmp.
Reported-by: Stefan Priebe <s.priebe@profihost.ag>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Message-id: 1370636393-21044-1-git-send-email-mdroth@linux.vnet.ibm.com
Cc: qemu-stable@nongnu.org
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-06-07 22:19:53 +02:00
|
|
|
qemu_chr_be_event(s, CHR_EVENT_OPENED);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
|
|
|
|
/* Not reporting errors from writing to logfile, as logs are
|
|
|
|
* defined to be "best effort" only */
|
2016-12-07 14:20:22 +01:00
|
|
|
static void qemu_chr_fe_write_log(Chardev *s,
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
const uint8_t *buf, size_t len)
|
|
|
|
{
|
|
|
|
size_t done = 0;
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (s->logfd < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (done < len) {
|
2016-03-31 17:29:27 +02:00
|
|
|
retry:
|
|
|
|
ret = write(s->logfd, buf + done, len - done);
|
|
|
|
if (ret == -1 && errno == EAGAIN) {
|
|
|
|
g_usleep(100);
|
|
|
|
goto retry;
|
|
|
|
}
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
|
|
|
|
if (ret <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
done += ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static int qemu_chr_fe_write_buffer(Chardev *s,
|
|
|
|
const uint8_t *buf, int len, int *offset)
|
2016-03-14 08:44:36 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
ChardevClass *cc = CHARDEV_GET_CLASS(s);
|
2016-03-14 08:44:36 +01:00
|
|
|
int res = 0;
|
|
|
|
*offset = 0;
|
|
|
|
|
|
|
|
qemu_mutex_lock(&s->chr_write_lock);
|
|
|
|
while (*offset < len) {
|
2016-03-31 17:29:27 +02:00
|
|
|
retry:
|
2016-12-07 16:39:10 +01:00
|
|
|
res = cc->chr_write(s, buf + *offset, len - *offset);
|
2016-03-31 17:29:27 +02:00
|
|
|
if (res < 0 && errno == EAGAIN) {
|
|
|
|
g_usleep(100);
|
|
|
|
goto retry;
|
|
|
|
}
|
2016-03-14 08:44:36 +01:00
|
|
|
|
|
|
|
if (res <= 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*offset += res;
|
|
|
|
}
|
|
|
|
if (*offset > 0) {
|
|
|
|
qemu_chr_fe_write_log(s, buf, *offset);
|
|
|
|
}
|
|
|
|
qemu_mutex_unlock(&s->chr_write_lock);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static bool qemu_chr_replay(Chardev *chr)
|
2016-10-21 21:58:45 +02:00
|
|
|
{
|
|
|
|
return qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2016-12-07 16:39:10 +01:00
|
|
|
ChardevClass *cc;
|
2014-06-18 08:43:58 +02:00
|
|
|
int ret;
|
|
|
|
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!s) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
|
2016-03-14 08:44:36 +01:00
|
|
|
int offset;
|
|
|
|
replay_char_write_event_load(&ret, &offset);
|
|
|
|
assert(offset <= len);
|
|
|
|
qemu_chr_fe_write_buffer(s, buf, offset, &offset);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
cc = CHARDEV_GET_CLASS(s);
|
2014-06-18 08:43:58 +02:00
|
|
|
qemu_mutex_lock(&s->chr_write_lock);
|
2016-12-07 16:39:10 +01:00
|
|
|
ret = cc->chr_write(s, buf, len);
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
|
|
|
|
if (ret > 0) {
|
|
|
|
qemu_chr_fe_write_log(s, buf, ret);
|
|
|
|
}
|
|
|
|
|
2014-06-18 08:43:58 +02:00
|
|
|
qemu_mutex_unlock(&s->chr_write_lock);
|
2016-03-14 08:44:36 +01:00
|
|
|
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
|
2016-03-14 08:44:36 +01:00
|
|
|
replay_char_write_event_save(ret, ret < 0 ? 0 : ret);
|
|
|
|
}
|
|
|
|
|
2014-06-18 08:43:58 +02:00
|
|
|
return ret;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-12 13:06:14 +01:00
|
|
|
int qemu_chr_write_all(Chardev *s, const uint8_t *buf, int len)
|
2013-03-26 16:04:17 +01:00
|
|
|
{
|
2016-03-14 08:44:36 +01:00
|
|
|
int offset;
|
|
|
|
int res;
|
2013-03-26 16:04:17 +01:00
|
|
|
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
|
2016-03-14 08:44:36 +01:00
|
|
|
replay_char_write_event_load(&res, &offset);
|
|
|
|
assert(offset <= len);
|
|
|
|
qemu_chr_fe_write_buffer(s, buf, offset, &offset);
|
|
|
|
return res;
|
|
|
|
}
|
2013-03-26 16:04:17 +01:00
|
|
|
|
2016-03-14 08:44:36 +01:00
|
|
|
res = qemu_chr_fe_write_buffer(s, buf, len, &offset);
|
2013-03-26 16:04:17 +01:00
|
|
|
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
|
2016-03-14 08:44:36 +01:00
|
|
|
replay_char_write_event_save(res, offset);
|
2013-03-26 16:04:17 +01:00
|
|
|
}
|
|
|
|
|
2014-06-18 08:43:58 +02:00
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
2013-03-26 16:04:17 +01:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
|
2014-05-27 14:03:48 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2016-10-22 11:52:55 +02:00
|
|
|
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!s) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
return qemu_chr_write_all(s, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
|
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2014-05-27 14:03:48 +02:00
|
|
|
int offset = 0, counter = 10;
|
|
|
|
int res;
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
|
2014-05-27 14:03:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2016-10-22 11:52:59 +02:00
|
|
|
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
|
2016-03-14 08:44:36 +01:00
|
|
|
return replay_char_read_all_load(buf);
|
|
|
|
}
|
2014-05-27 14:03:48 +02:00
|
|
|
|
|
|
|
while (offset < len) {
|
2016-03-31 17:29:27 +02:00
|
|
|
retry:
|
2016-12-07 16:39:10 +01:00
|
|
|
res = CHARDEV_GET_CLASS(s)->chr_sync_read(s, buf + offset,
|
|
|
|
len - offset);
|
2016-03-31 17:29:27 +02:00
|
|
|
if (res == -1 && errno == EAGAIN) {
|
|
|
|
g_usleep(100);
|
|
|
|
goto retry;
|
|
|
|
}
|
2014-05-27 14:03:48 +02:00
|
|
|
|
|
|
|
if (res == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res < 0) {
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
|
2016-03-14 08:44:36 +01:00
|
|
|
replay_char_read_all_save_error(res);
|
|
|
|
}
|
2014-05-27 14:03:48 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset += res;
|
|
|
|
|
|
|
|
if (!counter--) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
|
2016-03-14 08:44:36 +01:00
|
|
|
replay_char_read_all_save_buf(buf, offset);
|
|
|
|
}
|
2014-05-27 14:03:48 +02:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2016-03-14 08:44:36 +01:00
|
|
|
int res;
|
2016-10-22 11:52:59 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (!s || !CHARDEV_GET_CLASS(s)->chr_ioctl || qemu_chr_replay(s)) {
|
2016-03-14 08:44:36 +01:00
|
|
|
res = -ENOTSUP;
|
|
|
|
} else {
|
2016-12-07 16:39:10 +01:00
|
|
|
res = CHARDEV_GET_CLASS(s)->chr_ioctl(s, cmd, arg);
|
2016-03-14 08:44:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
int qemu_chr_be_can_write(Chardev *s)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-10-22 11:53:01 +02:00
|
|
|
CharBackend *be = s->be;
|
|
|
|
|
|
|
|
if (!be || !be->chr_can_read) {
|
2008-10-31 19:49:55 +01:00
|
|
|
return 0;
|
2016-10-22 11:53:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return be->chr_can_read(be->opaque);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-10-22 11:53:01 +02:00
|
|
|
CharBackend *be = s->be;
|
|
|
|
|
|
|
|
if (be && be->chr_read) {
|
|
|
|
be->chr_read(be->opaque, buf, len);
|
2012-04-19 22:27:14 +02:00
|
|
|
}
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
|
2016-03-14 08:44:36 +01:00
|
|
|
{
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(s)) {
|
2016-03-14 08:44:36 +01:00
|
|
|
if (replay_mode == REPLAY_MODE_PLAY) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
replay_chr_be_write(s, buf, len);
|
|
|
|
} else {
|
|
|
|
qemu_chr_be_write_impl(s, buf, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
int qemu_chr_fe_get_msgfd(CharBackend *be)
|
2009-07-22 10:11:39 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2014-05-27 14:04:15 +02:00
|
|
|
int fd;
|
2016-10-22 11:52:55 +02:00
|
|
|
int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
|
2016-10-21 21:58:45 +02:00
|
|
|
if (s && qemu_chr_replay(s)) {
|
2016-11-30 19:57:24 +01:00
|
|
|
error_report("Replay: get msgfd is not supported "
|
|
|
|
"for serial devices yet");
|
2016-03-14 08:44:36 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return res;
|
2014-05-27 14:04:15 +02:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
|
2014-05-27 14:04:15 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2016-10-22 11:52:55 +02:00
|
|
|
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!s) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
return CHARDEV_GET_CLASS(s)->get_msgfds ?
|
|
|
|
CHARDEV_GET_CLASS(s)->get_msgfds(s, fds, len) : -1;
|
2009-07-22 10:11:39 +02:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
|
2014-05-27 14:04:02 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2016-10-22 11:52:55 +02:00
|
|
|
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!s) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
return CHARDEV_GET_CLASS(s)->set_msgfds ?
|
|
|
|
CHARDEV_GET_CLASS(s)->set_msgfds(s, fds, num) : -1;
|
2014-05-27 14:04:02 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
int qemu_chr_add_client(Chardev *s, int fd)
|
Introduce a 'client_add' monitor command accepting an open FD
Allow client connections for VNC and socket based character
devices to be passed in over the monitor using SCM_RIGHTS.
One intended usage scenario is to start QEMU with VNC on a
UNIX domain socket. An unprivileged user which cannot access
the UNIX domain socket, can then connect to QEMU's VNC server
by passing an open FD to libvirt, which passes it onto QEMU.
{ "execute": "get_fd", "arguments": { "fdname": "myclient" } }
{ "return": {} }
{ "execute": "add_client", "arguments": { "protocol": "vnc",
"fdname": "myclient",
"skipauth": true } }
{ "return": {} }
In this case 'protocol' can be 'vnc' or 'spice', or the name
of a character device (eg from -chardev id=XXXX)
The 'skipauth' parameter can be used to skip any configured
VNC authentication scheme, which is useful if the mgmt layer
talking to the monitor has already authenticated the client
in another way.
* console.h: Define 'vnc_display_add_client' method
* monitor.c: Implement 'client_add' command
* qemu-char.c, qemu-char.h: Add 'qemu_char_add_client' method
* qerror.c, qerror.h: Add QERR_ADD_CLIENT_FAILED
* qmp-commands.hx: Declare 'client_add' command
* ui/vnc.c: Implement 'vnc_display_add_client' method
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-06-23 14:31:42 +02:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
return CHARDEV_GET_CLASS(s)->chr_add_client ?
|
|
|
|
CHARDEV_GET_CLASS(s)->chr_add_client(s, fd) : -1;
|
Introduce a 'client_add' monitor command accepting an open FD
Allow client connections for VNC and socket based character
devices to be passed in over the monitor using SCM_RIGHTS.
One intended usage scenario is to start QEMU with VNC on a
UNIX domain socket. An unprivileged user which cannot access
the UNIX domain socket, can then connect to QEMU's VNC server
by passing an open FD to libvirt, which passes it onto QEMU.
{ "execute": "get_fd", "arguments": { "fdname": "myclient" } }
{ "return": {} }
{ "execute": "add_client", "arguments": { "protocol": "vnc",
"fdname": "myclient",
"skipauth": true } }
{ "return": {} }
In this case 'protocol' can be 'vnc' or 'spice', or the name
of a character device (eg from -chardev id=XXXX)
The 'skipauth' parameter can be used to skip any configured
VNC authentication scheme, which is useful if the mgmt layer
talking to the monitor has already authenticated the client
in another way.
* console.h: Define 'vnc_display_add_client' method
* monitor.c: Implement 'client_add' command
* qemu-char.c, qemu-char.h: Add 'qemu_char_add_client' method
* qerror.c, qerror.h: Add QERR_ADD_CLIENT_FAILED
* qmp-commands.hx: Declare 'client_add' command
* ui/vnc.c: Implement 'vnc_display_add_client' method
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-06-23 14:31:42 +02:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
void qemu_chr_fe_accept_input(CharBackend *be)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2016-10-22 11:52:55 +02:00
|
|
|
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!s) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_GET_CLASS(s)->chr_accept_input) {
|
|
|
|
CHARDEV_GET_CLASS(s)->chr_accept_input(s);
|
2016-10-21 19:49:37 +02:00
|
|
|
}
|
2012-03-16 13:18:00 +01:00
|
|
|
qemu_notify_event();
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-12 14:39:35 +01:00
|
|
|
char buf[CHR_READ_BUF_LEN];
|
2008-10-31 19:49:55 +01:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
2016-09-06 15:56:05 +02:00
|
|
|
/* XXX this blocks entire thread. Rewrite to use
|
|
|
|
* qemu_chr_fe_write and background I/O callbacks */
|
2016-10-22 11:52:55 +02:00
|
|
|
qemu_chr_fe_write_all(be, (uint8_t *)buf, strlen(buf));
|
2008-10-31 19:49:55 +01:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
|
|
|
|
bool *be_opened, Error **errp)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
ChardevClass *cc = CHARDEV_GET_CLASS(chr);
|
|
|
|
/* Any ChardevCommon member would work */
|
|
|
|
ChardevCommon *common = backend ? backend->u.null.data : NULL;
|
|
|
|
|
|
|
|
if (common && common->has_logfile) {
|
|
|
|
int flags = O_WRONLY | O_CREAT;
|
|
|
|
if (common->has_logappend &&
|
|
|
|
common->logappend) {
|
|
|
|
flags |= O_APPEND;
|
|
|
|
} else {
|
|
|
|
flags |= O_TRUNC;
|
|
|
|
}
|
|
|
|
chr->logfd = qemu_open(common->logfile, flags, 0666);
|
|
|
|
if (chr->logfd < 0) {
|
|
|
|
error_setg_errno(errp, errno,
|
|
|
|
"Unable to open logfile %s",
|
|
|
|
common->logfile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cc->open) {
|
|
|
|
cc->open(chr, backend, be_opened, errp);
|
|
|
|
}
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void char_init(Object *obj)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
Chardev *chr = CHARDEV(obj);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
chr->logfd = -1;
|
|
|
|
qemu_mutex_init(&chr->chr_write_lock);
|
|
|
|
}
|
|
|
|
|
2016-12-12 11:41:40 +01:00
|
|
|
static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
|
|
|
{
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void char_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
|
|
|
|
|
|
|
cc->chr_write = null_chr_write;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void char_finalize(Object *obj)
|
|
|
|
{
|
|
|
|
Chardev *chr = CHARDEV(obj);
|
|
|
|
|
|
|
|
if (chr->be) {
|
|
|
|
chr->be->chr = NULL;
|
|
|
|
}
|
|
|
|
g_free(chr->filename);
|
|
|
|
g_free(chr->label);
|
|
|
|
if (chr->logfd != -1) {
|
|
|
|
close(chr->logfd);
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
}
|
2016-12-07 16:39:10 +01:00
|
|
|
qemu_mutex_destroy(&chr->chr_write_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo char_type_info = {
|
|
|
|
.name = TYPE_CHARDEV,
|
|
|
|
.parent = TYPE_OBJECT,
|
|
|
|
.instance_size = sizeof(Chardev),
|
|
|
|
.instance_init = char_init,
|
|
|
|
.instance_finalize = char_finalize,
|
|
|
|
.abstract = true,
|
|
|
|
.class_size = sizeof(ChardevClass),
|
2016-12-12 11:41:40 +01:00
|
|
|
.class_init = char_class_init,
|
2016-12-07 16:39:10 +01:00
|
|
|
};
|
|
|
|
|
chardev: fix CHR_EVENT_OPENED events for mux chardevs
As of bd5c51ee6c4f1c79cae5ad2516d711a27b4ea8ec, chardevs no longer use
bottom-halves to issue CHR_EVENT_OPENED events. To maintain past
semantics, we instead defer the CHR_EVENT_OPENED events toward the end
of chardev initialization.
For muxes, this isn't good enough, since a range of FEs must be able
to attach to the mux prior to any CHR_EVENT_OPENED being issued, else
each FE will immediately print it's initial output (prompts, banners,
etc.) just prior to us switching to the next FE as part of
initialization.
The is new and confusing behavior for users, as they'll see output for
things like the HMP monitor, even though their the current mux focus
may be a guest serial port with potentially no output.
We fix this by further deferring CHR_EVENT_OPENED events for FEs
associated with muxes until after machine init by flagging mux chardevs
with 'explicit_be_open', which suppresses emission of CHR_EVENT_OPENED
events until we explicitly set the mux as opened later.
Currently, we must defer till after machine init since we potentially
associate FEs with muxes as part of realize (for instance,
serial_isa_realizefn).
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Message-id: 1375207462-8141-1-git-send-email-mdroth@linux.vnet.ibm.com
Cc: qemu-stable@nongnu.org
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-07-30 20:04:22 +02:00
|
|
|
/**
|
|
|
|
* Called after processing of default and command-line-specified
|
|
|
|
* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
|
|
|
|
* to a mux chardev. This is done here to ensure that
|
|
|
|
* output/prompts/banners are only displayed for the FE that has
|
|
|
|
* focus when initial command-line processing/machine init is
|
|
|
|
* completed.
|
|
|
|
*
|
|
|
|
* After this point, any new FE attached to any new or existing
|
|
|
|
* mux will receive CHR_EVENT_OPENED notifications for the BE
|
|
|
|
* immediately.
|
|
|
|
*/
|
|
|
|
static void muxes_realize_done(Notifier *notifier, void *unused)
|
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr;
|
chardev: fix CHR_EVENT_OPENED events for mux chardevs
As of bd5c51ee6c4f1c79cae5ad2516d711a27b4ea8ec, chardevs no longer use
bottom-halves to issue CHR_EVENT_OPENED events. To maintain past
semantics, we instead defer the CHR_EVENT_OPENED events toward the end
of chardev initialization.
For muxes, this isn't good enough, since a range of FEs must be able
to attach to the mux prior to any CHR_EVENT_OPENED being issued, else
each FE will immediately print it's initial output (prompts, banners,
etc.) just prior to us switching to the next FE as part of
initialization.
The is new and confusing behavior for users, as they'll see output for
things like the HMP monitor, even though their the current mux focus
may be a guest serial port with potentially no output.
We fix this by further deferring CHR_EVENT_OPENED events for FEs
associated with muxes until after machine init by flagging mux chardevs
with 'explicit_be_open', which suppresses emission of CHR_EVENT_OPENED
events until we explicitly set the mux as opened later.
Currently, we must defer till after machine init since we potentially
associate FEs with muxes as part of realize (for instance,
serial_isa_realizefn).
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Message-id: 1375207462-8141-1-git-send-email-mdroth@linux.vnet.ibm.com
Cc: qemu-stable@nongnu.org
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-07-30 20:04:22 +02:00
|
|
|
|
|
|
|
QTAILQ_FOREACH(chr, &chardevs, next) {
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_IS_MUX(chr)) {
|
|
|
|
MuxChardev *d = MUX_CHARDEV(chr);
|
chardev: fix CHR_EVENT_OPENED events for mux chardevs
As of bd5c51ee6c4f1c79cae5ad2516d711a27b4ea8ec, chardevs no longer use
bottom-halves to issue CHR_EVENT_OPENED events. To maintain past
semantics, we instead defer the CHR_EVENT_OPENED events toward the end
of chardev initialization.
For muxes, this isn't good enough, since a range of FEs must be able
to attach to the mux prior to any CHR_EVENT_OPENED being issued, else
each FE will immediately print it's initial output (prompts, banners,
etc.) just prior to us switching to the next FE as part of
initialization.
The is new and confusing behavior for users, as they'll see output for
things like the HMP monitor, even though their the current mux focus
may be a guest serial port with potentially no output.
We fix this by further deferring CHR_EVENT_OPENED events for FEs
associated with muxes until after machine init by flagging mux chardevs
with 'explicit_be_open', which suppresses emission of CHR_EVENT_OPENED
events until we explicitly set the mux as opened later.
Currently, we must defer till after machine init since we potentially
associate FEs with muxes as part of realize (for instance,
serial_isa_realizefn).
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Message-id: 1375207462-8141-1-git-send-email-mdroth@linux.vnet.ibm.com
Cc: qemu-stable@nongnu.org
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-07-30 20:04:22 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* send OPENED to all already-attached FEs */
|
|
|
|
for (i = 0; i < d->mux_cnt; i++) {
|
|
|
|
mux_chr_send_event(d, i, CHR_EVENT_OPENED);
|
|
|
|
}
|
|
|
|
/* mark mux as OPENED so any new FEs will immediately receive
|
|
|
|
* OPENED event
|
|
|
|
*/
|
|
|
|
qemu_chr_be_generic_open(chr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
muxes_realized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Notifier muxes_realize_notify = {
|
|
|
|
.notify = muxes_realize_done,
|
|
|
|
};
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *qemu_chr_fe_get_driver(CharBackend *be)
|
2016-10-22 11:52:49 +02:00
|
|
|
{
|
|
|
|
return be->chr;
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
|
2016-10-22 11:52:49 +02:00
|
|
|
{
|
|
|
|
int tag = 0;
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_IS_MUX(s)) {
|
|
|
|
MuxChardev *d = MUX_CHARDEV(s);
|
2016-10-22 12:09:41 +02:00
|
|
|
|
|
|
|
if (d->mux_cnt >= MAX_MUX) {
|
|
|
|
goto unavailable;
|
2016-10-22 11:52:49 +02:00
|
|
|
}
|
2016-10-22 12:09:41 +02:00
|
|
|
|
|
|
|
d->backends[d->mux_cnt] = b;
|
|
|
|
tag = d->mux_cnt++;
|
|
|
|
} else if (s->be) {
|
|
|
|
goto unavailable;
|
2016-10-22 11:53:01 +02:00
|
|
|
} else {
|
|
|
|
s->be = b;
|
2016-10-22 11:52:49 +02:00
|
|
|
}
|
|
|
|
|
2016-10-22 12:09:37 +02:00
|
|
|
b->fe_open = false;
|
2016-10-22 11:52:49 +02:00
|
|
|
b->tag = tag;
|
|
|
|
b->chr = s;
|
|
|
|
return true;
|
2016-10-22 12:09:41 +02:00
|
|
|
|
|
|
|
unavailable:
|
|
|
|
error_setg(errp, QERR_DEVICE_IN_USE, s->label);
|
|
|
|
return false;
|
2016-10-22 11:52:49 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static bool qemu_chr_is_busy(Chardev *s)
|
2016-10-22 11:53:01 +02:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_IS_MUX(s)) {
|
|
|
|
MuxChardev *d = MUX_CHARDEV(s);
|
2016-10-22 11:53:01 +02:00
|
|
|
return d->mux_cnt >= 0;
|
|
|
|
} else {
|
|
|
|
return s->be != NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:58 +02:00
|
|
|
void qemu_chr_fe_deinit(CharBackend *b)
|
|
|
|
{
|
|
|
|
assert(b);
|
|
|
|
|
|
|
|
if (b->chr) {
|
2016-10-22 11:53:03 +02:00
|
|
|
qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
|
2017-01-10 12:06:21 +01:00
|
|
|
if (b->chr->be == b) {
|
|
|
|
b->chr->be = NULL;
|
|
|
|
}
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_IS_MUX(b->chr)) {
|
|
|
|
MuxChardev *d = MUX_CHARDEV(b->chr);
|
2016-10-22 11:53:01 +02:00
|
|
|
d->backends[b->tag] = NULL;
|
|
|
|
}
|
2016-10-22 11:52:58 +02:00
|
|
|
b->chr = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:49 +02:00
|
|
|
void qemu_chr_fe_set_handlers(CharBackend *b,
|
|
|
|
IOCanReadHandler *fd_can_read,
|
|
|
|
IOReadHandler *fd_read,
|
|
|
|
IOEventHandler *fd_event,
|
|
|
|
void *opaque,
|
2016-10-22 11:53:03 +02:00
|
|
|
GMainContext *context,
|
|
|
|
bool set_open)
|
2016-10-22 11:52:49 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s;
|
2016-12-07 16:39:10 +01:00
|
|
|
ChardevClass *cc;
|
2016-10-22 11:52:56 +02:00
|
|
|
int fe_open;
|
|
|
|
|
|
|
|
s = b->chr;
|
|
|
|
if (!s) {
|
2016-10-22 11:52:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
cc = CHARDEV_GET_CLASS(s);
|
2016-10-22 11:52:56 +02:00
|
|
|
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
|
|
|
|
fe_open = 0;
|
|
|
|
remove_fd_in_watch(s);
|
|
|
|
} else {
|
|
|
|
fe_open = 1;
|
|
|
|
}
|
2016-10-22 11:53:01 +02:00
|
|
|
b->chr_can_read = fd_can_read;
|
|
|
|
b->chr_read = fd_read;
|
|
|
|
b->chr_event = fd_event;
|
|
|
|
b->opaque = opaque;
|
2016-12-07 16:39:10 +01:00
|
|
|
if (cc->chr_update_read_handler) {
|
|
|
|
cc->chr_update_read_handler(s, context);
|
2016-10-22 11:52:56 +02:00
|
|
|
}
|
|
|
|
|
2016-10-22 11:53:03 +02:00
|
|
|
if (set_open) {
|
2016-10-22 11:52:56 +02:00
|
|
|
qemu_chr_fe_set_open(b, fe_open);
|
|
|
|
}
|
2016-10-22 11:52:49 +02:00
|
|
|
|
2016-10-22 11:52:56 +02:00
|
|
|
if (fe_open) {
|
|
|
|
qemu_chr_fe_take_focus(b);
|
|
|
|
/* We're connecting to an already opened device, so let's make sure we
|
|
|
|
also get the open event */
|
|
|
|
if (s->be_open) {
|
|
|
|
qemu_chr_be_generic_open(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_IS_MUX(s)) {
|
2016-10-22 11:52:56 +02:00
|
|
|
mux_chr_set_handlers(s, context);
|
2016-10-22 11:52:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_chr_fe_take_focus(CharBackend *b)
|
|
|
|
{
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!b->chr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_IS_MUX(b->chr)) {
|
2017-01-10 12:06:21 +01:00
|
|
|
mux_set_focus(b->chr, b->tag);
|
2016-10-22 11:52:49 +02:00
|
|
|
}
|
|
|
|
}
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2016-01-19 12:14:28 +01:00
|
|
|
#ifndef _WIN32
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qemu_chr_open_pipe(Chardev *chr,
|
|
|
|
ChardevBackend *backend,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
ChardevHostdev *opts = backend->u.pipe.data;
|
2008-10-31 19:49:55 +01:00
|
|
|
int fd_in, fd_out;
|
2016-01-19 12:14:28 +01:00
|
|
|
char *filename_in;
|
|
|
|
char *filename_out;
|
2013-02-25 11:50:55 +01:00
|
|
|
const char *filename = opts->device;
|
2016-01-19 12:14:28 +01:00
|
|
|
|
|
|
|
filename_in = g_strdup_printf("%s.in", filename);
|
|
|
|
filename_out = g_strdup_printf("%s.out", filename);
|
2009-12-02 12:24:42 +01:00
|
|
|
TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
|
|
|
|
TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY));
|
2016-01-19 12:14:28 +01:00
|
|
|
g_free(filename_in);
|
|
|
|
g_free(filename_out);
|
2008-10-31 19:49:55 +01:00
|
|
|
if (fd_in < 0 || fd_out < 0) {
|
|
|
|
if (fd_in >= 0)
|
|
|
|
close(fd_in);
|
|
|
|
if (fd_out >= 0)
|
|
|
|
close(fd_out);
|
2012-02-07 15:09:09 +01:00
|
|
|
TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY));
|
2012-02-07 15:09:10 +01:00
|
|
|
if (fd_in < 0) {
|
2015-09-29 15:14:07 +02:00
|
|
|
error_setg_file_open(errp, errno, filename);
|
2016-12-07 16:39:10 +01:00
|
|
|
return;
|
2012-02-07 15:09:10 +01:00
|
|
|
}
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
2016-12-07 16:39:10 +01:00
|
|
|
qemu_chr_open_fd(chr, fd_in, fd_out);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|
2009-11-29 18:00:41 +01:00
|
|
|
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
|
|
|
|
|| defined(__GLIBC__)
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2015-10-12 09:46:23 +02:00
|
|
|
#define HAVE_CHARDEV_SERIAL 1
|
|
|
|
#define HAVE_CHARDEV_PTY 1
|
2012-12-19 16:35:42 +01:00
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
typedef struct {
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev parent;
|
2016-01-19 12:14:29 +01:00
|
|
|
QIOChannel *ioc;
|
2008-10-31 19:49:55 +01:00
|
|
|
int read_bytes;
|
2014-06-18 08:43:58 +02:00
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
/* Protected by the Chardev chr_write_lock. */
|
2014-06-18 08:43:58 +02:00
|
|
|
int connected;
|
2013-03-05 18:51:26 +01:00
|
|
|
guint timer_tag;
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
guint open_tag;
|
2016-12-07 14:20:22 +01:00
|
|
|
} PtyChardev;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
#define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY)
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static void pty_chr_update_read_handler_locked(Chardev *chr);
|
|
|
|
static void pty_chr_state(Chardev *chr, int connected);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2013-03-05 18:51:26 +01:00
|
|
|
static gboolean pty_chr_timer(gpointer opaque)
|
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
struct Chardev *chr = CHARDEV(opaque);
|
|
|
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
2013-03-05 18:51:26 +01:00
|
|
|
|
2014-06-18 08:43:58 +02:00
|
|
|
qemu_mutex_lock(&chr->chr_write_lock);
|
2013-04-25 13:53:02 +02:00
|
|
|
s->timer_tag = 0;
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
s->open_tag = 0;
|
2013-08-22 11:43:58 +02:00
|
|
|
if (!s->connected) {
|
|
|
|
/* Next poll ... */
|
2014-06-18 08:43:58 +02:00
|
|
|
pty_chr_update_read_handler_locked(chr);
|
2013-08-22 11:43:58 +02:00
|
|
|
}
|
2014-06-18 08:43:58 +02:00
|
|
|
qemu_mutex_unlock(&chr->chr_write_lock);
|
2013-03-05 18:51:26 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2014-06-18 08:43:58 +02:00
|
|
|
/* Called with chr_write_lock held. */
|
2016-12-07 14:20:22 +01:00
|
|
|
static void pty_chr_rearm_timer(Chardev *chr, int ms)
|
2013-03-05 18:51:26 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
PtyChardev *s = PTY_CHARDEV(chr);
|
2016-09-30 12:57:14 +02:00
|
|
|
char *name;
|
2013-03-05 18:51:26 +01:00
|
|
|
|
|
|
|
if (s->timer_tag) {
|
|
|
|
g_source_remove(s->timer_tag);
|
|
|
|
s->timer_tag = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ms == 1000) {
|
2016-09-30 12:57:14 +02:00
|
|
|
name = g_strdup_printf("pty-timer-secs-%s", chr->label);
|
2013-03-05 18:51:26 +01:00
|
|
|
s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr);
|
|
|
|
} else {
|
2016-09-30 12:57:14 +02:00
|
|
|
name = g_strdup_printf("pty-timer-ms-%s", chr->label);
|
2013-03-05 18:51:26 +01:00
|
|
|
s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr);
|
|
|
|
}
|
2016-09-30 12:57:14 +02:00
|
|
|
g_source_set_name_by_id(s->timer_tag, name);
|
|
|
|
g_free(name);
|
2013-03-05 18:51:26 +01:00
|
|
|
}
|
|
|
|
|
2014-06-18 08:43:58 +02:00
|
|
|
/* Called with chr_write_lock held. */
|
2016-12-07 14:20:22 +01:00
|
|
|
static void pty_chr_update_read_handler_locked(Chardev *chr)
|
2014-06-18 08:43:57 +02:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
PtyChardev *s = PTY_CHARDEV(chr);
|
2014-06-18 08:43:57 +02:00
|
|
|
GPollFD pfd;
|
2015-12-01 11:27:00 +01:00
|
|
|
int rc;
|
2016-01-19 12:14:29 +01:00
|
|
|
QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
|
2014-06-18 08:43:57 +02:00
|
|
|
|
2016-01-19 12:14:29 +01:00
|
|
|
pfd.fd = fioc->fd;
|
2014-06-18 08:43:57 +02:00
|
|
|
pfd.events = G_IO_OUT;
|
|
|
|
pfd.revents = 0;
|
2015-12-01 11:27:00 +01:00
|
|
|
do {
|
|
|
|
rc = g_poll(&pfd, 1, 0);
|
|
|
|
} while (rc == -1 && errno == EINTR);
|
|
|
|
assert(rc >= 0);
|
|
|
|
|
2014-06-18 08:43:57 +02:00
|
|
|
if (pfd.revents & G_IO_HUP) {
|
|
|
|
pty_chr_state(chr, 0);
|
|
|
|
} else {
|
|
|
|
pty_chr_state(chr, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static void pty_chr_update_read_handler(Chardev *chr,
|
2016-10-22 11:53:01 +02:00
|
|
|
GMainContext *context)
|
2014-06-18 08:43:58 +02:00
|
|
|
{
|
|
|
|
qemu_mutex_lock(&chr->chr_write_lock);
|
|
|
|
pty_chr_update_read_handler_locked(chr);
|
|
|
|
qemu_mutex_unlock(&chr->chr_write_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called with chr_write_lock held. */
|
2016-12-07 16:39:10 +01:00
|
|
|
static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
PtyChardev *s = PTY_CHARDEV(chr);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
if (!s->connected) {
|
|
|
|
/* guest sends data, check for (re-)connect */
|
2014-06-18 08:43:58 +02:00
|
|
|
pty_chr_update_read_handler_locked(chr);
|
2014-07-28 13:39:14 +02:00
|
|
|
if (!s->connected) {
|
|
|
|
return 0;
|
|
|
|
}
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
2016-01-19 12:14:29 +01:00
|
|
|
return io_channel_send(s->ioc, buf, len);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
|
2013-03-05 18:51:24 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
PtyChardev *s = PTY_CHARDEV(chr);
|
2014-07-24 16:08:04 +02:00
|
|
|
if (!s->connected) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-01-19 12:14:29 +01:00
|
|
|
return qio_channel_create_watch(s->ioc, cond);
|
2013-03-05 18:51:24 +01:00
|
|
|
}
|
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
static int pty_chr_read_poll(void *opaque)
|
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
Chardev *chr = CHARDEV(opaque);
|
|
|
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2011-08-15 18:17:31 +02:00
|
|
|
s->read_bytes = qemu_chr_be_can_write(chr);
|
2008-10-31 19:49:55 +01:00
|
|
|
return s->read_bytes;
|
|
|
|
}
|
|
|
|
|
2016-01-19 12:14:29 +01:00
|
|
|
static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
Chardev *chr = CHARDEV(opaque);
|
|
|
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
2016-01-19 12:14:29 +01:00
|
|
|
gsize len;
|
2016-12-12 14:39:35 +01:00
|
|
|
uint8_t buf[CHR_READ_BUF_LEN];
|
2016-01-19 12:14:29 +01:00
|
|
|
ssize_t ret;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
len = sizeof(buf);
|
|
|
|
if (len > s->read_bytes)
|
|
|
|
len = s->read_bytes;
|
2013-04-19 17:32:08 +02:00
|
|
|
if (len == 0) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
2016-01-19 12:14:29 +01:00
|
|
|
ret = qio_channel_read(s->ioc, (char *)buf, len, NULL);
|
|
|
|
if (ret <= 0) {
|
2008-10-31 19:49:55 +01:00
|
|
|
pty_chr_state(chr, 0);
|
2013-03-05 18:51:20 +01:00
|
|
|
return FALSE;
|
|
|
|
} else {
|
2008-10-31 19:49:55 +01:00
|
|
|
pty_chr_state(chr, 1);
|
2016-01-19 12:14:29 +01:00
|
|
|
qemu_chr_be_write(chr, buf, ret);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
2013-03-05 18:51:20 +01:00
|
|
|
return TRUE;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
|
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
Chardev *chr = CHARDEV(opaque);
|
|
|
|
PtyChardev *s = PTY_CHARDEV(opaque);
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
|
|
|
|
s->open_tag = 0;
|
|
|
|
qemu_chr_be_generic_open(chr);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2014-06-18 08:43:58 +02:00
|
|
|
/* Called with chr_write_lock held. */
|
2016-12-07 14:20:22 +01:00
|
|
|
static void pty_chr_state(Chardev *chr, int connected)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
PtyChardev *s = PTY_CHARDEV(chr);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
if (!connected) {
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
if (s->open_tag) {
|
|
|
|
g_source_remove(s->open_tag);
|
|
|
|
s->open_tag = 0;
|
|
|
|
}
|
2013-08-28 11:53:37 +02:00
|
|
|
remove_fd_in_watch(chr);
|
2008-10-31 19:49:55 +01:00
|
|
|
s->connected = 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. */
|
2013-03-05 18:51:26 +01:00
|
|
|
pty_chr_rearm_timer(chr, 1000);
|
2008-10-31 19:49:55 +01:00
|
|
|
} else {
|
2013-04-19 17:32:07 +02:00
|
|
|
if (s->timer_tag) {
|
|
|
|
g_source_remove(s->timer_tag);
|
|
|
|
s->timer_tag = 0;
|
|
|
|
}
|
|
|
|
if (!s->connected) {
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
g_assert(s->open_tag == 0);
|
2013-04-19 17:32:07 +02:00
|
|
|
s->connected = 1;
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
|
2014-02-25 11:12:35 +01:00
|
|
|
}
|
|
|
|
if (!chr->fd_in_tag) {
|
2016-09-30 12:57:14 +02:00
|
|
|
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
2016-01-19 12:14:29 +01:00
|
|
|
pty_chr_read_poll,
|
2016-09-27 04:22:25 +02:00
|
|
|
pty_chr_read,
|
|
|
|
chr, NULL);
|
2013-04-19 17:32:07 +02:00
|
|
|
}
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-08 14:52:38 +01:00
|
|
|
static void char_pty_finalize(Object *obj)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-08 14:52:38 +01:00
|
|
|
Chardev *chr = CHARDEV(obj);
|
|
|
|
PtyChardev *s = PTY_CHARDEV(obj);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
qemu_mutex_lock(&chr->chr_write_lock);
|
|
|
|
pty_chr_state(chr, 0);
|
2016-01-19 12:14:29 +01:00
|
|
|
object_unref(OBJECT(s->ioc));
|
2013-03-05 18:51:26 +01:00
|
|
|
if (s->timer_tag) {
|
|
|
|
g_source_remove(s->timer_tag);
|
2013-04-19 17:32:06 +02:00
|
|
|
s->timer_tag = 0;
|
2013-03-05 18:51:26 +01:00
|
|
|
}
|
qemu-char: fix deadlock with "-monitor pty"
qemu_chr_be_generic_open cannot be called with the write lock taken,
because it calls client code that may call qemu_chr_fe_write. This
actually happens for the monitor:
0x00007ffff27dbf79 in __GI_raise (sig=sig@entry=6)
0x00007ffff27df388 in __GI_abort ()
0x00005555555ef489 in error_exit (err=<optimized out>, msg=msg@entry=0x5555559796d0 <__func__.5959> "qemu_mutex_lock")
0x00005555558f9080 in qemu_mutex_lock (mutex=mutex@entry=0x555556248a30)
0x0000555555713936 in qemu_chr_fe_write (s=0x555556248a30, buf=buf@entry=0x5555563d8870 "QEMU 2.0.90 monitor - type 'help' for more information\r\n", len=56)
0x00005555556217fd in monitor_flush_locked (mon=mon@entry=0x555556251fd0)
0x0000555555621a12 in monitor_flush_locked (mon=0x555556251fd0)
monitor_puts (mon=mon@entry=0x555556251fd0, str=0x55555634bfa7 "", str@entry=0x55555634bf70 "QEMU 2.0.90 monitor - type 'help' for more information\n")
0x0000555555624359 in monitor_vprintf (mon=0x555556251fd0, fmt=<optimized out>, ap=<optimized out>)
0x0000555555624414 in monitor_printf (mon=<optimized out>, fmt=fmt@entry=0x5555559105a0 "QEMU %s monitor - type 'help' for more information\n")
0x0000555555629806 in monitor_event (opaque=0x555556251fd0, event=<optimized out>)
0x000055555571343c in qemu_chr_be_generic_open (s=0x555556248a30)
To avoid this, defer the call to an idle callback, which will be
called as soon as the main loop is re-entered. In order to simplify
the cleanup and do it in one place only, change pty_chr_close to
call pty_chr_state.
To reproduce, run with "-monitor pty", then try to read from the
slave /dev/pts/FOO that it creates.
Fixes: 9005b2a7589540a3733b3abdcfbccfe7746cd1a1
Reported-by: Li Liang <liangx.z.li@intel.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 12:11:38 +02:00
|
|
|
qemu_mutex_unlock(&chr->chr_write_lock);
|
2011-11-19 10:22:43 +01:00
|
|
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void char_pty_open(Chardev *chr,
|
|
|
|
ChardevBackend *backend,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
PtyChardev *s;
|
2013-02-25 10:16:46 +01:00
|
|
|
int master_fd, slave_fd;
|
2008-10-31 19:49:55 +01:00
|
|
|
char pty_name[PATH_MAX];
|
2016-09-30 12:57:14 +02:00
|
|
|
char *name;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2013-06-05 16:44:54 +02:00
|
|
|
master_fd = qemu_openpty_raw(&slave_fd, pty_name);
|
|
|
|
if (master_fd < 0) {
|
2015-09-29 15:23:42 +02:00
|
|
|
error_setg_errno(errp, errno, "Failed to create PTY");
|
2016-12-07 16:39:10 +01:00
|
|
|
return;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-02-12 16:05:10 +01:00
|
|
|
close(slave_fd);
|
2014-12-22 16:04:00 +01:00
|
|
|
qemu_set_nonblock(master_fd);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2013-06-05 16:44:54 +02:00
|
|
|
chr->filename = g_strdup_printf("pty:%s", pty_name);
|
2016-11-30 19:57:24 +01:00
|
|
|
error_report("char device redirected to %s (label %s)",
|
2016-12-07 16:39:10 +01:00
|
|
|
pty_name, chr->label);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
s = PTY_CHARDEV(chr);
|
2016-01-19 12:14:29 +01:00
|
|
|
s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
|
2016-09-30 12:57:14 +02:00
|
|
|
name = g_strdup_printf("chardev-pty-%s", chr->label);
|
|
|
|
qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
|
|
|
|
g_free(name);
|
2013-03-05 18:51:26 +01:00
|
|
|
s->timer_tag = 0;
|
2016-10-21 22:44:44 +02:00
|
|
|
*be_opened = false;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void char_pty_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
|
|
|
|
|
|
|
cc->open = char_pty_open;
|
|
|
|
cc->chr_write = char_pty_chr_write;
|
|
|
|
cc->chr_update_read_handler = pty_chr_update_read_handler;
|
|
|
|
cc->chr_add_watch = pty_chr_add_watch;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo char_pty_type_info = {
|
|
|
|
.name = TYPE_CHARDEV_PTY,
|
|
|
|
.parent = TYPE_CHARDEV,
|
|
|
|
.instance_size = sizeof(PtyChardev),
|
2016-12-08 14:52:38 +01:00
|
|
|
.instance_finalize = char_pty_finalize,
|
2016-12-07 16:39:10 +01:00
|
|
|
.class_init = char_pty_class_init,
|
2016-10-21 19:49:37 +02:00
|
|
|
};
|
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
static void tty_serial_init(int fd, int speed,
|
|
|
|
int parity, int data_bits, int stop_bits)
|
|
|
|
{
|
|
|
|
struct termios tty;
|
|
|
|
speed_t spd;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
|
|
|
|
speed, parity, data_bits, stop_bits);
|
|
|
|
#endif
|
|
|
|
tcgetattr (fd, &tty);
|
|
|
|
|
2009-10-26 16:10:10 +01:00
|
|
|
#define check_speed(val) if (speed <= val) { spd = B##val; break; }
|
|
|
|
speed = speed * 10 / 11;
|
|
|
|
do {
|
|
|
|
check_speed(50);
|
|
|
|
check_speed(75);
|
|
|
|
check_speed(110);
|
|
|
|
check_speed(134);
|
|
|
|
check_speed(150);
|
|
|
|
check_speed(200);
|
|
|
|
check_speed(300);
|
|
|
|
check_speed(600);
|
|
|
|
check_speed(1200);
|
|
|
|
check_speed(1800);
|
|
|
|
check_speed(2400);
|
|
|
|
check_speed(4800);
|
|
|
|
check_speed(9600);
|
|
|
|
check_speed(19200);
|
|
|
|
check_speed(38400);
|
|
|
|
/* Non-Posix values follow. They may be unsupported on some systems. */
|
|
|
|
check_speed(57600);
|
|
|
|
check_speed(115200);
|
|
|
|
#ifdef B230400
|
|
|
|
check_speed(230400);
|
|
|
|
#endif
|
|
|
|
#ifdef B460800
|
|
|
|
check_speed(460800);
|
|
|
|
#endif
|
|
|
|
#ifdef B500000
|
|
|
|
check_speed(500000);
|
|
|
|
#endif
|
|
|
|
#ifdef B576000
|
|
|
|
check_speed(576000);
|
|
|
|
#endif
|
|
|
|
#ifdef B921600
|
|
|
|
check_speed(921600);
|
|
|
|
#endif
|
|
|
|
#ifdef B1000000
|
|
|
|
check_speed(1000000);
|
|
|
|
#endif
|
|
|
|
#ifdef B1152000
|
|
|
|
check_speed(1152000);
|
|
|
|
#endif
|
|
|
|
#ifdef B1500000
|
|
|
|
check_speed(1500000);
|
|
|
|
#endif
|
|
|
|
#ifdef B2000000
|
|
|
|
check_speed(2000000);
|
|
|
|
#endif
|
|
|
|
#ifdef B2500000
|
|
|
|
check_speed(2500000);
|
|
|
|
#endif
|
|
|
|
#ifdef B3000000
|
|
|
|
check_speed(3000000);
|
|
|
|
#endif
|
|
|
|
#ifdef B3500000
|
|
|
|
check_speed(3500000);
|
|
|
|
#endif
|
|
|
|
#ifdef B4000000
|
|
|
|
check_speed(4000000);
|
|
|
|
#endif
|
2008-10-31 19:49:55 +01:00
|
|
|
spd = B115200;
|
2009-10-26 16:10:10 +01:00
|
|
|
} while (0);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
cfsetispeed(&tty, spd);
|
|
|
|
cfsetospeed(&tty, spd);
|
|
|
|
|
|
|
|
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|
|
|
|
|INLCR|IGNCR|ICRNL|IXON);
|
|
|
|
tty.c_oflag |= OPOST;
|
|
|
|
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
|
|
|
|
tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
|
|
|
|
switch(data_bits) {
|
|
|
|
default:
|
|
|
|
case 8:
|
|
|
|
tty.c_cflag |= CS8;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
tty.c_cflag |= CS7;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
tty.c_cflag |= CS6;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
tty.c_cflag |= CS5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch(parity) {
|
|
|
|
default:
|
|
|
|
case 'N':
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
tty.c_cflag |= PARENB;
|
|
|
|
break;
|
|
|
|
case 'O':
|
|
|
|
tty.c_cflag |= PARENB | PARODD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (stop_bits == 2)
|
|
|
|
tty.c_cflag |= CSTOPB;
|
|
|
|
|
|
|
|
tcsetattr (fd, TCSANOW, &tty);
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static int tty_serial_ioctl(Chardev *chr, int cmd, void *arg)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
FDChardev *s = FD_CHARDEV(chr);
|
2016-01-19 12:14:29 +01:00
|
|
|
QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
switch(cmd) {
|
|
|
|
case CHR_IOCTL_SERIAL_SET_PARAMS:
|
|
|
|
{
|
|
|
|
QEMUSerialSetParams *ssp = arg;
|
2016-01-19 12:14:29 +01:00
|
|
|
tty_serial_init(fioc->fd,
|
2013-03-05 18:51:19 +01:00
|
|
|
ssp->speed, ssp->parity,
|
2008-10-31 19:49:55 +01:00
|
|
|
ssp->data_bits, ssp->stop_bits);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_SERIAL_SET_BREAK:
|
|
|
|
{
|
|
|
|
int enable = *(int *)arg;
|
2013-03-05 18:51:19 +01:00
|
|
|
if (enable) {
|
2016-01-19 12:14:29 +01:00
|
|
|
tcsendbreak(fioc->fd, 1);
|
2013-03-05 18:51:19 +01:00
|
|
|
}
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_SERIAL_GET_TIOCM:
|
|
|
|
{
|
|
|
|
int sarg = 0;
|
|
|
|
int *targ = (int *)arg;
|
2016-01-19 12:14:29 +01:00
|
|
|
ioctl(fioc->fd, TIOCMGET, &sarg);
|
2008-10-31 19:49:55 +01:00
|
|
|
*targ = 0;
|
2009-02-08 15:46:17 +01:00
|
|
|
if (sarg & TIOCM_CTS)
|
2008-10-31 19:49:55 +01:00
|
|
|
*targ |= CHR_TIOCM_CTS;
|
2009-02-08 15:46:17 +01:00
|
|
|
if (sarg & TIOCM_CAR)
|
2008-10-31 19:49:55 +01:00
|
|
|
*targ |= CHR_TIOCM_CAR;
|
2009-02-08 15:46:17 +01:00
|
|
|
if (sarg & TIOCM_DSR)
|
2008-10-31 19:49:55 +01:00
|
|
|
*targ |= CHR_TIOCM_DSR;
|
2009-02-08 15:46:17 +01:00
|
|
|
if (sarg & TIOCM_RI)
|
2008-10-31 19:49:55 +01:00
|
|
|
*targ |= CHR_TIOCM_RI;
|
2009-02-08 15:46:17 +01:00
|
|
|
if (sarg & TIOCM_DTR)
|
2008-10-31 19:49:55 +01:00
|
|
|
*targ |= CHR_TIOCM_DTR;
|
2009-02-08 15:46:17 +01:00
|
|
|
if (sarg & TIOCM_RTS)
|
2008-10-31 19:49:55 +01:00
|
|
|
*targ |= CHR_TIOCM_RTS;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_SERIAL_SET_TIOCM:
|
|
|
|
{
|
|
|
|
int sarg = *(int *)arg;
|
|
|
|
int targ = 0;
|
2016-01-19 12:14:29 +01:00
|
|
|
ioctl(fioc->fd, TIOCMGET, &targ);
|
2009-02-08 15:46:17 +01:00
|
|
|
targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
|
|
|
|
| CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
|
|
|
|
if (sarg & CHR_TIOCM_CTS)
|
|
|
|
targ |= TIOCM_CTS;
|
|
|
|
if (sarg & CHR_TIOCM_CAR)
|
|
|
|
targ |= TIOCM_CAR;
|
|
|
|
if (sarg & CHR_TIOCM_DSR)
|
|
|
|
targ |= TIOCM_DSR;
|
|
|
|
if (sarg & CHR_TIOCM_RI)
|
|
|
|
targ |= TIOCM_RI;
|
|
|
|
if (sarg & CHR_TIOCM_DTR)
|
2008-10-31 19:49:55 +01:00
|
|
|
targ |= TIOCM_DTR;
|
2009-02-08 15:46:17 +01:00
|
|
|
if (sarg & CHR_TIOCM_RTS)
|
2008-10-31 19:49:55 +01:00
|
|
|
targ |= TIOCM_RTS;
|
2016-01-19 12:14:29 +01:00
|
|
|
ioctl(fioc->fd, TIOCMSET, &targ);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* __linux__ || __sun__ */
|
|
|
|
|
|
|
|
#if defined(__linux__)
|
2012-12-19 16:35:42 +01:00
|
|
|
|
|
|
|
#define HAVE_CHARDEV_PARPORT 1
|
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
typedef struct {
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev parent;
|
2008-10-31 19:49:55 +01:00
|
|
|
int fd;
|
|
|
|
int mode;
|
2016-12-07 14:20:22 +01:00
|
|
|
} ParallelChardev;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
#define PARALLEL_CHARDEV(obj) \
|
|
|
|
OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static int pp_hw_mode(ParallelChardev *s, uint16_t mode)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
|
|
|
if (s->mode != mode) {
|
|
|
|
int m = mode;
|
|
|
|
if (ioctl(s->fd, PPSETMODE, &m) < 0)
|
|
|
|
return 0;
|
|
|
|
s->mode = mode;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static int pp_ioctl(Chardev *chr, int cmd, void *arg)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
2008-10-31 19:49:55 +01:00
|
|
|
int fd = drv->fd;
|
|
|
|
uint8_t b;
|
|
|
|
|
|
|
|
switch(cmd) {
|
|
|
|
case CHR_IOCTL_PP_READ_DATA:
|
|
|
|
if (ioctl(fd, PPRDATA, &b) < 0)
|
|
|
|
return -ENOTSUP;
|
|
|
|
*(uint8_t *)arg = b;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_WRITE_DATA:
|
|
|
|
b = *(uint8_t *)arg;
|
|
|
|
if (ioctl(fd, PPWDATA, &b) < 0)
|
|
|
|
return -ENOTSUP;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_READ_CONTROL:
|
|
|
|
if (ioctl(fd, PPRCONTROL, &b) < 0)
|
|
|
|
return -ENOTSUP;
|
|
|
|
/* Linux gives only the lowest bits, and no way to know data
|
|
|
|
direction! For better compatibility set the fixed upper
|
|
|
|
bits. */
|
|
|
|
*(uint8_t *)arg = b | 0xc0;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_WRITE_CONTROL:
|
|
|
|
b = *(uint8_t *)arg;
|
|
|
|
if (ioctl(fd, PPWCONTROL, &b) < 0)
|
|
|
|
return -ENOTSUP;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_READ_STATUS:
|
|
|
|
if (ioctl(fd, PPRSTATUS, &b) < 0)
|
|
|
|
return -ENOTSUP;
|
|
|
|
*(uint8_t *)arg = b;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_DATA_DIR:
|
|
|
|
if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
|
|
|
|
return -ENOTSUP;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_EPP_READ_ADDR:
|
|
|
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
|
|
|
|
struct ParallelIOArg *parg = arg;
|
|
|
|
int n = read(fd, parg->buffer, parg->count);
|
|
|
|
if (n != parg->count) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_EPP_READ:
|
|
|
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
|
|
|
|
struct ParallelIOArg *parg = arg;
|
|
|
|
int n = read(fd, parg->buffer, parg->count);
|
|
|
|
if (n != parg->count) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_EPP_WRITE_ADDR:
|
|
|
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
|
|
|
|
struct ParallelIOArg *parg = arg;
|
|
|
|
int n = write(fd, parg->buffer, parg->count);
|
|
|
|
if (n != parg->count) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_EPP_WRITE:
|
|
|
|
if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
|
|
|
|
struct ParallelIOArg *parg = arg;
|
|
|
|
int n = write(fd, parg->buffer, parg->count);
|
|
|
|
if (n != parg->count) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qemu_chr_open_pp_fd(Chardev *chr,
|
|
|
|
int fd,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
if (ioctl(fd, PPCLAIM) < 0) {
|
2015-10-12 09:49:28 +02:00
|
|
|
error_setg_errno(errp, errno, "not a parallel port");
|
2008-10-31 19:49:55 +01:00
|
|
|
close(fd);
|
2016-12-07 16:39:10 +01:00
|
|
|
return;
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
}
|
2016-01-18 11:25:45 +01:00
|
|
|
|
|
|
|
drv->fd = fd;
|
|
|
|
drv->mode = IEEE1284_MODE_COMPAT;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
#endif /* __linux__ */
|
|
|
|
|
2009-11-29 18:00:41 +01:00
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
2012-12-19 16:35:42 +01:00
|
|
|
|
|
|
|
#define HAVE_CHARDEV_PARPORT 1
|
|
|
|
|
2016-10-21 22:44:44 +02:00
|
|
|
typedef struct {
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev parent;
|
2016-10-21 22:44:44 +02:00
|
|
|
int fd;
|
2016-12-07 14:20:22 +01:00
|
|
|
} ParallelChardev;
|
2016-10-21 22:44:44 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
#define PARALLEL_CHARDEV(obj) \
|
|
|
|
OBJECT_CHECK(ParallelChardev, (obj), TYPE_CHARDEV_PARALLEL)
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static int pp_ioctl(Chardev *chr, int cmd, void *arg)
|
2008-11-22 21:49:12 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
2008-11-22 21:49:12 +01:00
|
|
|
uint8_t b;
|
|
|
|
|
2016-10-21 22:44:44 +02:00
|
|
|
switch (cmd) {
|
2008-11-22 21:49:12 +01:00
|
|
|
case CHR_IOCTL_PP_READ_DATA:
|
2016-10-21 22:44:44 +02:00
|
|
|
if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
|
2008-11-22 21:49:12 +01:00
|
|
|
return -ENOTSUP;
|
2016-10-21 22:44:44 +02:00
|
|
|
}
|
2008-11-22 21:49:12 +01:00
|
|
|
*(uint8_t *)arg = b;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_WRITE_DATA:
|
|
|
|
b = *(uint8_t *)arg;
|
2016-10-21 22:44:44 +02:00
|
|
|
if (ioctl(drv->fd, PPISDATA, &b) < 0) {
|
2008-11-22 21:49:12 +01:00
|
|
|
return -ENOTSUP;
|
2016-10-21 22:44:44 +02:00
|
|
|
}
|
2008-11-22 21:49:12 +01:00
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_READ_CONTROL:
|
2016-10-21 22:44:44 +02:00
|
|
|
if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
|
2008-11-22 21:49:12 +01:00
|
|
|
return -ENOTSUP;
|
2016-10-21 22:44:44 +02:00
|
|
|
}
|
2008-11-22 21:49:12 +01:00
|
|
|
*(uint8_t *)arg = b;
|
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_WRITE_CONTROL:
|
|
|
|
b = *(uint8_t *)arg;
|
2016-10-21 22:44:44 +02:00
|
|
|
if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
|
2008-11-22 21:49:12 +01:00
|
|
|
return -ENOTSUP;
|
2016-10-21 22:44:44 +02:00
|
|
|
}
|
2008-11-22 21:49:12 +01:00
|
|
|
break;
|
|
|
|
case CHR_IOCTL_PP_READ_STATUS:
|
2016-10-21 22:44:44 +02:00
|
|
|
if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
|
2008-11-22 21:49:12 +01:00
|
|
|
return -ENOTSUP;
|
2016-10-21 22:44:44 +02:00
|
|
|
}
|
2008-11-22 21:49:12 +01:00
|
|
|
*(uint8_t *)arg = b;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qemu_chr_open_pp_fd(Chardev *chr,
|
|
|
|
int fd,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2008-11-22 21:49:12 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
2016-10-21 22:44:44 +02:00
|
|
|
drv->fd = fd;
|
2016-10-22 12:09:43 +02:00
|
|
|
*be_opened = false;
|
2008-11-22 21:49:12 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
#else /* _WIN32 */
|
|
|
|
|
2015-10-12 09:46:23 +02:00
|
|
|
#define HAVE_CHARDEV_SERIAL 1
|
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
#define MAXCONNECT 1
|
|
|
|
#define NTIMEOUT 5000
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
static int win_chr_pipe_init(Chardev *chr, const char *filename,
|
2015-09-29 15:14:07 +02:00
|
|
|
Error **errp)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
WinChardev *s = WIN_CHARDEV(chr);
|
2008-10-31 19:49:55 +01:00
|
|
|
OVERLAPPED ov;
|
|
|
|
int ret;
|
|
|
|
DWORD size;
|
2016-01-19 12:14:28 +01:00
|
|
|
char *openname;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
|
|
|
s->fpipe = TRUE;
|
|
|
|
|
|
|
|
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (!s->hsend) {
|
2015-09-29 15:14:07 +02:00
|
|
|
error_setg(errp, "Failed CreateEvent");
|
2008-10-31 19:49:55 +01:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (!s->hrecv) {
|
2015-09-29 15:14:07 +02:00
|
|
|
error_setg(errp, "Failed CreateEvent");
|
2008-10-31 19:49:55 +01:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-01-19 12:14:28 +01:00
|
|
|
openname = g_strdup_printf("\\\\.\\pipe\\%s", filename);
|
2008-10-31 19:49:55 +01:00
|
|
|
s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
|
|
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
|
|
|
|
PIPE_WAIT,
|
|
|
|
MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
|
2016-01-19 12:14:28 +01:00
|
|
|
g_free(openname);
|
2008-10-31 19:49:55 +01:00
|
|
|
if (s->hcom == INVALID_HANDLE_VALUE) {
|
2015-09-29 15:14:07 +02:00
|
|
|
error_setg(errp, "Failed CreateNamedPipe (%lu)", GetLastError());
|
2008-10-31 19:49:55 +01:00
|
|
|
s->hcom = NULL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZeroMemory(&ov, sizeof(ov));
|
|
|
|
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
ret = ConnectNamedPipe(s->hcom, &ov);
|
|
|
|
if (ret) {
|
2015-09-29 15:14:07 +02:00
|
|
|
error_setg(errp, "Failed ConnectNamedPipe");
|
2008-10-31 19:49:55 +01:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
|
|
|
|
if (!ret) {
|
2015-09-29 15:14:07 +02:00
|
|
|
error_setg(errp, "Failed GetOverlappedResult");
|
2008-10-31 19:49:55 +01:00
|
|
|
if (ov.hEvent) {
|
|
|
|
CloseHandle(ov.hEvent);
|
|
|
|
ov.hEvent = NULL;
|
|
|
|
}
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ov.hEvent) {
|
|
|
|
CloseHandle(ov.hEvent);
|
|
|
|
ov.hEvent = NULL;
|
|
|
|
}
|
|
|
|
qemu_add_polling_cb(win_chr_pipe_poll, chr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qemu_chr_open_pipe(Chardev *chr,
|
|
|
|
ChardevBackend *backend,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
ChardevHostdev *opts = backend->u.pipe.data;
|
2013-02-25 11:50:55 +01:00
|
|
|
const char *filename = opts->device;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2015-09-29 15:14:07 +02:00
|
|
|
if (win_chr_pipe_init(chr, filename, errp) < 0) {
|
2016-12-07 16:39:10 +01:00
|
|
|
return;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qemu_chr_open_win_con(Chardev *chr,
|
|
|
|
ChardevBackend *backend,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
qemu_chr_open_win_file(chr, GetStdHandle(STD_OUTPUT_HANDLE));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void char_console_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
|
|
|
|
|
|
|
cc->open = qemu_chr_open_win_con;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo char_console_type_info = {
|
|
|
|
.name = TYPE_CHARDEV_CONSOLE,
|
|
|
|
.parent = TYPE_CHARDEV_WIN,
|
|
|
|
.class_init = char_console_class_init,
|
2016-10-21 19:49:37 +02:00
|
|
|
};
|
|
|
|
|
2008-10-31 19:49:55 +01:00
|
|
|
#endif /* !_WIN32 */
|
|
|
|
|
2016-12-12 16:41:00 +01:00
|
|
|
int qemu_chr_wait_connected(Chardev *chr, Error **errp)
|
2016-07-26 23:15:17 +02:00
|
|
|
{
|
2016-12-07 16:39:10 +01:00
|
|
|
ChardevClass *cc = CHARDEV_GET_CLASS(chr);
|
|
|
|
|
|
|
|
if (cc->chr_wait_connected) {
|
|
|
|
return cc->chr_wait_connected(chr, errp);
|
2016-07-26 23:15:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
|
|
|
|
{
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!be->chr) {
|
|
|
|
error_setg(errp, "missing associated backend");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
return qemu_chr_wait_connected(be->chr, errp);
|
|
|
|
}
|
|
|
|
|
2009-12-08 13:11:49 +01:00
|
|
|
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
2009-09-10 10:58:35 +02:00
|
|
|
{
|
2009-09-10 10:58:49 +02:00
|
|
|
char host[65], port[33], width[8], height[8];
|
2009-09-10 10:58:42 +02:00
|
|
|
int pos;
|
2009-09-10 10:58:36 +02:00
|
|
|
const char *p;
|
2009-09-10 10:58:35 +02:00
|
|
|
QemuOpts *opts;
|
2012-03-20 19:51:57 +01:00
|
|
|
Error *local_err = NULL;
|
2009-09-10 10:58:35 +02:00
|
|
|
|
2012-03-20 19:51:57 +01:00
|
|
|
opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, &local_err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (local_err) {
|
2015-02-10 15:21:26 +01:00
|
|
|
error_report_err(local_err);
|
2009-09-10 10:58:35 +02:00
|
|
|
return NULL;
|
2012-03-20 19:51:57 +01:00
|
|
|
}
|
2009-09-10 10:58:35 +02:00
|
|
|
|
2009-09-10 10:58:50 +02:00
|
|
|
if (strstart(filename, "mon:", &p)) {
|
|
|
|
filename = p;
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "mux", "on", &error_abort);
|
2013-07-03 18:29:45 +02:00
|
|
|
if (strcmp(filename, "stdio") == 0) {
|
|
|
|
/* Monitor is muxed to stdio: do not exit on Ctrl+C by default
|
|
|
|
* but pass it to the guest. Handle this only for compat syntax,
|
|
|
|
* for -chardev syntax we have special option for this.
|
|
|
|
* This is what -nographic did, redirecting+muxing serial+monitor
|
|
|
|
* to stdio causing Ctrl+C to be passed to guest. */
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "signal", "off", &error_abort);
|
2013-07-03 18:29:45 +02:00
|
|
|
}
|
2009-09-10 10:58:50 +02:00
|
|
|
}
|
|
|
|
|
2009-09-10 10:58:45 +02:00
|
|
|
if (strcmp(filename, "null") == 0 ||
|
|
|
|
strcmp(filename, "pty") == 0 ||
|
|
|
|
strcmp(filename, "msmouse") == 0 ||
|
2009-09-10 10:58:46 +02:00
|
|
|
strcmp(filename, "braille") == 0 ||
|
backends: Introduce chr-testdev
From: Paolo Bonzini <pbonzini@redhat.com>
chr-testdev enables a virtio serial channel to be used for guest
initiated qemu exits. hw/misc/debugexit already enables guest
initiated qemu exits, but only for PC targets. chr-testdev supports
any virtio-capable target. kvm-unit-tests/arm is already making use
of this backend.
Currently there is a single command implemented, "q". It takes a
(prefix) argument for the exit code, thus an exit is implemented by
writing, e.g. "1q", to the virtio-serial port.
It can be used as:
$QEMU ... \
-device virtio-serial-device \
-device virtserialport,chardev=ctd -chardev testdev,id=ctd
or, use:
$QEMU ... \
-device virtio-serial-device \
-device virtconsole,chardev=ctd -chardev testdev,id=ctd
to bind it to virtio-serial port0.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2014-07-11 09:44:26 +02:00
|
|
|
strcmp(filename, "testdev") == 0 ||
|
2009-09-10 10:58:45 +02:00
|
|
|
strcmp(filename, "stdio") == 0) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", filename, &error_abort);
|
2009-09-10 10:58:35 +02:00
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:49 +02:00
|
|
|
if (strstart(filename, "vc", &p)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "vc", &error_abort);
|
2009-09-10 10:58:49 +02:00
|
|
|
if (*p == ':') {
|
2013-09-30 23:04:49 +02:00
|
|
|
if (sscanf(p+1, "%7[0-9]x%7[0-9]", width, height) == 2) {
|
2009-09-10 10:58:49 +02:00
|
|
|
/* pixels */
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "width", width, &error_abort);
|
|
|
|
qemu_opt_set(opts, "height", height, &error_abort);
|
2013-09-30 23:04:49 +02:00
|
|
|
} else if (sscanf(p+1, "%7[0-9]Cx%7[0-9]C", width, height) == 2) {
|
2009-09-10 10:58:49 +02:00
|
|
|
/* chars */
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "cols", width, &error_abort);
|
|
|
|
qemu_opt_set(opts, "rows", height, &error_abort);
|
2009-09-10 10:58:49 +02:00
|
|
|
} else {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:47 +02:00
|
|
|
if (strcmp(filename, "con:") == 0) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "console", &error_abort);
|
2009-09-10 10:58:47 +02:00
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:48 +02:00
|
|
|
if (strstart(filename, "COM", NULL)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "serial", &error_abort);
|
|
|
|
qemu_opt_set(opts, "path", filename, &error_abort);
|
2009-09-10 10:58:48 +02:00
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:36 +02:00
|
|
|
if (strstart(filename, "file:", &p)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "file", &error_abort);
|
|
|
|
qemu_opt_set(opts, "path", p, &error_abort);
|
2009-09-10 10:58:36 +02:00
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
if (strstart(filename, "pipe:", &p)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "pipe", &error_abort);
|
|
|
|
qemu_opt_set(opts, "path", p, &error_abort);
|
2009-09-10 10:58:36 +02:00
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:42 +02:00
|
|
|
if (strstart(filename, "tcp:", &p) ||
|
|
|
|
strstart(filename, "telnet:", &p)) {
|
|
|
|
if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
|
|
|
|
host[0] = 0;
|
|
|
|
if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
|
|
|
|
goto fail;
|
|
|
|
}
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "socket", &error_abort);
|
|
|
|
qemu_opt_set(opts, "host", host, &error_abort);
|
|
|
|
qemu_opt_set(opts, "port", port, &error_abort);
|
2009-09-10 10:58:42 +02:00
|
|
|
if (p[pos] == ',') {
|
2015-02-12 18:37:11 +01:00
|
|
|
qemu_opts_do_parse(opts, p+pos+1, NULL, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_report_err(local_err);
|
2009-09-10 10:58:42 +02:00
|
|
|
goto fail;
|
2015-02-12 18:37:11 +01:00
|
|
|
}
|
2009-09-10 10:58:42 +02:00
|
|
|
}
|
|
|
|
if (strstart(filename, "telnet:", &p))
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "telnet", "on", &error_abort);
|
2009-09-10 10:58:42 +02:00
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:51 +02:00
|
|
|
if (strstart(filename, "udp:", &p)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "udp", &error_abort);
|
2009-09-10 10:58:51 +02:00
|
|
|
if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
|
|
|
|
host[0] = 0;
|
2010-03-07 11:28:48 +01:00
|
|
|
if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
|
2009-09-10 10:58:51 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "host", host, &error_abort);
|
|
|
|
qemu_opt_set(opts, "port", port, &error_abort);
|
2009-09-10 10:58:51 +02:00
|
|
|
if (p[pos] == '@') {
|
|
|
|
p += pos + 1;
|
|
|
|
if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
|
|
|
|
host[0] = 0;
|
|
|
|
if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "localaddr", host, &error_abort);
|
|
|
|
qemu_opt_set(opts, "localport", port, &error_abort);
|
2009-09-10 10:58:51 +02:00
|
|
|
}
|
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:42 +02:00
|
|
|
if (strstart(filename, "unix:", &p)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "socket", &error_abort);
|
2015-02-12 18:37:11 +01:00
|
|
|
qemu_opts_do_parse(opts, p, "path", &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_report_err(local_err);
|
2009-09-10 10:58:42 +02:00
|
|
|
goto fail;
|
2015-02-12 18:37:11 +01:00
|
|
|
}
|
2009-09-10 10:58:42 +02:00
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:48 +02:00
|
|
|
if (strstart(filename, "/dev/parport", NULL) ||
|
|
|
|
strstart(filename, "/dev/ppi", NULL)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "parport", &error_abort);
|
|
|
|
qemu_opt_set(opts, "path", filename, &error_abort);
|
2009-09-10 10:58:48 +02:00
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
if (strstart(filename, "/dev/", NULL)) {
|
2015-02-12 17:52:20 +01:00
|
|
|
qemu_opt_set(opts, "backend", "tty", &error_abort);
|
|
|
|
qemu_opt_set(opts, "path", filename, &error_abort);
|
2009-09-10 10:58:48 +02:00
|
|
|
return opts;
|
|
|
|
}
|
2009-09-10 10:58:35 +02:00
|
|
|
|
2009-09-10 10:58:42 +02:00
|
|
|
fail:
|
2009-09-10 10:58:35 +02:00
|
|
|
qemu_opts_del(opts);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-20 01:19:31 +01:00
|
|
|
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
{
|
|
|
|
const char *logfile = qemu_opt_get(opts, "logfile");
|
|
|
|
|
|
|
|
backend->has_logfile = logfile != NULL;
|
|
|
|
backend->logfile = logfile ? g_strdup(logfile) : NULL;
|
|
|
|
|
|
|
|
backend->has_logappend = true;
|
|
|
|
backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
|
|
|
|
}
|
|
|
|
|
2015-09-29 15:08:05 +02:00
|
|
|
#ifdef HAVE_CHARDEV_SERIAL
|
2013-02-22 15:48:05 +01:00
|
|
|
static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
const char *device = qemu_opt_get(opts, "path");
|
2016-03-03 17:16:47 +01:00
|
|
|
ChardevHostdev *serial;
|
2013-02-22 15:48:05 +01:00
|
|
|
|
2016-12-09 09:04:51 +01:00
|
|
|
backend->type = CHARDEV_BACKEND_KIND_SERIAL;
|
2013-02-22 15:48:05 +01:00
|
|
|
if (device == NULL) {
|
|
|
|
error_setg(errp, "chardev: serial/tty: no device path given");
|
|
|
|
return;
|
|
|
|
}
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
serial = backend->u.serial.data = g_new0(ChardevHostdev, 1);
|
2016-03-03 17:16:47 +01:00
|
|
|
qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(serial));
|
|
|
|
serial->device = g_strdup(device);
|
2013-02-22 15:48:05 +01:00
|
|
|
}
|
2015-09-29 15:08:05 +02:00
|
|
|
#endif
|
2013-02-22 15:48:05 +01:00
|
|
|
|
2015-10-12 09:49:28 +02:00
|
|
|
#ifdef HAVE_CHARDEV_PARPORT
|
2013-02-22 16:17:01 +01:00
|
|
|
static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
const char *device = qemu_opt_get(opts, "path");
|
2016-03-03 17:16:47 +01:00
|
|
|
ChardevHostdev *parallel;
|
2013-02-22 16:17:01 +01:00
|
|
|
|
2016-12-09 09:04:51 +01:00
|
|
|
backend->type = CHARDEV_BACKEND_KIND_PARALLEL;
|
2013-02-22 16:17:01 +01:00
|
|
|
if (device == NULL) {
|
|
|
|
error_setg(errp, "chardev: parallel: no device path given");
|
|
|
|
return;
|
|
|
|
}
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
parallel = backend->u.parallel.data = g_new0(ChardevHostdev, 1);
|
2016-03-03 17:16:47 +01:00
|
|
|
qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(parallel));
|
|
|
|
parallel->device = g_strdup(device);
|
2013-02-22 16:17:01 +01:00
|
|
|
}
|
2015-10-12 09:49:28 +02:00
|
|
|
#endif
|
2013-02-22 16:17:01 +01:00
|
|
|
|
2013-02-25 11:50:55 +01:00
|
|
|
static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
const char *device = qemu_opt_get(opts, "path");
|
2016-03-03 17:16:47 +01:00
|
|
|
ChardevHostdev *dev;
|
2013-02-25 11:50:55 +01:00
|
|
|
|
2016-12-09 09:04:51 +01:00
|
|
|
backend->type = CHARDEV_BACKEND_KIND_PIPE;
|
2013-02-25 11:50:55 +01:00
|
|
|
if (device == NULL) {
|
|
|
|
error_setg(errp, "chardev: pipe: no device path given");
|
|
|
|
return;
|
|
|
|
}
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
dev = backend->u.pipe.data = g_new0(ChardevHostdev, 1);
|
2016-03-03 17:16:47 +01:00
|
|
|
qemu_chr_parse_common(opts, qapi_ChardevHostdev_base(dev));
|
|
|
|
dev->device = g_strdup(device);
|
2013-02-25 11:50:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void char_pipe_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
cc->parse = qemu_chr_parse_pipe;
|
2016-12-07 16:39:10 +01:00
|
|
|
cc->open = qemu_chr_open_pipe;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo char_pipe_type_info = {
|
|
|
|
.name = TYPE_CHARDEV_PIPE,
|
2016-10-21 19:49:37 +02:00
|
|
|
#ifdef _WIN32
|
2016-12-07 16:39:10 +01:00
|
|
|
.parent = TYPE_CHARDEV_WIN,
|
2016-10-21 19:49:37 +02:00
|
|
|
#else
|
2016-12-07 16:39:10 +01:00
|
|
|
.parent = TYPE_CHARDEV_FD,
|
2016-10-21 19:49:37 +02:00
|
|
|
#endif
|
2016-12-07 16:39:10 +01:00
|
|
|
.class_init = char_pipe_class_init,
|
2016-10-21 19:49:37 +02:00
|
|
|
};
|
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
static const ChardevClass *char_get_class(const char *driver, Error **errp)
|
|
|
|
{
|
|
|
|
ObjectClass *oc;
|
|
|
|
const ChardevClass *cc;
|
|
|
|
char *typename = g_strdup_printf("chardev-%s", driver);
|
|
|
|
|
|
|
|
oc = object_class_by_name(typename);
|
|
|
|
g_free(typename);
|
|
|
|
|
|
|
|
if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
|
|
|
|
error_setg(errp, "'%s' is not a valid char driver name", driver);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-03-05 18:51:28 +01:00
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
if (object_class_is_abstract(oc)) {
|
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
|
|
|
|
"abstract device type");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc = CHARDEV_CLASS(oc);
|
|
|
|
if (cc->internal) {
|
|
|
|
error_setg(errp, "'%s' is not a valid char driver name", driver);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cc;
|
|
|
|
}
|
|
|
|
|
2016-12-09 09:04:51 +01:00
|
|
|
static Chardev *qemu_chardev_add(const char *id, const char *typename,
|
|
|
|
ChardevBackend *backend, Error **errp)
|
|
|
|
{
|
|
|
|
Chardev *chr;
|
|
|
|
|
|
|
|
chr = qemu_chr_find(id);
|
|
|
|
if (chr) {
|
|
|
|
error_setg(errp, "Chardev '%s' already exists", id);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
chr = qemu_chardev_new(id, typename, backend, errp);
|
|
|
|
if (!chr) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
QTAILQ_INSERT_TAIL(&chardevs, chr, next);
|
|
|
|
return chr;
|
|
|
|
}
|
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
static const struct ChardevAlias {
|
|
|
|
const char *typename;
|
|
|
|
const char *alias;
|
|
|
|
} chardev_alias_table[] = {
|
|
|
|
#ifdef HAVE_CHARDEV_PARPORT
|
|
|
|
{ "parallel", "parport" },
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_CHARDEV_SERIAL
|
|
|
|
{ "serial", "tty" },
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct ChadevClassFE {
|
|
|
|
void (*fn)(const char *name, void *opaque);
|
|
|
|
void *opaque;
|
|
|
|
} ChadevClassFE;
|
|
|
|
|
|
|
|
static void
|
|
|
|
chardev_class_foreach(ObjectClass *klass, void *opaque)
|
2013-02-21 11:39:12 +01:00
|
|
|
{
|
2016-12-08 22:50:12 +01:00
|
|
|
ChadevClassFE *fe = opaque;
|
|
|
|
|
|
|
|
assert(g_str_has_prefix(object_class_get_name(klass), "chardev-"));
|
|
|
|
if (CHARDEV_CLASS(klass)->internal) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fe->fn(object_class_get_name(klass) + 8, fe->opaque);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
chardev_name_foreach(void (*fn)(const char *name, void *opaque), void *opaque)
|
|
|
|
{
|
|
|
|
ChadevClassFE fe = { .fn = fn, .opaque = opaque };
|
|
|
|
int i;
|
|
|
|
|
|
|
|
object_class_foreach(chardev_class_foreach, TYPE_CHARDEV, false, &fe);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(chardev_alias_table); i++) {
|
|
|
|
fn(chardev_alias_table[i].alias, opaque);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
help_string_append(const char *name, void *opaque)
|
|
|
|
{
|
|
|
|
GString *str = opaque;
|
|
|
|
|
|
|
|
g_string_append_printf(str, "\n%s", name);
|
2013-02-21 11:39:12 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
|
|
|
Error **errp)
|
2009-09-10 10:58:35 +02:00
|
|
|
{
|
2014-05-19 18:57:35 +02:00
|
|
|
Error *local_err = NULL;
|
2016-12-08 22:50:12 +01:00
|
|
|
const ChardevClass *cc;
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr;
|
2016-10-21 15:30:29 +02:00
|
|
|
int i;
|
2016-12-09 09:04:51 +01:00
|
|
|
ChardevBackend *backend = NULL;
|
2016-10-21 15:07:45 +02:00
|
|
|
const char *name = qemu_opt_get(opts, "backend");
|
2014-09-02 12:24:16 +02:00
|
|
|
const char *id = qemu_opts_id(opts);
|
|
|
|
char *bid = NULL;
|
2009-09-10 10:58:35 +02:00
|
|
|
|
2016-10-21 15:07:45 +02:00
|
|
|
if (name == NULL) {
|
error: Strip trailing '\n' from error string arguments (again)
Commit 6daf194d and be62a2eb got rid of a bunch, but they keep coming
back. Tracked down with this Coccinelle semantic patch:
@r@
expression err, eno, cls, fmt;
position p;
@@
(
error_report(fmt, ...)@p
|
error_set(err, cls, fmt, ...)@p
|
error_set_errno(err, eno, cls, fmt, ...)@p
|
error_setg(err, fmt, ...)@p
|
error_setg_errno(err, eno, fmt, ...)@p
)
@script:python@
fmt << r.fmt;
p << r.p;
@@
if "\\n" in str(fmt):
print "%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-id: 1360354939-10994-4-git-send-email-armbru@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-08 21:22:16 +01:00
|
|
|
error_setg(errp, "chardev: \"%s\" missing backend",
|
2012-10-15 09:28:05 +02:00
|
|
|
qemu_opts_id(opts));
|
2016-12-09 09:04:51 +01:00
|
|
|
return NULL;
|
2011-01-22 14:07:26 +01:00
|
|
|
}
|
2016-08-16 19:13:52 +02:00
|
|
|
|
2016-10-21 15:07:45 +02:00
|
|
|
if (is_help_option(name)) {
|
2016-11-30 19:57:24 +01:00
|
|
|
GString *str = g_string_new("");
|
2016-12-08 22:50:12 +01:00
|
|
|
|
|
|
|
chardev_name_foreach(help_string_append, str);
|
2016-11-30 19:57:24 +01:00
|
|
|
|
|
|
|
error_report("Available chardev backend types: %s", str->str);
|
|
|
|
g_string_free(str, true);
|
2016-10-21 15:07:45 +02:00
|
|
|
exit(0);
|
2016-08-16 19:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (id == NULL) {
|
|
|
|
error_setg(errp, "chardev: no id specified");
|
2016-12-09 09:04:51 +01:00
|
|
|
return NULL;
|
2016-08-16 19:13:52 +02:00
|
|
|
}
|
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(chardev_alias_table); i++) {
|
|
|
|
if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
|
|
|
|
name = chardev_alias_table[i].typename;
|
2009-09-10 10:58:35 +02:00
|
|
|
break;
|
2013-03-05 18:51:28 +01:00
|
|
|
}
|
2009-09-10 10:58:35 +02:00
|
|
|
}
|
2016-12-08 22:50:12 +01:00
|
|
|
|
|
|
|
cc = char_get_class(name, errp);
|
|
|
|
if (cc == NULL) {
|
2016-12-09 09:04:51 +01:00
|
|
|
return NULL;
|
2009-09-10 10:58:35 +02:00
|
|
|
}
|
|
|
|
|
2014-09-02 12:24:16 +02:00
|
|
|
backend = g_new0(ChardevBackend, 1);
|
2016-12-09 09:04:51 +01:00
|
|
|
backend->type = CHARDEV_BACKEND_KIND_NULL;
|
2013-02-21 16:16:42 +01:00
|
|
|
|
2014-09-02 12:24:16 +02:00
|
|
|
if (qemu_opt_get_bool(opts, "mux", 0)) {
|
|
|
|
bid = g_strdup_printf("%s-base", id);
|
|
|
|
}
|
2013-02-21 11:39:12 +01:00
|
|
|
|
2014-09-02 12:24:16 +02:00
|
|
|
chr = NULL;
|
2016-12-08 22:50:12 +01:00
|
|
|
if (cc->parse) {
|
|
|
|
cc->parse(opts, backend, &local_err);
|
2014-09-02 12:24:16 +02:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2016-12-09 09:04:51 +01:00
|
|
|
goto out;
|
2013-02-21 11:39:12 +01:00
|
|
|
}
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
} else {
|
2016-12-08 22:50:12 +01:00
|
|
|
ChardevCommon *ccom = g_new0(ChardevCommon, 1);
|
|
|
|
qemu_chr_parse_common(opts, ccom);
|
|
|
|
backend->u.null.data = ccom; /* Any ChardevCommon member would work */
|
2013-02-21 11:39:12 +01:00
|
|
|
}
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
|
2016-12-09 09:04:51 +01:00
|
|
|
chr = qemu_chardev_add(bid ? bid : id,
|
|
|
|
object_class_get_name(OBJECT_CLASS(cc)),
|
|
|
|
backend, errp);
|
|
|
|
if (chr == NULL) {
|
|
|
|
goto out;
|
2009-09-10 10:58:35 +02:00
|
|
|
}
|
|
|
|
|
2014-09-02 12:24:16 +02:00
|
|
|
if (bid) {
|
2016-12-09 09:04:51 +01:00
|
|
|
Chardev *mux;
|
2014-09-02 12:24:16 +02:00
|
|
|
qapi_free_ChardevBackend(backend);
|
|
|
|
backend = g_new0(ChardevBackend, 1);
|
2015-10-26 23:34:57 +01:00
|
|
|
backend->type = CHARDEV_BACKEND_KIND_MUX;
|
2016-12-09 09:04:51 +01:00
|
|
|
backend->u.mux.data = g_new0(ChardevMux, 1);
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
backend->u.mux.data->chardev = g_strdup(bid);
|
2016-12-09 09:04:51 +01:00
|
|
|
mux = qemu_chardev_add(id, TYPE_CHARDEV_MUX, backend, errp);
|
|
|
|
if (mux == NULL) {
|
2014-09-02 12:24:16 +02:00
|
|
|
qemu_chr_delete(chr);
|
|
|
|
chr = NULL;
|
2016-12-09 09:04:51 +01:00
|
|
|
goto out;
|
2014-09-02 12:24:16 +02:00
|
|
|
}
|
2016-12-09 09:04:51 +01:00
|
|
|
chr = mux;
|
qemu-char: don't issue CHR_EVENT_OPEN in a BH
When CHR_EVENT_OPENED was initially added, it was CHR_EVENT_RESET,
and it was issued as a bottom-half:
86e94dea5b740dad65446c857f6959eae43e0ba6
Which we basically used to print out a greeting/prompt for the
monitor.
AFAICT the only reason this was ever done in a BH was because in
some cases we'd modify the chr_write handler for a new chardev
backend *after* the site where we issued the reset (see:
86e94d:qemu_chr_open_stdio())
At some point this event was renamed to CHR_EVENT_OPENED, and we've
maintained the use of this BH ever since.
However, due to 9f939df955a4152aad69a19a77e0898631bb2c18, we schedule
the BH via g_idle_add(), which is causing events to sometimes be
delivered after we've already begun processing data from backends,
leading to:
known bugs:
QMP:
session negotation resets with OPENED event, in some cases this
is causing new sessions to get sporadically reset
potential bugs:
hw/usb/redirect.c:
can_read handler checks for dev->parser != NULL, which may be
true if CLOSED BH has not been executed yet. In the past, OPENED
quiesced outstanding CLOSED events prior to us reading client
data. If it's delayed, our check may allow reads to occur even
though we haven't processed the OPENED event yet, and when we
do finally get the OPENED event, our state may get reset.
qtest.c:
can begin session before OPENED event is processed, leading to
a spurious reset of the system and irq_levels
gdbstub.c:
may start a gdb session prior to the machine being paused
To fix these, let's just drop the BH.
Since the initial reasoning for using it still applies to an extent,
work around that by deferring the delivery of CHR_EVENT_OPENED until
after the chardevs have been fully initialized, toward the end of
qmp_chardev_add() (or some cases, qemu_chr_new_from_opts()). This
defers delivery long enough that we can be assured a CharDriverState
is fully initialized before CHR_EVENT_OPENED is sent.
Also, rather than requiring each chardev to do an explicit open, do it
automatically, and allow the small few who don't desire such behavior to
suppress the OPENED-on-init behavior by setting a 'explicit_be_open'
flag.
We additionally add missing OPENED events for stdio backends on w32,
which were previously not being issued, causing us to not recieve the
banner and initial prompts for qmp/hmp.
Reported-by: Stefan Priebe <s.priebe@profihost.ag>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Message-id: 1370636393-21044-1-git-send-email-mdroth@linux.vnet.ibm.com
Cc: qemu-stable@nongnu.org
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-06-07 22:19:53 +02:00
|
|
|
}
|
2009-09-10 10:58:50 +02:00
|
|
|
|
2016-12-09 09:04:51 +01:00
|
|
|
out:
|
2014-09-02 12:24:16 +02:00
|
|
|
qapi_free_ChardevBackend(backend);
|
|
|
|
g_free(bid);
|
2009-09-10 10:58:35 +02:00
|
|
|
return chr;
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
|
|
|
const char *p;
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr;
|
2009-09-10 10:58:35 +02:00
|
|
|
QemuOpts *opts;
|
2012-10-15 09:28:05 +02:00
|
|
|
Error *err = NULL;
|
2009-09-10 10:58:35 +02:00
|
|
|
|
2009-09-10 10:58:52 +02:00
|
|
|
if (strstart(filename, "chardev:", &p)) {
|
|
|
|
return qemu_chr_find(p);
|
|
|
|
}
|
|
|
|
|
2009-09-10 10:58:35 +02:00
|
|
|
opts = qemu_chr_parse_compat(label, filename);
|
2009-09-10 10:58:51 +02:00
|
|
|
if (!opts)
|
|
|
|
return NULL;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2016-10-22 11:52:46 +02:00
|
|
|
chr = qemu_chr_new_from_opts(opts, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err) {
|
2015-02-12 13:55:05 +01:00
|
|
|
error_report_err(err);
|
2012-10-15 09:28:05 +02:00
|
|
|
}
|
2009-09-10 10:58:51 +02:00
|
|
|
if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
|
|
|
|
monitor_init(chr, MONITOR_USE_READLINE);
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
net: don't poke at chardev internal QemuOpts
The vhost-user & colo code is poking at the QemuOpts instance
in the CharDriverState struct, not realizing that it is valid
for this to be NULL. e.g. the following crash shows a codepath
where it will be NULL:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
617 QTAILQ_FOREACH(opt, &opts->head, next) {
[Current thread is 1 (Thread 0x7f1d4970bb40 (LWP 6603))]
(gdb) bt
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
#1 0x000055baf696b7da in net_vhost_parse_chardev (opts=0x55baf8ff9260, errp=0x7ffc51368e48) at net/vhost-user.c:314
#2 0x000055baf696b985 in net_init_vhost_user (netdev=0x55baf8ff9250, name=0x55baf879d270 "hostnet2", peer=0x0, errp=0x7ffc51368e48) at net/vhost-user.c:360
#3 0x000055baf6960216 in net_client_init1 (object=0x55baf8ff9250, is_netdev=true, errp=0x7ffc51368e48) at net/net.c:1051
#4 0x000055baf6960518 in net_client_init (opts=0x55baf776e7e0, is_netdev=true, errp=0x7ffc51368f00) at net/net.c:1108
#5 0x000055baf696083f in netdev_add (opts=0x55baf776e7e0, errp=0x7ffc51368f00) at net/net.c:1186
#6 0x000055baf69608c7 in qmp_netdev_add (qdict=0x55baf7afaf60, ret=0x7ffc51368f50, errp=0x7ffc51368f48) at net/net.c:1205
#7 0x000055baf6622135 in handle_qmp_command (parser=0x55baf77fb590, tokens=0x7f1d24011960) at /path/to/qemu.git/monitor.c:3978
#8 0x000055baf6a9d099 in json_message_process_token (lexer=0x55baf77fb598, input=0x55baf75acd20, type=JSON_RCURLY, x=113, y=19) at qobject/json-streamer.c:105
#9 0x000055baf6abf7aa in json_lexer_feed_char (lexer=0x55baf77fb598, ch=125 '}', flush=false) at qobject/json-lexer.c:319
#10 0x000055baf6abf8f2 in json_lexer_feed (lexer=0x55baf77fb598, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-lexer.c:369
#11 0x000055baf6a9d13c in json_message_parser_feed (parser=0x55baf77fb590, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-streamer.c:124
#12 0x000055baf66221f7 in monitor_qmp_read (opaque=0x55baf77fb530, buf=0x7ffc51369170 "}R\204\367\272U", size=1) at /path/to/qemu.git/monitor.c:3994
#13 0x000055baf6757014 in qemu_chr_be_write_impl (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:387
#14 0x000055baf6757076 in qemu_chr_be_write (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:399
#15 0x000055baf675b3b0 in tcp_chr_read (chan=0x55baf90244b0, cond=G_IO_IN, opaque=0x55baf7610a40) at qemu-char.c:2927
#16 0x000055baf6a5d655 in qio_channel_fd_source_dispatch (source=0x55baf7610df0, callback=0x55baf675b25a <tcp_chr_read>, user_data=0x55baf7610a40) at io/channel-watch.c:84
#17 0x00007f1d3e80cbbd in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0
#18 0x000055baf69d3720 in glib_pollfds_poll () at main-loop.c:213
#19 0x000055baf69d37fd in os_host_main_loop_wait (timeout=126000000) at main-loop.c:258
#20 0x000055baf69d38ad in main_loop_wait (nonblocking=0) at main-loop.c:506
#21 0x000055baf676587b in main_loop () at vl.c:1908
#22 0x000055baf676d3bf in main (argc=101, argv=0x7ffc5136a6c8, envp=0x7ffc5136a9f8) at vl.c:4604
(gdb) p opts
$1 = (QemuOpts *) 0x0
The crash occurred when attaching vhost-user net via QMP:
{
"execute": "chardev-add",
"arguments": {
"id": "charnet2",
"backend": {
"type": "socket",
"data": {
"addr": {
"type": "unix",
"data": {
"path": "/var/run/openvswitch/vhost-user1"
}
},
"wait": false,
"server": false
}
}
},
"id": "libvirt-19"
}
{
"return": {
},
"id": "libvirt-19"
}
{
"execute": "netdev_add",
"arguments": {
"type": "vhost-user",
"chardev": "charnet2",
"id": "hostnet2"
},
"id": "libvirt-20"
}
Code using chardevs should not be poking at the internals of the
CharDriverState struct. What vhost-user wants is a chardev that is
operating as reconnectable network service, along with the ability
to do FD passing over the connection. The colo code simply wants
a network service. Add a feature concept to the char drivers so
that chardev users can query the actual features they wish to have
supported. The QemuOpts member is removed to prevent future mistakes
in this area.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-10-07 14:18:34 +02:00
|
|
|
qemu_opts_del(opts);
|
2008-10-31 19:49:55 +01:00
|
|
|
return chr;
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *qemu_chr_new(const char *label, const char *filename)
|
2016-03-14 08:44:36 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr;
|
2016-10-22 11:52:46 +02:00
|
|
|
chr = qemu_chr_new_noreplay(label, filename);
|
2016-03-14 08:44:36 +01:00
|
|
|
if (chr) {
|
2016-10-21 21:58:45 +02:00
|
|
|
if (replay_mode != REPLAY_MODE_NONE) {
|
|
|
|
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
|
|
|
|
}
|
2016-12-07 16:39:10 +01:00
|
|
|
if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
|
2016-11-30 19:57:24 +01:00
|
|
|
error_report("Replay: ioctl is not supported "
|
|
|
|
"for serial devices yet");
|
2016-03-14 08:44:36 +01:00
|
|
|
}
|
|
|
|
replay_register_char_driver(chr);
|
|
|
|
}
|
|
|
|
return chr;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
|
2010-12-23 13:42:48 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr = be->chr;
|
2016-10-22 11:52:55 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (chr && CHARDEV_GET_CLASS(chr)->chr_set_echo) {
|
|
|
|
CHARDEV_GET_CLASS(chr)->chr_set_echo(chr, echo);
|
2010-12-23 13:42:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
|
2011-03-24 11:12:02 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr = be->chr;
|
2016-10-22 11:52:55 +02:00
|
|
|
|
2016-10-22 11:52:59 +02:00
|
|
|
if (!chr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-22 12:09:37 +02:00
|
|
|
if (be->fe_open == fe_open) {
|
2013-03-26 11:07:55 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-10-22 12:09:37 +02:00
|
|
|
be->fe_open = fe_open;
|
2016-12-07 16:39:10 +01:00
|
|
|
if (CHARDEV_GET_CLASS(chr)->chr_set_fe_open) {
|
|
|
|
CHARDEV_GET_CLASS(chr)->chr_set_fe_open(chr, fe_open);
|
2011-03-24 11:12:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
|
2016-06-20 15:02:40 +02:00
|
|
|
GIOFunc func, void *user_data)
|
2013-03-05 18:51:23 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *s = be->chr;
|
2013-03-05 18:51:23 +01:00
|
|
|
GSource *src;
|
|
|
|
guint tag;
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (!s || CHARDEV_GET_CLASS(s)->chr_add_watch == NULL) {
|
2016-06-20 15:02:40 +02:00
|
|
|
return 0;
|
2013-03-05 18:51:23 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
src = CHARDEV_GET_CLASS(s)->chr_add_watch(s, cond);
|
2014-07-24 16:08:04 +02:00
|
|
|
if (!src) {
|
2016-06-20 15:02:40 +02:00
|
|
|
return 0;
|
2014-07-24 16:08:04 +02:00
|
|
|
}
|
|
|
|
|
2013-03-05 18:51:23 +01:00
|
|
|
g_source_set_callback(src, (GSourceFunc)func, user_data, NULL);
|
|
|
|
tag = g_source_attach(src, NULL);
|
|
|
|
g_source_unref(src);
|
|
|
|
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
void qemu_chr_fe_disconnect(CharBackend *be)
|
2016-06-06 18:45:02 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr = be->chr;
|
2016-10-22 11:52:55 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
if (chr && CHARDEV_GET_CLASS(chr)->chr_disconnect) {
|
|
|
|
CHARDEV_GET_CLASS(chr)->chr_disconnect(chr);
|
2016-06-06 18:45:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
void qemu_chr_delete(Chardev *chr)
|
2015-06-22 18:20:18 +02:00
|
|
|
{
|
|
|
|
QTAILQ_REMOVE(&chardevs, chr, next);
|
2016-12-08 17:35:01 +01:00
|
|
|
object_unref(OBJECT(chr));
|
2015-06-22 18:20:18 +02:00
|
|
|
}
|
|
|
|
|
2011-09-14 21:05:49 +02:00
|
|
|
ChardevInfoList *qmp_query_chardev(Error **errp)
|
2008-10-31 19:49:55 +01:00
|
|
|
{
|
2011-09-14 21:05:49 +02:00
|
|
|
ChardevInfoList *chr_list = NULL;
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr;
|
2008-10-31 19:49:55 +01:00
|
|
|
|
2009-09-12 09:36:22 +02:00
|
|
|
QTAILQ_FOREACH(chr, &chardevs, next) {
|
2011-09-14 21:05:49 +02:00
|
|
|
ChardevInfoList *info = g_malloc0(sizeof(*info));
|
|
|
|
info->value = g_malloc0(sizeof(*info->value));
|
|
|
|
info->value->label = g_strdup(chr->label);
|
|
|
|
info->value->filename = g_strdup(chr->filename);
|
2016-10-22 12:09:37 +02:00
|
|
|
info->value->frontend_open = chr->be && chr->be->fe_open;
|
2011-09-14 21:05:49 +02:00
|
|
|
|
|
|
|
info->next = chr_list;
|
|
|
|
chr_list = info;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
2009-12-10 20:16:08 +01:00
|
|
|
|
2011-09-14 21:05:49 +02:00
|
|
|
return chr_list;
|
2008-10-31 19:49:55 +01:00
|
|
|
}
|
2009-09-10 10:58:52 +02:00
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
static void
|
|
|
|
qmp_prepend_backend(const char *name, void *opaque)
|
2016-10-21 15:07:45 +02:00
|
|
|
{
|
2016-12-08 22:50:12 +01:00
|
|
|
ChardevBackendInfoList **list = opaque;
|
2016-10-21 15:07:45 +02:00
|
|
|
ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
|
2016-12-08 22:50:12 +01:00
|
|
|
|
2016-10-21 15:07:45 +02:00
|
|
|
info->value = g_malloc0(sizeof(*info->value));
|
|
|
|
info->value->name = g_strdup(name);
|
2016-12-08 22:50:12 +01:00
|
|
|
info->next = *list;
|
|
|
|
*list = info;
|
2016-10-21 15:07:45 +02:00
|
|
|
}
|
|
|
|
|
2014-02-01 12:52:42 +01:00
|
|
|
ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
|
|
|
|
{
|
|
|
|
ChardevBackendInfoList *backend_list = NULL;
|
2016-10-21 15:30:29 +02:00
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
chardev_name_foreach(qmp_prepend_backend, &backend_list);
|
2014-02-01 12:52:42 +01:00
|
|
|
|
|
|
|
return backend_list;
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *qemu_chr_find(const char *name)
|
2009-09-10 10:58:52 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr;
|
2009-09-10 10:58:52 +02:00
|
|
|
|
2009-09-12 09:36:22 +02:00
|
|
|
QTAILQ_FOREACH(chr, &chardevs, next) {
|
2009-09-10 10:58:52 +02:00
|
|
|
if (strcmp(chr->label, name) != 0)
|
|
|
|
continue;
|
|
|
|
return chr;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-12-22 22:29:25 +01:00
|
|
|
|
2012-11-26 16:03:42 +01:00
|
|
|
QemuOptsList qemu_chardev_opts = {
|
|
|
|
.name = "chardev",
|
|
|
|
.implied_opt_name = "backend",
|
|
|
|
.head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
|
|
|
|
.desc = {
|
|
|
|
{
|
|
|
|
.name = "backend",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "path",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "host",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "port",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "localaddr",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "localport",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "to",
|
|
|
|
.type = QEMU_OPT_NUMBER,
|
|
|
|
},{
|
|
|
|
.name = "ipv4",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
|
|
|
},{
|
|
|
|
.name = "ipv6",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
|
|
|
},{
|
|
|
|
.name = "wait",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
|
|
|
},{
|
|
|
|
.name = "server",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
|
|
|
},{
|
|
|
|
.name = "delay",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
2014-10-02 18:17:37 +02:00
|
|
|
},{
|
|
|
|
.name = "reconnect",
|
|
|
|
.type = QEMU_OPT_NUMBER,
|
2012-11-26 16:03:42 +01:00
|
|
|
},{
|
|
|
|
.name = "telnet",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
char: introduce support for TLS encrypted TCP chardev backend
This integrates support for QIOChannelTLS object in the TCP
chardev backend. If the 'tls-creds=NAME' option is passed with
the '-chardev tcp' argument, then it will setup the chardev
such that the client is required to establish a TLS handshake
when connecting. There is no support for checking the client
certificate against ACLs in this initial patch. This is pending
work to QOM-ify the ACL object code.
A complete invocation to run QEMU as the server for a TLS
encrypted serial dev might be
$ qemu-system-x86_64 \
-nodefconfig -nodefaults -device sga -display none \
-chardev socket,id=s0,host=127.0.0.1,port=9000,tls-creds=tls0,server \
-device isa-serial,chardev=s0 \
-object tls-creds-x509,id=tls0,endpoint=server,verify-peer=off,\
dir=/home/berrange/security/qemutls
To test with the gnutls-cli tool as the client:
$ gnutls-cli --priority=NORMAL -p 9000 \
--x509cafile=/home/berrange/security/qemutls/ca-cert.pem \
127.0.0.1
If QEMU was told to use 'anon' credential type, then use the
priority string 'NORMAL:+ANON-DH' with gnutls-cli
Alternatively, if setting up a chardev to operate as a client,
then the TLS credentials registered must be for the client
endpoint. First a TLS server must be setup, which can be done
with the gnutls-serv tool
$ gnutls-serv --priority=NORMAL -p 9000 --echo \
--x509cafile=/home/berrange/security/qemutls/ca-cert.pem \
--x509certfile=/home/berrange/security/qemutls/server-cert.pem \
--x509keyfile=/home/berrange/security/qemutls/server-key.pem
Then QEMU can connect with
$ qemu-system-x86_64 \
-nodefconfig -nodefaults -device sga -display none \
-chardev socket,id=s0,host=127.0.0.1,port=9000,tls-creds=tls0 \
-device isa-serial,chardev=s0 \
-object tls-creds-x509,id=tls0,endpoint=client,\
dir=/home/berrange/security/qemutls
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1453202071-10289-5-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-19 12:14:31 +01:00
|
|
|
},{
|
|
|
|
.name = "tls-creds",
|
|
|
|
.type = QEMU_OPT_STRING,
|
2012-11-26 16:03:42 +01:00
|
|
|
},{
|
|
|
|
.name = "width",
|
|
|
|
.type = QEMU_OPT_NUMBER,
|
|
|
|
},{
|
|
|
|
.name = "height",
|
|
|
|
.type = QEMU_OPT_NUMBER,
|
|
|
|
},{
|
|
|
|
.name = "cols",
|
|
|
|
.type = QEMU_OPT_NUMBER,
|
|
|
|
},{
|
|
|
|
.name = "rows",
|
|
|
|
.type = QEMU_OPT_NUMBER,
|
|
|
|
},{
|
|
|
|
.name = "mux",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
|
|
|
},{
|
|
|
|
.name = "signal",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
|
|
|
},{
|
|
|
|
.name = "name",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "debug",
|
|
|
|
.type = QEMU_OPT_NUMBER,
|
2013-01-24 17:03:19 +01:00
|
|
|
},{
|
qemu-char: Saner naming of memchar stuff & doc fixes
New device, has never been released, so we can still improve things
without worrying about compatibility.
Naming is a mess. The code calls the device driver CirMemCharDriver,
the public API calls it "memory", "memchardev", or "memchar", and the
special commands are named like "memchar-FOO". "memory" is a
particularly unfortunate choice, because there's another character
device driver called MemoryDriver. Moreover, the device's distinctive
property is that it's a ring buffer, not that's in memory. Therefore:
* Rename CirMemCharDriver to RingBufCharDriver, and call the thing a
"ringbuf" in the API.
* Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO.
* Rename device parameter from maxcapacity to size (simple words are
good for you).
* Clearly mark the parameter as optional in documentation.
* Fix error reporting so that chardev-add reports to current monitor,
not stderr.
* Replace cirmem in C identifiers by ringbuf.
* Rework documentation. Document the impact of our crappy UTF-8
handling on reading.
* QMP examples that even work.
I could split this up into multiple commits, but they'd change the
same documentation lines multiple times. Not worth it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-06 21:27:24 +01:00
|
|
|
.name = "size",
|
2013-02-06 21:27:25 +01:00
|
|
|
.type = QEMU_OPT_SIZE,
|
2013-06-24 08:39:54 +02:00
|
|
|
},{
|
|
|
|
.name = "chardev",
|
|
|
|
.type = QEMU_OPT_STRING,
|
2015-12-04 07:42:04 +01:00
|
|
|
},{
|
|
|
|
.name = "append",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
qemu-char: add logfile facility to all chardev backends
Typically a UNIX guest OS will log boot messages to a serial
port in addition to any graphical console. An admin user
may also wish to use the serial port for an interactive
console. A virtualization management system may wish to
collect system boot messages by logging the serial port,
but also wish to allow admins interactive access.
Currently providing such a feature forces the mgmt app
to either provide 2 separate serial ports, one for
logging boot messages and one for interactive console
login, or to proxy all output via a separate service
that can multiplex the two needs onto one serial port.
While both are valid approaches, they each have their
own downsides. The former causes confusion and extra
setup work for VM admins creating disk images. The latter
places an extra burden to re-implement much of the QEMU
chardev backends logic in libvirt or even higher level
mgmt apps and adds extra hops in the data transfer path.
A simpler approach that is satisfactory for many use
cases is to allow the QEMU chardev backends to have a
"logfile" property associated with them.
$QEMU -chardev socket,host=localhost,port=9000,\
server=on,nowait,id-charserial0,\
logfile=/var/log/libvirt/qemu/test-serial0.log
-device isa-serial,chardev=charserial0,id=serial0
This patch introduces a 'ChardevCommon' struct which
is setup as a base for all the ChardevBackend types.
Ideally this would be registered directly as a base
against ChardevBackend, rather than each type, but
the QAPI generator doesn't allow that since the
ChardevBackend is a non-discriminated union. The
ChardevCommon struct provides the optional 'logfile'
parameter, as well as 'logappend' which controls
whether QEMU truncates or appends (default truncate).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1452516281-27519-1-git-send-email-berrange@redhat.com>
[Call qemu_chr_parse_common if cd->parse is NULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-01-11 13:44:41 +01:00
|
|
|
},{
|
|
|
|
.name = "logfile",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "logappend",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
2012-11-26 16:03:42 +01:00
|
|
|
},
|
|
|
|
{ /* end of list */ }
|
|
|
|
},
|
|
|
|
};
|
2012-12-19 10:33:56 +01:00
|
|
|
|
2012-12-19 13:13:57 +01:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qmp_chardev_open_serial(Chardev *chr,
|
|
|
|
ChardevBackend *backend,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2012-12-19 13:50:29 +01:00
|
|
|
{
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
ChardevHostdev *serial = backend->u.serial.data;
|
2016-10-21 21:09:15 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
win_chr_init(chr, serial->device, errp);
|
2013-02-13 15:54:16 +01:00
|
|
|
}
|
|
|
|
|
2012-12-19 13:13:57 +01:00
|
|
|
#else /* WIN32 */
|
|
|
|
|
2015-10-12 09:46:23 +02:00
|
|
|
#ifdef HAVE_CHARDEV_SERIAL
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qmp_chardev_open_serial(Chardev *chr,
|
|
|
|
ChardevBackend *backend,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2012-12-19 13:50:29 +01:00
|
|
|
{
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
ChardevHostdev *serial = backend->u.serial.data;
|
2013-02-13 15:54:16 +01:00
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
|
2014-05-19 18:57:34 +02:00
|
|
|
if (fd < 0) {
|
2016-12-07 16:39:10 +01:00
|
|
|
return;
|
2013-01-24 17:14:39 +01:00
|
|
|
}
|
2013-03-27 10:10:43 +01:00
|
|
|
qemu_set_nonblock(fd);
|
2016-10-21 21:09:15 +02:00
|
|
|
tty_serial_init(fd, 115200, 'N', 8, 1);
|
2016-10-21 19:49:37 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
qemu_chr_open_fd(chr, fd, fd);
|
2013-02-13 15:54:16 +01:00
|
|
|
}
|
2015-09-29 15:08:05 +02:00
|
|
|
#endif
|
2013-02-13 15:54:16 +01:00
|
|
|
|
2015-10-12 09:46:23 +02:00
|
|
|
#ifdef HAVE_CHARDEV_PARPORT
|
2016-12-07 16:39:10 +01:00
|
|
|
static void qmp_chardev_open_parallel(Chardev *chr,
|
|
|
|
ChardevBackend *backend,
|
|
|
|
bool *be_opened,
|
|
|
|
Error **errp)
|
2013-02-13 15:54:16 +01:00
|
|
|
{
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
ChardevHostdev *parallel = backend->u.parallel.data;
|
2013-02-13 15:54:16 +01:00
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
|
2014-05-19 18:57:34 +02:00
|
|
|
if (fd < 0) {
|
2016-12-07 16:39:10 +01:00
|
|
|
return;
|
2012-12-19 13:50:29 +01:00
|
|
|
}
|
2016-12-07 16:39:10 +01:00
|
|
|
qemu_chr_open_pp_fd(chr, fd, be_opened, errp);
|
2012-12-19 13:50:29 +01:00
|
|
|
}
|
2016-10-21 19:49:37 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static void char_parallel_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
cc->parse = qemu_chr_parse_parallel;
|
2016-12-07 16:39:10 +01:00
|
|
|
cc->open = qmp_chardev_open_parallel;
|
2016-10-21 19:49:37 +02:00
|
|
|
#if defined(__linux__)
|
2016-12-07 16:39:10 +01:00
|
|
|
cc->chr_ioctl = pp_ioctl;
|
2016-10-21 19:49:37 +02:00
|
|
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
2016-12-07 16:39:10 +01:00
|
|
|
cc->chr_ioctl = pp_ioctl;
|
2016-10-21 19:49:37 +02:00
|
|
|
#endif
|
2016-12-07 16:39:10 +01:00
|
|
|
}
|
|
|
|
|
2016-12-08 15:57:35 +01:00
|
|
|
static void char_parallel_finalize(Object *obj)
|
|
|
|
{
|
|
|
|
#if defined(__linux__)
|
|
|
|
Chardev *chr = CHARDEV(obj);
|
|
|
|
ParallelChardev *drv = PARALLEL_CHARDEV(chr);
|
|
|
|
int fd = drv->fd;
|
|
|
|
|
|
|
|
pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
|
|
|
|
ioctl(fd, PPRELEASE);
|
|
|
|
close(fd);
|
|
|
|
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
|
|
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
|
|
|
/* FIXME: close fd? */
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
static const TypeInfo char_parallel_type_info = {
|
|
|
|
.name = TYPE_CHARDEV_PARALLEL,
|
|
|
|
.parent = TYPE_CHARDEV,
|
|
|
|
.instance_size = sizeof(ParallelChardev),
|
2016-12-08 15:57:35 +01:00
|
|
|
.instance_finalize = char_parallel_finalize,
|
2016-12-07 16:39:10 +01:00
|
|
|
.class_init = char_parallel_class_init,
|
2016-10-21 19:49:37 +02:00
|
|
|
};
|
2015-10-12 09:46:23 +02:00
|
|
|
#endif
|
2012-12-19 13:50:29 +01:00
|
|
|
|
2012-12-19 13:13:57 +01:00
|
|
|
#endif /* WIN32 */
|
|
|
|
|
2016-10-21 19:49:37 +02:00
|
|
|
#ifdef HAVE_CHARDEV_SERIAL
|
2016-12-07 16:39:10 +01:00
|
|
|
|
|
|
|
static void char_serial_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
|
|
|
|
2016-12-08 22:50:12 +01:00
|
|
|
cc->parse = qemu_chr_parse_serial;
|
2016-12-07 16:39:10 +01:00
|
|
|
cc->open = qmp_chardev_open_serial;
|
|
|
|
#ifndef _WIN32
|
|
|
|
cc->chr_ioctl = tty_serial_ioctl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo char_serial_type_info = {
|
|
|
|
.name = TYPE_CHARDEV_SERIAL,
|
2016-10-21 19:49:37 +02:00
|
|
|
#ifdef _WIN32
|
2016-12-07 16:39:10 +01:00
|
|
|
.parent = TYPE_CHARDEV_WIN,
|
2016-10-21 19:49:37 +02:00
|
|
|
#else
|
2016-12-07 16:39:10 +01:00
|
|
|
.parent = TYPE_CHARDEV_FD,
|
2016-10-21 19:49:37 +02:00
|
|
|
#endif
|
2016-12-07 16:39:10 +01:00
|
|
|
.class_init = char_serial_class_init,
|
2016-10-21 19:49:37 +02:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
bool qemu_chr_has_feature(Chardev *chr,
|
2016-12-14 11:27:58 +01:00
|
|
|
ChardevFeature feature)
|
net: don't poke at chardev internal QemuOpts
The vhost-user & colo code is poking at the QemuOpts instance
in the CharDriverState struct, not realizing that it is valid
for this to be NULL. e.g. the following crash shows a codepath
where it will be NULL:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
617 QTAILQ_FOREACH(opt, &opts->head, next) {
[Current thread is 1 (Thread 0x7f1d4970bb40 (LWP 6603))]
(gdb) bt
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
#1 0x000055baf696b7da in net_vhost_parse_chardev (opts=0x55baf8ff9260, errp=0x7ffc51368e48) at net/vhost-user.c:314
#2 0x000055baf696b985 in net_init_vhost_user (netdev=0x55baf8ff9250, name=0x55baf879d270 "hostnet2", peer=0x0, errp=0x7ffc51368e48) at net/vhost-user.c:360
#3 0x000055baf6960216 in net_client_init1 (object=0x55baf8ff9250, is_netdev=true, errp=0x7ffc51368e48) at net/net.c:1051
#4 0x000055baf6960518 in net_client_init (opts=0x55baf776e7e0, is_netdev=true, errp=0x7ffc51368f00) at net/net.c:1108
#5 0x000055baf696083f in netdev_add (opts=0x55baf776e7e0, errp=0x7ffc51368f00) at net/net.c:1186
#6 0x000055baf69608c7 in qmp_netdev_add (qdict=0x55baf7afaf60, ret=0x7ffc51368f50, errp=0x7ffc51368f48) at net/net.c:1205
#7 0x000055baf6622135 in handle_qmp_command (parser=0x55baf77fb590, tokens=0x7f1d24011960) at /path/to/qemu.git/monitor.c:3978
#8 0x000055baf6a9d099 in json_message_process_token (lexer=0x55baf77fb598, input=0x55baf75acd20, type=JSON_RCURLY, x=113, y=19) at qobject/json-streamer.c:105
#9 0x000055baf6abf7aa in json_lexer_feed_char (lexer=0x55baf77fb598, ch=125 '}', flush=false) at qobject/json-lexer.c:319
#10 0x000055baf6abf8f2 in json_lexer_feed (lexer=0x55baf77fb598, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-lexer.c:369
#11 0x000055baf6a9d13c in json_message_parser_feed (parser=0x55baf77fb590, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-streamer.c:124
#12 0x000055baf66221f7 in monitor_qmp_read (opaque=0x55baf77fb530, buf=0x7ffc51369170 "}R\204\367\272U", size=1) at /path/to/qemu.git/monitor.c:3994
#13 0x000055baf6757014 in qemu_chr_be_write_impl (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:387
#14 0x000055baf6757076 in qemu_chr_be_write (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:399
#15 0x000055baf675b3b0 in tcp_chr_read (chan=0x55baf90244b0, cond=G_IO_IN, opaque=0x55baf7610a40) at qemu-char.c:2927
#16 0x000055baf6a5d655 in qio_channel_fd_source_dispatch (source=0x55baf7610df0, callback=0x55baf675b25a <tcp_chr_read>, user_data=0x55baf7610a40) at io/channel-watch.c:84
#17 0x00007f1d3e80cbbd in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0
#18 0x000055baf69d3720 in glib_pollfds_poll () at main-loop.c:213
#19 0x000055baf69d37fd in os_host_main_loop_wait (timeout=126000000) at main-loop.c:258
#20 0x000055baf69d38ad in main_loop_wait (nonblocking=0) at main-loop.c:506
#21 0x000055baf676587b in main_loop () at vl.c:1908
#22 0x000055baf676d3bf in main (argc=101, argv=0x7ffc5136a6c8, envp=0x7ffc5136a9f8) at vl.c:4604
(gdb) p opts
$1 = (QemuOpts *) 0x0
The crash occurred when attaching vhost-user net via QMP:
{
"execute": "chardev-add",
"arguments": {
"id": "charnet2",
"backend": {
"type": "socket",
"data": {
"addr": {
"type": "unix",
"data": {
"path": "/var/run/openvswitch/vhost-user1"
}
},
"wait": false,
"server": false
}
}
},
"id": "libvirt-19"
}
{
"return": {
},
"id": "libvirt-19"
}
{
"execute": "netdev_add",
"arguments": {
"type": "vhost-user",
"chardev": "charnet2",
"id": "hostnet2"
},
"id": "libvirt-20"
}
Code using chardevs should not be poking at the internals of the
CharDriverState struct. What vhost-user wants is a chardev that is
operating as reconnectable network service, along with the ability
to do FD passing over the connection. The colo code simply wants
a network service. Add a feature concept to the char drivers so
that chardev users can query the actual features they wish to have
supported. The QemuOpts member is removed to prevent future mistakes
in this area.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-10-07 14:18:34 +02:00
|
|
|
{
|
|
|
|
return test_bit(feature, chr->features);
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
void qemu_chr_set_feature(Chardev *chr,
|
2016-12-14 11:27:58 +01:00
|
|
|
ChardevFeature feature)
|
net: don't poke at chardev internal QemuOpts
The vhost-user & colo code is poking at the QemuOpts instance
in the CharDriverState struct, not realizing that it is valid
for this to be NULL. e.g. the following crash shows a codepath
where it will be NULL:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
617 QTAILQ_FOREACH(opt, &opts->head, next) {
[Current thread is 1 (Thread 0x7f1d4970bb40 (LWP 6603))]
(gdb) bt
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
#1 0x000055baf696b7da in net_vhost_parse_chardev (opts=0x55baf8ff9260, errp=0x7ffc51368e48) at net/vhost-user.c:314
#2 0x000055baf696b985 in net_init_vhost_user (netdev=0x55baf8ff9250, name=0x55baf879d270 "hostnet2", peer=0x0, errp=0x7ffc51368e48) at net/vhost-user.c:360
#3 0x000055baf6960216 in net_client_init1 (object=0x55baf8ff9250, is_netdev=true, errp=0x7ffc51368e48) at net/net.c:1051
#4 0x000055baf6960518 in net_client_init (opts=0x55baf776e7e0, is_netdev=true, errp=0x7ffc51368f00) at net/net.c:1108
#5 0x000055baf696083f in netdev_add (opts=0x55baf776e7e0, errp=0x7ffc51368f00) at net/net.c:1186
#6 0x000055baf69608c7 in qmp_netdev_add (qdict=0x55baf7afaf60, ret=0x7ffc51368f50, errp=0x7ffc51368f48) at net/net.c:1205
#7 0x000055baf6622135 in handle_qmp_command (parser=0x55baf77fb590, tokens=0x7f1d24011960) at /path/to/qemu.git/monitor.c:3978
#8 0x000055baf6a9d099 in json_message_process_token (lexer=0x55baf77fb598, input=0x55baf75acd20, type=JSON_RCURLY, x=113, y=19) at qobject/json-streamer.c:105
#9 0x000055baf6abf7aa in json_lexer_feed_char (lexer=0x55baf77fb598, ch=125 '}', flush=false) at qobject/json-lexer.c:319
#10 0x000055baf6abf8f2 in json_lexer_feed (lexer=0x55baf77fb598, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-lexer.c:369
#11 0x000055baf6a9d13c in json_message_parser_feed (parser=0x55baf77fb590, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-streamer.c:124
#12 0x000055baf66221f7 in monitor_qmp_read (opaque=0x55baf77fb530, buf=0x7ffc51369170 "}R\204\367\272U", size=1) at /path/to/qemu.git/monitor.c:3994
#13 0x000055baf6757014 in qemu_chr_be_write_impl (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:387
#14 0x000055baf6757076 in qemu_chr_be_write (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:399
#15 0x000055baf675b3b0 in tcp_chr_read (chan=0x55baf90244b0, cond=G_IO_IN, opaque=0x55baf7610a40) at qemu-char.c:2927
#16 0x000055baf6a5d655 in qio_channel_fd_source_dispatch (source=0x55baf7610df0, callback=0x55baf675b25a <tcp_chr_read>, user_data=0x55baf7610a40) at io/channel-watch.c:84
#17 0x00007f1d3e80cbbd in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0
#18 0x000055baf69d3720 in glib_pollfds_poll () at main-loop.c:213
#19 0x000055baf69d37fd in os_host_main_loop_wait (timeout=126000000) at main-loop.c:258
#20 0x000055baf69d38ad in main_loop_wait (nonblocking=0) at main-loop.c:506
#21 0x000055baf676587b in main_loop () at vl.c:1908
#22 0x000055baf676d3bf in main (argc=101, argv=0x7ffc5136a6c8, envp=0x7ffc5136a9f8) at vl.c:4604
(gdb) p opts
$1 = (QemuOpts *) 0x0
The crash occurred when attaching vhost-user net via QMP:
{
"execute": "chardev-add",
"arguments": {
"id": "charnet2",
"backend": {
"type": "socket",
"data": {
"addr": {
"type": "unix",
"data": {
"path": "/var/run/openvswitch/vhost-user1"
}
},
"wait": false,
"server": false
}
}
},
"id": "libvirt-19"
}
{
"return": {
},
"id": "libvirt-19"
}
{
"execute": "netdev_add",
"arguments": {
"type": "vhost-user",
"chardev": "charnet2",
"id": "hostnet2"
},
"id": "libvirt-20"
}
Code using chardevs should not be poking at the internals of the
CharDriverState struct. What vhost-user wants is a chardev that is
operating as reconnectable network service, along with the ability
to do FD passing over the connection. The colo code simply wants
a network service. Add a feature concept to the char drivers so
that chardev users can query the actual features they wish to have
supported. The QemuOpts member is removed to prevent future mistakes
in this area.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-10-07 14:18:34 +02:00
|
|
|
{
|
|
|
|
return set_bit(feature, chr->features);
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
Chardev *qemu_chardev_new(const char *id, const char *typename,
|
|
|
|
ChardevBackend *backend, Error **errp)
|
2012-12-19 10:33:56 +01:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr = NULL;
|
2015-09-29 14:54:05 +02:00
|
|
|
Error *local_err = NULL;
|
2016-10-22 12:09:43 +02:00
|
|
|
bool be_opened = true;
|
2012-12-19 10:33:56 +01:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
assert(g_str_has_prefix(typename, "chardev-"));
|
2012-12-19 10:33:56 +01:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
chr = CHARDEV(object_new(typename));
|
|
|
|
chr->label = g_strdup(id);
|
2015-09-29 14:55:59 +02:00
|
|
|
|
2016-12-07 16:39:10 +01:00
|
|
|
qemu_char_open(chr, backend, &be_opened, &local_err);
|
2016-10-21 15:30:29 +02:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
2016-12-07 16:39:10 +01:00
|
|
|
object_unref(OBJECT(chr));
|
|
|
|
return NULL;
|
2015-09-29 14:54:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!chr->filename) {
|
2016-12-07 16:39:10 +01:00
|
|
|
chr->filename = g_strdup(typename + 8);
|
2012-12-19 10:33:56 +01:00
|
|
|
}
|
2016-10-22 12:09:43 +02:00
|
|
|
if (be_opened) {
|
2015-09-29 14:54:05 +02:00
|
|
|
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
|
|
|
|
}
|
2016-12-07 16:39:10 +01:00
|
|
|
|
|
|
|
return chr;
|
|
|
|
}
|
|
|
|
|
|
|
|
ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
const ChardevClass *cc;
|
|
|
|
ChardevReturn *ret;
|
|
|
|
Chardev *chr;
|
|
|
|
|
|
|
|
cc = char_get_class(ChardevBackendKind_lookup[backend->type], errp);
|
|
|
|
if (!cc) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-12-09 09:04:51 +01:00
|
|
|
chr = qemu_chardev_add(id, object_class_get_name(OBJECT_CLASS(cc)),
|
2016-12-07 16:39:10 +01:00
|
|
|
backend, errp);
|
|
|
|
if (!chr) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = g_new0(ChardevReturn, 1);
|
|
|
|
if (CHARDEV_IS_PTY(chr)) {
|
|
|
|
ret->pty = g_strdup(chr->filename + 4);
|
|
|
|
ret->has_pty = true;
|
|
|
|
}
|
|
|
|
|
2015-09-29 14:54:05 +02:00
|
|
|
return ret;
|
2012-12-19 10:33:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void qmp_chardev_remove(const char *id, Error **errp)
|
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr;
|
2012-12-19 10:33:56 +01:00
|
|
|
|
|
|
|
chr = qemu_chr_find(id);
|
2014-08-11 15:00:55 +02:00
|
|
|
if (chr == NULL) {
|
2012-12-19 10:33:56 +01:00
|
|
|
error_setg(errp, "Chardev '%s' not found", id);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-22 11:53:01 +02:00
|
|
|
if (qemu_chr_is_busy(chr)) {
|
2012-12-19 10:33:56 +01:00
|
|
|
error_setg(errp, "Chardev '%s' is busy", id);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-21 21:58:45 +02:00
|
|
|
if (qemu_chr_replay(chr)) {
|
2016-03-14 08:44:36 +01:00
|
|
|
error_setg(errp,
|
|
|
|
"Chardev '%s' cannot be unplugged in record/replay mode", id);
|
|
|
|
return;
|
|
|
|
}
|
2012-12-19 10:33:56 +01:00
|
|
|
qemu_chr_delete(chr);
|
|
|
|
}
|
2013-03-05 18:51:28 +01:00
|
|
|
|
char: do not use atexit cleanup handler
It turns out qemu is calling exit() in various places from various
threads without taking much care of resources state. The atexit()
cleanup handlers cannot easily destroy resources that are in use (by
the same thread or other).
Since c1111a24a3, TCG arm guests run into the following abort() when
running tests, the chardev mutex is locked during the write, so
qemu_mutex_destroy() returns an error:
#0 0x00007fffdbb806f5 in raise () at /lib64/libc.so.6
#1 0x00007fffdbb822fa in abort () at /lib64/libc.so.6
#2 0x00005555557616fe in error_exit (err=<optimized out>, msg=msg@entry=0x555555c38c30 <__func__.14622> "qemu_mutex_destroy")
at /home/drjones/code/qemu/util/qemu-thread-posix.c:39
#3 0x0000555555b0be20 in qemu_mutex_destroy (mutex=mutex@entry=0x5555566aa0e0) at /home/drjones/code/qemu/util/qemu-thread-posix.c:57
#4 0x00005555558aab00 in qemu_chr_free_common (chr=0x5555566aa0e0) at /home/drjones/code/qemu/qemu-char.c:4029
#5 0x00005555558b05f9 in qemu_chr_delete (chr=<optimized out>) at /home/drjones/code/qemu/qemu-char.c:4038
#6 0x00005555558b05f9 in qemu_chr_delete (chr=<optimized out>) at /home/drjones/code/qemu/qemu-char.c:4044
#7 0x00005555558b062c in qemu_chr_cleanup () at /home/drjones/code/qemu/qemu-char.c:4557
#8 0x00007fffdbb851e8 in __run_exit_handlers () at /lib64/libc.so.6
#9 0x00007fffdbb85235 in () at /lib64/libc.so.6
#10 0x00005555558d1b39 in testdev_write (testdev=0x5555566aa0a0) at /home/drjones/code/qemu/backends/testdev.c:71
#11 0x00005555558d1b39 in testdev_write (chr=<optimized out>, buf=0x7fffc343fd9a "", len=0) at /home/drjones/code/qemu/backends/testdev.c:95
#12 0x00005555558adced in qemu_chr_fe_write (s=0x5555566aa0e0, buf=buf@entry=0x7fffc343fd98 "0q", len=len@entry=2) at /home/drjones/code/qemu/qemu-char.c:282
Instead of using a atexit() handler, only run the chardev cleanup as
initially proposed at the end of main(), where there are less chances
(hic) of conflicts or other races.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reported-by: Andrew Jones <drjones@redhat.com>
Message-Id: <20160704153823.16879-1-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-07-04 17:38:23 +02:00
|
|
|
void qemu_chr_cleanup(void)
|
2016-06-16 21:28:50 +02:00
|
|
|
{
|
2016-12-07 14:20:22 +01:00
|
|
|
Chardev *chr, *tmp;
|
2016-06-16 21:28:50 +02:00
|
|
|
|
|
|
|
QTAILQ_FOREACH_SAFE(chr, &chardevs, next, tmp) {
|
|
|
|
qemu_chr_delete(chr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-05 18:51:28 +01:00
|
|
|
static void register_types(void)
|
|
|
|
{
|
2016-12-08 22:50:12 +01:00
|
|
|
type_register_static(&char_type_info);
|
2016-10-21 19:49:37 +02:00
|
|
|
#ifdef HAVE_CHARDEV_SERIAL
|
2016-12-08 22:50:12 +01:00
|
|
|
type_register_static(&char_serial_type_info);
|
2015-09-29 15:08:05 +02:00
|
|
|
#endif
|
2015-10-12 09:49:28 +02:00
|
|
|
#ifdef HAVE_CHARDEV_PARPORT
|
2016-12-08 22:50:12 +01:00
|
|
|
type_register_static(&char_parallel_type_info);
|
2015-10-12 09:49:28 +02:00
|
|
|
#endif
|
2015-09-29 15:23:42 +02:00
|
|
|
#ifdef HAVE_CHARDEV_PTY
|
2016-12-08 22:50:12 +01:00
|
|
|
type_register_static(&char_pty_type_info);
|
2015-09-29 15:23:42 +02:00
|
|
|
#endif
|
2015-09-29 15:42:04 +02:00
|
|
|
#ifdef _WIN32
|
2016-12-08 22:50:12 +01:00
|
|
|
type_register_static(&char_console_type_info);
|
2015-09-29 15:42:04 +02:00
|
|
|
#endif
|
2016-12-08 22:50:12 +01:00
|
|
|
type_register_static(&char_pipe_type_info);
|
2016-10-21 15:07:45 +02:00
|
|
|
|
chardev: fix CHR_EVENT_OPENED events for mux chardevs
As of bd5c51ee6c4f1c79cae5ad2516d711a27b4ea8ec, chardevs no longer use
bottom-halves to issue CHR_EVENT_OPENED events. To maintain past
semantics, we instead defer the CHR_EVENT_OPENED events toward the end
of chardev initialization.
For muxes, this isn't good enough, since a range of FEs must be able
to attach to the mux prior to any CHR_EVENT_OPENED being issued, else
each FE will immediately print it's initial output (prompts, banners,
etc.) just prior to us switching to the next FE as part of
initialization.
The is new and confusing behavior for users, as they'll see output for
things like the HMP monitor, even though their the current mux focus
may be a guest serial port with potentially no output.
We fix this by further deferring CHR_EVENT_OPENED events for FEs
associated with muxes until after machine init by flagging mux chardevs
with 'explicit_be_open', which suppresses emission of CHR_EVENT_OPENED
events until we explicitly set the mux as opened later.
Currently, we must defer till after machine init since we potentially
associate FEs with muxes as part of realize (for instance,
serial_isa_realizefn).
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Message-id: 1375207462-8141-1-git-send-email-mdroth@linux.vnet.ibm.com
Cc: qemu-stable@nongnu.org
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-07-30 20:04:22 +02:00
|
|
|
/* this must be done after machine init, since we register FEs with muxes
|
|
|
|
* as part of realize functions like serial_isa_realizefn when -nographic
|
|
|
|
* is specified
|
|
|
|
*/
|
|
|
|
qemu_add_machine_init_done_notifier(&muxes_realize_notify);
|
2013-03-05 18:51:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type_init(register_types);
|