mirror of
https://github.com/qemu/qemu.git
synced 2025-08-08 17:04:34 +00:00
chardev patches
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbtKCeAAoJENro4Ql1lpzlpSAQALQLmMMuzYwUkpC7J5rxvlYv bKpdi3urdXxQ2zG+QDErCQEsJdGefmJkcT236qRyWR2Ol5J0x5aOA/vZO3EDRGbH uEvuaJt0WamPOT8H2JKGfYyp6dT+VvO7ZIJqeCWGFyMy1LJaJR6eYnEjr2Z0eB/J s8MhIPTw5xl4x44Bi9/52nkk3HZlpZF36CvdQA+rGVvz1E/MFbDECgV6xMGMmTPw P95pgK73JWB+B+6IZcEDUrL42xH3SBqm/ty9r8kT45NGui1l6CdwjEck4MDnafdc bsGTMCJn35B0rPx/vPd9M/ocw4q1Ql2ErvOiMo6Kx6d98Y7O7+jf1NF3uZfT19fc Y1/ysv2a7BMHF81iJcR4xYQGs5s1xenxm2pK1A1dxz5Ltwbw/3ns+sDCkQvZww9q UAc9y+fywmqJVFhX/pF7DLkpeKa2LPviBiJkEKErrrgXv1bU5TcR18NkDcXl4eR6 Mi9mjyx868lotlHOwcbcdZGvrY82HFToxTuU8tleNKsdAE9q8zT9Iocg6Q5xAvH2 2gwW4isY0RvGvhWwabAhOVw1kIsPD2qICzMUZGKtYA6o4whbY4uvxP+EVtKuy8KP OIyMd4YcGvS065QvHzwCu8U9U7eJPZP9cbrn+iP93gBGBHiL+w9hhU10sEiTUYw+ JqwsmDWVhUx9RIdftiZn =xdVN -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/elmarco/tags/chardev-pull-request' into staging chardev patches # gpg: Signature made Wed 03 Oct 2018 11:57:34 BST # gpg: using RSA key DAE8E10975969CE5 # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * remotes/elmarco/tags/chardev-pull-request: chardev: use a child source for qio input source chardev: mark the calls that allow an implicit mux monitor char.h: fix gtk-doc comment style chardev: unref if underlying chardev has no parent chardev: remove qemu_chr_fe_read_all() counter chardev: avoid crash if no associated address Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b8e5671a8c
@ -56,7 +56,7 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
|
|||||||
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
|
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
Chardev *s = be->chr;
|
Chardev *s = be->chr;
|
||||||
int offset = 0, counter = 10;
|
int offset = 0;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
|
if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
|
||||||
@ -88,10 +88,6 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
offset += res;
|
offset += res;
|
||||||
|
|
||||||
if (!counter--) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
|
if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
|
||||||
@ -239,7 +235,12 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
|
|||||||
d->backends[b->tag] = NULL;
|
d->backends[b->tag] = NULL;
|
||||||
}
|
}
|
||||||
if (del) {
|
if (del) {
|
||||||
object_unparent(OBJECT(b->chr));
|
Object *obj = OBJECT(b->chr);
|
||||||
|
if (obj->parent) {
|
||||||
|
object_unparent(obj);
|
||||||
|
} else {
|
||||||
|
object_unref(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
b->chr = NULL;
|
b->chr = NULL;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ typedef struct IOWatchPoll {
|
|||||||
IOCanReadHandler *fd_can_read;
|
IOCanReadHandler *fd_can_read;
|
||||||
GSourceFunc fd_read;
|
GSourceFunc fd_read;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
GMainContext *context;
|
|
||||||
} IOWatchPoll;
|
} IOWatchPoll;
|
||||||
|
|
||||||
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
|
static IOWatchPoll *io_watch_poll_from_source(GSource *source)
|
||||||
@ -55,47 +54,24 @@ static gboolean io_watch_poll_prepare(GSource *source,
|
|||||||
iwp->src = qio_channel_create_watch(
|
iwp->src = qio_channel_create_watch(
|
||||||
iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
|
iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
|
||||||
g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
|
g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
|
||||||
g_source_attach(iwp->src, iwp->context);
|
g_source_add_child_source(source, iwp->src);
|
||||||
} else {
|
|
||||||
g_source_destroy(iwp->src);
|
|
||||||
g_source_unref(iwp->src);
|
g_source_unref(iwp->src);
|
||||||
|
} else {
|
||||||
|
g_source_remove_child_source(source, iwp->src);
|
||||||
iwp->src = NULL;
|
iwp->src = NULL;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean io_watch_poll_check(GSource *source)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
|
static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
abort();
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
|
||||||
|
|
||||||
static void io_watch_poll_finalize(GSource *source)
|
|
||||||
{
|
|
||||||
/* Due to a glib bug, removing the last reference to a source
|
|
||||||
* inside a finalize callback causes recursive locking (and a
|
|
||||||
* deadlock). This is not a problem inside other callbacks,
|
|
||||||
* including dispatch callbacks, so we call io_remove_watch_poll
|
|
||||||
* to remove this source. At this point, iwp->src must
|
|
||||||
* be NULL, or we would leak it.
|
|
||||||
*
|
|
||||||
* This would be solved much more elegantly by child sources,
|
|
||||||
* but we support older glib versions that do not have them.
|
|
||||||
*/
|
|
||||||
IOWatchPoll *iwp = io_watch_poll_from_source(source);
|
|
||||||
assert(iwp->src == NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GSourceFuncs io_watch_poll_funcs = {
|
static GSourceFuncs io_watch_poll_funcs = {
|
||||||
.prepare = io_watch_poll_prepare,
|
.prepare = io_watch_poll_prepare,
|
||||||
.check = io_watch_poll_check,
|
|
||||||
.dispatch = io_watch_poll_dispatch,
|
.dispatch = io_watch_poll_dispatch,
|
||||||
.finalize = io_watch_poll_finalize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GSource *io_add_watch_poll(Chardev *chr,
|
GSource *io_add_watch_poll(Chardev *chr,
|
||||||
@ -115,7 +91,6 @@ GSource *io_add_watch_poll(Chardev *chr,
|
|||||||
iwp->ioc = ioc;
|
iwp->ioc = ioc;
|
||||||
iwp->fd_read = (GSourceFunc) fd_read;
|
iwp->fd_read = (GSourceFunc) fd_read;
|
||||||
iwp->src = NULL;
|
iwp->src = NULL;
|
||||||
iwp->context = context;
|
|
||||||
|
|
||||||
name = g_strdup_printf("chardev-iowatch-%s", chr->label);
|
name = g_strdup_printf("chardev-iowatch-%s", chr->label);
|
||||||
g_source_set_name((GSource *)iwp, name);
|
g_source_set_name((GSource *)iwp, name);
|
||||||
@ -126,23 +101,10 @@ GSource *io_add_watch_poll(Chardev *chr,
|
|||||||
return (GSource *)iwp;
|
return (GSource *)iwp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void io_remove_watch_poll(GSource *source)
|
|
||||||
{
|
|
||||||
IOWatchPoll *iwp;
|
|
||||||
|
|
||||||
iwp = io_watch_poll_from_source(source);
|
|
||||||
if (iwp->src) {
|
|
||||||
g_source_destroy(iwp->src);
|
|
||||||
g_source_unref(iwp->src);
|
|
||||||
iwp->src = NULL;
|
|
||||||
}
|
|
||||||
g_source_destroy(&iwp->parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_fd_in_watch(Chardev *chr)
|
void remove_fd_in_watch(Chardev *chr)
|
||||||
{
|
{
|
||||||
if (chr->gsource) {
|
if (chr->gsource) {
|
||||||
io_remove_watch_poll(chr->gsource);
|
g_source_destroy(chr->gsource);
|
||||||
chr->gsource = NULL;
|
chr->gsource = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,8 +423,12 @@ static void update_disconnected_filename(SocketChardev *s)
|
|||||||
Chardev *chr = CHARDEV(s);
|
Chardev *chr = CHARDEV(s);
|
||||||
|
|
||||||
g_free(chr->filename);
|
g_free(chr->filename);
|
||||||
chr->filename = SocketAddress_to_str("disconnected:", s->addr,
|
if (s->addr) {
|
||||||
s->is_listen, s->is_telnet);
|
chr->filename = SocketAddress_to_str("disconnected:", s->addr,
|
||||||
|
s->is_listen, s->is_telnet);
|
||||||
|
} else {
|
||||||
|
chr->filename = g_strdup("disconnected:socket");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NB may be called even if tcp_chr_connect has not been
|
/* NB may be called even if tcp_chr_connect has not been
|
||||||
|
@ -329,7 +329,8 @@ int qemu_chr_wait_connected(Chardev *chr, Error **errp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
|
||||||
|
bool permit_mux_mon)
|
||||||
{
|
{
|
||||||
char host[65], port[33], width[8], height[8];
|
char host[65], port[33], width[8], height[8];
|
||||||
int pos;
|
int pos;
|
||||||
@ -344,6 +345,10 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strstart(filename, "mon:", &p)) {
|
if (strstart(filename, "mon:", &p)) {
|
||||||
|
if (!permit_mux_mon) {
|
||||||
|
error_report("mon: isn't supported in this context");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
filename = p;
|
filename = p;
|
||||||
qemu_opt_set(opts, "mux", "on", &error_abort);
|
qemu_opt_set(opts, "mux", "on", &error_abort);
|
||||||
if (strcmp(filename, "stdio") == 0) {
|
if (strcmp(filename, "stdio") == 0) {
|
||||||
@ -683,7 +688,8 @@ out:
|
|||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename)
|
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
|
||||||
|
bool permit_mux_mon)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
Chardev *chr;
|
Chardev *chr;
|
||||||
@ -694,25 +700,32 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename)
|
|||||||
return qemu_chr_find(p);
|
return qemu_chr_find(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = qemu_chr_parse_compat(label, filename);
|
opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
|
||||||
if (!opts)
|
if (!opts)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
chr = qemu_chr_new_from_opts(opts, &err);
|
chr = qemu_chr_new_from_opts(opts, &err);
|
||||||
if (err) {
|
if (!chr) {
|
||||||
error_report_err(err);
|
error_report_err(err);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
|
|
||||||
|
if (qemu_opt_get_bool(opts, "mux", 0)) {
|
||||||
|
assert(permit_mux_mon);
|
||||||
monitor_init(chr, MONITOR_USE_READLINE);
|
monitor_init(chr, MONITOR_USE_READLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chardev *qemu_chr_new(const char *label, const char *filename)
|
static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
|
||||||
|
const char *filename,
|
||||||
|
bool permit_mux_mon)
|
||||||
{
|
{
|
||||||
Chardev *chr;
|
Chardev *chr;
|
||||||
chr = qemu_chr_new_noreplay(label, filename);
|
chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon);
|
||||||
if (chr) {
|
if (chr) {
|
||||||
if (replay_mode != REPLAY_MODE_NONE) {
|
if (replay_mode != REPLAY_MODE_NONE) {
|
||||||
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
|
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
|
||||||
@ -726,6 +739,16 @@ Chardev *qemu_chr_new(const char *label, const char *filename)
|
|||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Chardev *qemu_chr_new(const char *label, const char *filename)
|
||||||
|
{
|
||||||
|
return qemu_chr_new_permit_mux_mon(label, filename, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename)
|
||||||
|
{
|
||||||
|
return qemu_chr_new_permit_mux_mon(label, filename, true);
|
||||||
|
}
|
||||||
|
|
||||||
static int qmp_query_chardev_foreach(Object *obj, void *data)
|
static int qmp_query_chardev_foreach(Object *obj, void *data)
|
||||||
{
|
{
|
||||||
Chardev *chr = CHARDEV(obj);
|
Chardev *chr = CHARDEV(obj);
|
||||||
|
@ -2038,7 +2038,11 @@ int gdbserver_start(const char *device)
|
|||||||
sigaction(SIGINT, &act, NULL);
|
sigaction(SIGINT, &act, NULL);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
chr = qemu_chr_new_noreplay("gdb", device);
|
/*
|
||||||
|
* FIXME: it's a bit weird to allow using a mux chardev here
|
||||||
|
* and implicitly setup a monitor. We may want to break this.
|
||||||
|
*/
|
||||||
|
chr = qemu_chr_new_noreplay("gdb", device, true);
|
||||||
if (!chr)
|
if (!chr)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,11 @@ static int con_init(struct XenDevice *xendev)
|
|||||||
} else {
|
} else {
|
||||||
snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
|
snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
|
||||||
qemu_chr_fe_init(&con->chr,
|
qemu_chr_fe_init(&con->chr,
|
||||||
qemu_chr_new(label, output), &error_abort);
|
/*
|
||||||
|
* FIXME: sure we want to support implicit
|
||||||
|
* muxed monitors here?
|
||||||
|
*/
|
||||||
|
qemu_chr_new_mux_mon(label, output), &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
xenstore_store_pv_console_info(con->xendev.dev,
|
xenstore_store_pv_console_info(con->xendev.dev,
|
||||||
|
@ -20,7 +20,7 @@ struct CharBackend {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_init:
|
* qemu_chr_fe_init:
|
||||||
*
|
*
|
||||||
* Initializes a front end for the given CharBackend and
|
* Initializes a front end for the given CharBackend and
|
||||||
* Chardev. Call qemu_chr_fe_deinit() to remove the association and
|
* Chardev. Call qemu_chr_fe_deinit() to remove the association and
|
||||||
@ -31,7 +31,7 @@ struct CharBackend {
|
|||||||
bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp);
|
bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_deinit:
|
* qemu_chr_fe_deinit:
|
||||||
* @b: a CharBackend
|
* @b: a CharBackend
|
||||||
* @del: if true, delete the chardev backend
|
* @del: if true, delete the chardev backend
|
||||||
*
|
*
|
||||||
@ -42,9 +42,9 @@ bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp);
|
|||||||
void qemu_chr_fe_deinit(CharBackend *b, bool del);
|
void qemu_chr_fe_deinit(CharBackend *b, bool del);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_get_driver:
|
* qemu_chr_fe_get_driver:
|
||||||
*
|
*
|
||||||
* Returns the driver associated with a CharBackend or NULL if no
|
* Returns: the driver associated with a CharBackend or NULL if no
|
||||||
* associated Chardev.
|
* associated Chardev.
|
||||||
* Note: avoid this function as the driver should never be accessed directly,
|
* Note: avoid this function as the driver should never be accessed directly,
|
||||||
* especially by the frontends that support chardevice hotswap.
|
* especially by the frontends that support chardevice hotswap.
|
||||||
@ -53,21 +53,21 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del);
|
|||||||
Chardev *qemu_chr_fe_get_driver(CharBackend *be);
|
Chardev *qemu_chr_fe_get_driver(CharBackend *be);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_backend_connected:
|
* qemu_chr_fe_backend_connected:
|
||||||
*
|
*
|
||||||
* Returns true if there is a chardevice associated with @be.
|
* Returns: true if there is a chardevice associated with @be.
|
||||||
*/
|
*/
|
||||||
bool qemu_chr_fe_backend_connected(CharBackend *be);
|
bool qemu_chr_fe_backend_connected(CharBackend *be);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_backend_open:
|
* qemu_chr_fe_backend_open:
|
||||||
*
|
*
|
||||||
* Returns true if chardevice associated with @be is open.
|
* Returns: true if chardevice associated with @be is open.
|
||||||
*/
|
*/
|
||||||
bool qemu_chr_fe_backend_open(CharBackend *be);
|
bool qemu_chr_fe_backend_open(CharBackend *be);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_set_handlers:
|
* qemu_chr_fe_set_handlers:
|
||||||
* @b: a CharBackend
|
* @b: a CharBackend
|
||||||
* @fd_can_read: callback to get the amount of data the frontend may
|
* @fd_can_read: callback to get the amount of data the frontend may
|
||||||
* receive
|
* receive
|
||||||
@ -95,7 +95,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
|||||||
bool set_open);
|
bool set_open);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_take_focus:
|
* qemu_chr_fe_take_focus:
|
||||||
*
|
*
|
||||||
* Take the focus (if the front end is muxed).
|
* Take the focus (if the front end is muxed).
|
||||||
*
|
*
|
||||||
@ -104,14 +104,14 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
|||||||
void qemu_chr_fe_take_focus(CharBackend *b);
|
void qemu_chr_fe_take_focus(CharBackend *b);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_accept_input:
|
* qemu_chr_fe_accept_input:
|
||||||
*
|
*
|
||||||
* Notify that the frontend is ready to receive data
|
* Notify that the frontend is ready to receive data
|
||||||
*/
|
*/
|
||||||
void qemu_chr_fe_accept_input(CharBackend *be);
|
void qemu_chr_fe_accept_input(CharBackend *be);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_disconnect:
|
* qemu_chr_fe_disconnect:
|
||||||
*
|
*
|
||||||
* Close a fd accepted by character backend.
|
* Close a fd accepted by character backend.
|
||||||
* Without associated Chardev, do nothing.
|
* Without associated Chardev, do nothing.
|
||||||
@ -119,7 +119,7 @@ void qemu_chr_fe_accept_input(CharBackend *be);
|
|||||||
void qemu_chr_fe_disconnect(CharBackend *be);
|
void qemu_chr_fe_disconnect(CharBackend *be);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_wait_connected:
|
* qemu_chr_fe_wait_connected:
|
||||||
*
|
*
|
||||||
* Wait for characted backend to be connected, return < 0 on error or
|
* Wait for characted backend to be connected, return < 0 on error or
|
||||||
* if no associated Chardev.
|
* if no associated Chardev.
|
||||||
@ -127,19 +127,18 @@ void qemu_chr_fe_disconnect(CharBackend *be);
|
|||||||
int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
|
int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_set_echo:
|
* qemu_chr_fe_set_echo:
|
||||||
|
* @echo: true to enable echo, false to disable echo
|
||||||
*
|
*
|
||||||
* Ask the backend to override its normal echo setting. This only really
|
* Ask the backend to override its normal echo setting. This only really
|
||||||
* applies to the stdio backend and is used by the QMP server such that you
|
* applies to the stdio backend and is used by the QMP server such that you
|
||||||
* can see what you type if you try to type QMP commands.
|
* can see what you type if you try to type QMP commands.
|
||||||
* Without associated Chardev, do nothing.
|
* Without associated Chardev, do nothing.
|
||||||
*
|
|
||||||
* @echo true to enable echo, false to disable echo
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_fe_set_echo(CharBackend *be, bool echo);
|
void qemu_chr_fe_set_echo(CharBackend *be, bool echo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_set_open:
|
* qemu_chr_fe_set_open:
|
||||||
*
|
*
|
||||||
* Set character frontend open status. This is an indication that the
|
* Set character frontend open status. This is an indication that the
|
||||||
* front end is ready (or not) to begin doing I/O.
|
* front end is ready (or not) to begin doing I/O.
|
||||||
@ -148,83 +147,77 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo);
|
|||||||
void qemu_chr_fe_set_open(CharBackend *be, int fe_open);
|
void qemu_chr_fe_set_open(CharBackend *be, int fe_open);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_printf:
|
* qemu_chr_fe_printf:
|
||||||
|
* @fmt: see #printf
|
||||||
*
|
*
|
||||||
* Write to a character backend using a printf style interface. This
|
* Write to a character backend using a printf style interface. This
|
||||||
* function is thread-safe. It does nothing without associated
|
* function is thread-safe. It does nothing without associated
|
||||||
* Chardev.
|
* Chardev.
|
||||||
*
|
|
||||||
* @fmt see #printf
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
|
void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
|
||||||
GCC_FMT_ATTR(2, 3);
|
GCC_FMT_ATTR(2, 3);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_add_watch:
|
* qemu_chr_fe_add_watch:
|
||||||
|
* @cond: the condition to poll for
|
||||||
|
* @func: the function to call when the condition happens
|
||||||
|
* @user_data: the opaque pointer to pass to @func
|
||||||
*
|
*
|
||||||
* If the backend is connected, create and add a #GSource that fires
|
* If the backend is connected, create and add a #GSource that fires
|
||||||
* when the given condition (typically G_IO_OUT|G_IO_HUP or G_IO_HUP)
|
* when the given condition (typically G_IO_OUT|G_IO_HUP or G_IO_HUP)
|
||||||
* is active; return the #GSource's tag. If it is disconnected,
|
* is active; return the #GSource's tag. If it is disconnected,
|
||||||
* or without associated Chardev, return 0.
|
* or without associated Chardev, return 0.
|
||||||
*
|
*
|
||||||
* @cond the condition to poll for
|
|
||||||
* @func the function to call when the condition happens
|
|
||||||
* @user_data the opaque pointer to pass to @func
|
|
||||||
*
|
|
||||||
* Returns: the source tag
|
* Returns: the source tag
|
||||||
*/
|
*/
|
||||||
guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
|
guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
|
||||||
GIOFunc func, void *user_data);
|
GIOFunc func, void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_write:
|
* qemu_chr_fe_write:
|
||||||
|
* @buf: the data
|
||||||
|
* @len: the number of bytes to send
|
||||||
*
|
*
|
||||||
* Write data to a character backend from the front end. This function
|
* Write data to a character backend from the front end. This function
|
||||||
* will send data from the front end to the back end. This function
|
* will send data from the front end to the back end. This function
|
||||||
* is thread-safe.
|
* is thread-safe.
|
||||||
*
|
*
|
||||||
* @buf the data
|
|
||||||
* @len the number of bytes to send
|
|
||||||
*
|
|
||||||
* Returns: the number of bytes consumed (0 if no associated Chardev)
|
* Returns: the number of bytes consumed (0 if no associated Chardev)
|
||||||
*/
|
*/
|
||||||
int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
|
int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_write_all:
|
* qemu_chr_fe_write_all:
|
||||||
|
* @buf: the data
|
||||||
|
* @len: the number of bytes to send
|
||||||
*
|
*
|
||||||
* Write data to a character backend from the front end. This function will
|
* Write data to a character backend from the front end. This function will
|
||||||
* send data from the front end to the back end. Unlike @qemu_chr_fe_write,
|
* send data from the front end to the back end. Unlike @qemu_chr_fe_write,
|
||||||
* this function will block if the back end cannot consume all of the data
|
* this function will block if the back end cannot consume all of the data
|
||||||
* attempted to be written. This function is thread-safe.
|
* attempted to be written. This function is thread-safe.
|
||||||
*
|
*
|
||||||
* @buf the data
|
|
||||||
* @len the number of bytes to send
|
|
||||||
*
|
|
||||||
* Returns: the number of bytes consumed (0 if no associated Chardev)
|
* Returns: the number of bytes consumed (0 if no associated Chardev)
|
||||||
*/
|
*/
|
||||||
int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
|
int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_read_all:
|
* qemu_chr_fe_read_all:
|
||||||
|
* @buf: the data buffer
|
||||||
|
* @len: the number of bytes to read
|
||||||
*
|
*
|
||||||
* Read data to a buffer from the back end.
|
* Read data to a buffer from the back end.
|
||||||
*
|
*
|
||||||
* @buf the data buffer
|
|
||||||
* @len the number of bytes to read
|
|
||||||
*
|
|
||||||
* Returns: the number of bytes read (0 if no associated Chardev)
|
* Returns: the number of bytes read (0 if no associated Chardev)
|
||||||
*/
|
*/
|
||||||
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
|
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_ioctl:
|
* qemu_chr_fe_ioctl:
|
||||||
|
* @cmd: see CHR_IOCTL_*
|
||||||
|
* @arg: the data associated with @cmd
|
||||||
*
|
*
|
||||||
* Issue a device specific ioctl to a backend. This function is thread-safe.
|
* Issue a device specific ioctl to a backend. This function is thread-safe.
|
||||||
*
|
*
|
||||||
* @cmd see CHR_IOCTL_*
|
|
||||||
* @arg the data associated with @cmd
|
|
||||||
*
|
|
||||||
* Returns: if @cmd is not supported by the backend or there is no
|
* Returns: if @cmd is not supported by the backend or there is no
|
||||||
* associated Chardev, -ENOTSUP, otherwise the return
|
* associated Chardev, -ENOTSUP, otherwise the return
|
||||||
* value depends on the semantics of @cmd
|
* value depends on the semantics of @cmd
|
||||||
@ -232,7 +225,7 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
|
|||||||
int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg);
|
int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_get_msgfd:
|
* qemu_chr_fe_get_msgfd:
|
||||||
*
|
*
|
||||||
* For backends capable of fd passing, return the latest file descriptor passed
|
* For backends capable of fd passing, return the latest file descriptor passed
|
||||||
* by a client.
|
* by a client.
|
||||||
@ -245,7 +238,7 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg);
|
|||||||
int qemu_chr_fe_get_msgfd(CharBackend *be);
|
int qemu_chr_fe_get_msgfd(CharBackend *be);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_get_msgfds:
|
* qemu_chr_fe_get_msgfds:
|
||||||
*
|
*
|
||||||
* For backends capable of fd passing, return the number of file received
|
* For backends capable of fd passing, return the number of file received
|
||||||
* descriptors and fills the fds array up to num elements
|
* descriptors and fills the fds array up to num elements
|
||||||
@ -258,7 +251,7 @@ int qemu_chr_fe_get_msgfd(CharBackend *be);
|
|||||||
int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int num);
|
int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int num);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_fe_set_msgfds:
|
* qemu_chr_fe_set_msgfds:
|
||||||
*
|
*
|
||||||
* For backends capable of fd passing, set an array of fds to be passed with
|
* For backends capable of fd passing, set an array of fds to be passed with
|
||||||
* the next send operation.
|
* the next send operation.
|
||||||
|
@ -68,12 +68,11 @@ struct Chardev {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_new_from_opts:
|
* qemu_chr_new_from_opts:
|
||||||
|
* @opts: see qemu-config.c for a list of valid options
|
||||||
*
|
*
|
||||||
* Create a new character backend from a QemuOpts list.
|
* Create a new character backend from a QemuOpts list.
|
||||||
*
|
*
|
||||||
* @opts see qemu-config.c for a list of valid options
|
|
||||||
*
|
|
||||||
* Returns: on success: a new character backend
|
* Returns: on success: a new character backend
|
||||||
* otherwise: NULL; @errp specifies the error
|
* otherwise: NULL; @errp specifies the error
|
||||||
* or left untouched in case of help option
|
* or left untouched in case of help option
|
||||||
@ -82,17 +81,16 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
|||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_parse_common:
|
* qemu_chr_parse_common:
|
||||||
|
* @opts: the options that still need parsing
|
||||||
|
* @backend: a new backend
|
||||||
*
|
*
|
||||||
* Parse the common options available to all character backends.
|
* Parse the common options available to all character backends.
|
||||||
*
|
|
||||||
* @opts the options that still need parsing
|
|
||||||
* @backend a new backend
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
|
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_parse_opts:
|
* qemu_chr_parse_opts:
|
||||||
*
|
*
|
||||||
* Parse the options to the ChardevBackend struct.
|
* Parse the options to the ChardevBackend struct.
|
||||||
*
|
*
|
||||||
@ -102,49 +100,61 @@ ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts,
|
|||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_new:
|
* qemu_chr_new:
|
||||||
|
* @label: the name of the backend
|
||||||
|
* @filename: the URI
|
||||||
*
|
*
|
||||||
* Create a new character backend from a URI.
|
* Create a new character backend from a URI.
|
||||||
*
|
* Do not implicitly initialize a monitor if the chardev is muxed.
|
||||||
* @label the name of the backend
|
|
||||||
* @filename the URI
|
|
||||||
*
|
*
|
||||||
* Returns: a new character backend
|
* Returns: a new character backend
|
||||||
*/
|
*/
|
||||||
Chardev *qemu_chr_new(const char *label, const char *filename);
|
Chardev *qemu_chr_new(const char *label, const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_change:
|
* qemu_chr_new_mux_mon:
|
||||||
|
* @label: the name of the backend
|
||||||
|
* @filename: the URI
|
||||||
|
*
|
||||||
|
* Create a new character backend from a URI.
|
||||||
|
* Implicitly initialize a monitor if the chardev is muxed.
|
||||||
|
*
|
||||||
|
* Returns: a new character backend
|
||||||
|
*/
|
||||||
|
Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemu_chr_change:
|
||||||
|
* @opts: the new backend options
|
||||||
*
|
*
|
||||||
* Change an existing character backend
|
* Change an existing character backend
|
||||||
*
|
|
||||||
* @opts the new backend options
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_change(QemuOpts *opts, Error **errp);
|
void qemu_chr_change(QemuOpts *opts, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_cleanup:
|
* qemu_chr_cleanup:
|
||||||
*
|
*
|
||||||
* Delete all chardevs (when leaving qemu)
|
* Delete all chardevs (when leaving qemu)
|
||||||
*/
|
*/
|
||||||
void qemu_chr_cleanup(void);
|
void qemu_chr_cleanup(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_new_noreplay:
|
* qemu_chr_new_noreplay:
|
||||||
|
* @label: the name of the backend
|
||||||
|
* @filename: the URI
|
||||||
|
* @permit_mux_mon: if chardev is muxed, initialize a monitor
|
||||||
*
|
*
|
||||||
* Create a new character backend from a URI.
|
* Create a new character backend from a URI.
|
||||||
* Character device communications are not written
|
* Character device communications are not written
|
||||||
* into the replay log.
|
* into the replay log.
|
||||||
*
|
*
|
||||||
* @label the name of the backend
|
|
||||||
* @filename the URI
|
|
||||||
*
|
|
||||||
* Returns: a new character backend
|
* Returns: a new character backend
|
||||||
*/
|
*/
|
||||||
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename);
|
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
|
||||||
|
bool permit_mux_mon);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_be_can_write:
|
* qemu_chr_be_can_write:
|
||||||
*
|
*
|
||||||
* Determine how much data the front end can currently accept. This function
|
* Determine how much data the front end can currently accept. This function
|
||||||
* returns the number of bytes the front end can accept. If it returns 0, the
|
* returns the number of bytes the front end can accept. If it returns 0, the
|
||||||
@ -156,43 +166,39 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename);
|
|||||||
int qemu_chr_be_can_write(Chardev *s);
|
int qemu_chr_be_can_write(Chardev *s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_be_write:
|
* qemu_chr_be_write:
|
||||||
|
* @buf: a buffer to receive data from the front end
|
||||||
|
* @len: the number of bytes to receive from the front end
|
||||||
*
|
*
|
||||||
* Write data from the back end to the front end. Before issuing this call,
|
* Write data from the back end to the front end. Before issuing this call,
|
||||||
* the caller should call @qemu_chr_be_can_write to determine how much data
|
* the caller should call @qemu_chr_be_can_write to determine how much data
|
||||||
* the front end can currently accept.
|
* the front end can currently accept.
|
||||||
*
|
|
||||||
* @buf a buffer to receive data from the front end
|
|
||||||
* @len the number of bytes to receive from the front end
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
|
void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_be_write_impl:
|
* qemu_chr_be_write_impl:
|
||||||
|
* @buf: a buffer to receive data from the front end
|
||||||
|
* @len: the number of bytes to receive from the front end
|
||||||
*
|
*
|
||||||
* Implementation of back end writing. Used by replay module.
|
* Implementation of back end writing. Used by replay module.
|
||||||
*
|
|
||||||
* @buf a buffer to receive data from the front end
|
|
||||||
* @len the number of bytes to receive from the front end
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len);
|
void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_be_update_read_handlers:
|
* qemu_chr_be_update_read_handlers:
|
||||||
|
* @context: the gcontext that will be used to attach the watch sources
|
||||||
*
|
*
|
||||||
* Invoked when frontend read handlers are setup
|
* Invoked when frontend read handlers are setup
|
||||||
*
|
|
||||||
* @context the gcontext that will be used to attach the watch sources
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_be_update_read_handlers(Chardev *s,
|
void qemu_chr_be_update_read_handlers(Chardev *s,
|
||||||
GMainContext *context);
|
GMainContext *context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_be_event:
|
* qemu_chr_be_event:
|
||||||
|
* @event: the event to send
|
||||||
*
|
*
|
||||||
* Send an event from the back end to the front end.
|
* Send an event from the back end to the front end.
|
||||||
*
|
|
||||||
* @event the event to send
|
|
||||||
*/
|
*/
|
||||||
void qemu_chr_be_event(Chardev *s, int event);
|
void qemu_chr_be_event(Chardev *s, int event);
|
||||||
|
|
||||||
@ -203,7 +209,8 @@ bool qemu_chr_has_feature(Chardev *chr,
|
|||||||
ChardevFeature feature);
|
ChardevFeature feature);
|
||||||
void qemu_chr_set_feature(Chardev *chr,
|
void qemu_chr_set_feature(Chardev *chr,
|
||||||
ChardevFeature feature);
|
ChardevFeature feature);
|
||||||
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
|
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
|
||||||
|
bool permit_mux_mon);
|
||||||
int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all);
|
int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all);
|
||||||
#define qemu_chr_write_all(s, buf, len) qemu_chr_write(s, buf, len, true)
|
#define qemu_chr_write_all(s, buf, len) qemu_chr_write(s, buf, len, true)
|
||||||
int qemu_chr_wait_connected(Chardev *chr, Error **errp);
|
int qemu_chr_wait_connected(Chardev *chr, Error **errp);
|
||||||
|
@ -764,7 +764,11 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
Chardev *chr = qemu_chr_new(buf, p);
|
/*
|
||||||
|
* FIXME: sure we want to support implicit
|
||||||
|
* muxed monitors here?
|
||||||
|
*/
|
||||||
|
Chardev *chr = qemu_chr_new_mux_mon(buf, p);
|
||||||
|
|
||||||
if (!chr) {
|
if (!chr) {
|
||||||
error_setg(errp, "Could not open guest forwarding device '%s'",
|
error_setg(errp, "Could not open guest forwarding device '%s'",
|
||||||
|
10
vl.c
10
vl.c
@ -2310,7 +2310,7 @@ static void monitor_parse(const char *optarg, const char *mode, bool pretty)
|
|||||||
} else {
|
} else {
|
||||||
snprintf(label, sizeof(label), "compat_monitor%d",
|
snprintf(label, sizeof(label), "compat_monitor%d",
|
||||||
monitor_device_index);
|
monitor_device_index);
|
||||||
opts = qemu_chr_parse_compat(label, optarg);
|
opts = qemu_chr_parse_compat(label, optarg, true);
|
||||||
if (!opts) {
|
if (!opts) {
|
||||||
error_report("parse error: %s", optarg);
|
error_report("parse error: %s", optarg);
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -2382,7 +2382,7 @@ static int serial_parse(const char *devname)
|
|||||||
snprintf(label, sizeof(label), "serial%d", index);
|
snprintf(label, sizeof(label), "serial%d", index);
|
||||||
serial_hds = g_renew(Chardev *, serial_hds, index + 1);
|
serial_hds = g_renew(Chardev *, serial_hds, index + 1);
|
||||||
|
|
||||||
serial_hds[index] = qemu_chr_new(label, devname);
|
serial_hds[index] = qemu_chr_new_mux_mon(label, devname);
|
||||||
if (!serial_hds[index]) {
|
if (!serial_hds[index]) {
|
||||||
error_report("could not connect serial device"
|
error_report("could not connect serial device"
|
||||||
" to character backend '%s'", devname);
|
" to character backend '%s'", devname);
|
||||||
@ -2418,7 +2418,7 @@ static int parallel_parse(const char *devname)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
snprintf(label, sizeof(label), "parallel%d", index);
|
snprintf(label, sizeof(label), "parallel%d", index);
|
||||||
parallel_hds[index] = qemu_chr_new(label, devname);
|
parallel_hds[index] = qemu_chr_new_mux_mon(label, devname);
|
||||||
if (!parallel_hds[index]) {
|
if (!parallel_hds[index]) {
|
||||||
error_report("could not connect parallel device"
|
error_report("could not connect parallel device"
|
||||||
" to character backend '%s'", devname);
|
" to character backend '%s'", devname);
|
||||||
@ -2449,7 +2449,7 @@ static int virtcon_parse(const char *devname)
|
|||||||
qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort);
|
qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort);
|
||||||
|
|
||||||
snprintf(label, sizeof(label), "virtcon%d", index);
|
snprintf(label, sizeof(label), "virtcon%d", index);
|
||||||
virtcon_hds[index] = qemu_chr_new(label, devname);
|
virtcon_hds[index] = qemu_chr_new_mux_mon(label, devname);
|
||||||
if (!virtcon_hds[index]) {
|
if (!virtcon_hds[index]) {
|
||||||
error_report("could not connect virtio console"
|
error_report("could not connect virtio console"
|
||||||
" to character backend '%s'", devname);
|
" to character backend '%s'", devname);
|
||||||
@ -2465,7 +2465,7 @@ static int debugcon_parse(const char *devname)
|
|||||||
{
|
{
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
|
|
||||||
if (!qemu_chr_new("debugcon", devname)) {
|
if (!qemu_chr_new_mux_mon("debugcon", devname)) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL);
|
opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL);
|
||||||
|
Loading…
Reference in New Issue
Block a user