static int io_channel_send(GIOChannel *fd, const void *buf, size_t len)
{
- GIOStatus status;
- size_t offset;
+ size_t offset = 0;
+ GIOStatus status = G_IO_STATUS_NORMAL;
- offset = 0;
- while (offset < len) {
- gsize bytes_written;
+ while (offset < len && status == G_IO_STATUS_NORMAL) {
+ gsize bytes_written = 0;
status = g_io_channel_write_chars(fd, buf + offset, len - offset,
&bytes_written, NULL);
- if (status != G_IO_STATUS_NORMAL) {
- if (status == G_IO_STATUS_AGAIN) {
- /* If we've written any data, return a partial write. */
- if (offset) {
- break;
- }
- errno = EAGAIN;
- } else {
- errno = EINVAL;
- }
-
- return -1;
- } else if (status == G_IO_STATUS_EOF) {
- break;
- }
-
offset += bytes_written;
}
- return offset;
+ if (offset > 0) {
+ return offset;
+ }
+ switch (status) {
+ case G_IO_STATUS_NORMAL:
+ g_assert(len == 0);
+ return 0;
+ case G_IO_STATUS_AGAIN:
+ errno = EAGAIN;
+ return -1;
+ default:
+ break;
+ }
+ errno = EINVAL;
+ return -1;
}
#ifndef _WIN32
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
}
- /* if graphical mode, we allow Ctrl-C handling */
if (!stdio_allow_signal)
tty.c_lflag &= ~ISIG;
chr = qemu_chr_open_fd(0, 1);
chr->chr_close = qemu_chr_close_stdio;
chr->chr_set_echo = qemu_chr_set_echo_stdio;
- stdio_allow_signal = display_type != DT_NOGRAPHIC;
if (opts->has_signal) {
stdio_allow_signal = opts->signal;
}
fd = inet_dgram_opts(opts, &local_err);
if (fd < 0) {
+ qerror_report_err(local_err);
+ error_free(local_err);
return NULL;
}
return qemu_chr_open_udp_fd(fd);
chr->opaque = NULL;
}
-static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts,
- Error **errp)
+static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts,
+ Error **errp)
{
CharDriverState *chr;
RingBufCharDriver *d;
/* The size must be power of 2 */
if (d->size & (d->size - 1)) {
- error_setg(errp, "size of memory chardev must be power of two");
+ error_setg(errp, "size of ringbuf chardev must be power of two");
goto fail;
}
if (strstart(filename, "mon:", &p)) {
filename = p;
qemu_opt_set(opts, "mux", "on");
+ 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. */
+ qemu_opt_set(opts, "signal", "off");
+ }
}
if (strcmp(filename, "null") == 0 ||
{
backend->stdio = g_new0(ChardevStdio, 1);
backend->stdio->has_signal = true;
- backend->stdio->signal =
- qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC);
+ backend->stdio->signal = qemu_opt_get_bool(opts, "signal", true);
}
static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend,
backend->pipe->device = g_strdup(device);
}
-static void qemu_chr_parse_memory(QemuOpts *opts, ChardevBackend *backend,
- Error **errp)
+static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
+ Error **errp)
{
int val;
- backend->memory = g_new0(ChardevMemory, 1);
+ backend->ringbuf = g_new0(ChardevRingbuf, 1);
- val = qemu_opt_get_number(opts, "size", 0);
+ val = qemu_opt_get_size(opts, "size", 0);
if (val != 0) {
- backend->memory->has_size = true;
- backend->memory->size = val;
+ backend->ringbuf->has_size = true;
+ backend->ringbuf->size = val;
+ }
+}
+
+static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
+ Error **errp)
+{
+ const char *chardev = qemu_opt_get(opts, "chardev");
+
+ if (chardev == NULL) {
+ error_setg(errp, "chardev: mux: no chardev given");
+ return;
}
+ backend->mux = g_new0(ChardevMux, 1);
+ backend->mux->chardev = g_strdup(chardev);
}
typedef struct CharDriver {
ChardevBackend *backend = g_new0(ChardevBackend, 1);
ChardevReturn *ret = NULL;
const char *id = qemu_opts_id(opts);
- const char *bid = NULL;
+ char *bid = NULL;
if (qemu_opt_get_bool(opts, "mux", 0)) {
bid = g_strdup_printf("%s-base", id);
backend->kind = CHARDEV_BACKEND_KIND_MUX;
backend->mux->chardev = g_strdup(bid);
ret = qmp_chardev_add(id, backend, errp);
- if (error_is_set(errp)) {
- goto qapi_out;
- }
+ assert(!error_is_set(errp));
}
chr = qemu_chr_find(id);
+ chr->opts = opts;
qapi_out:
qapi_free_ChardevBackend(backend);
qapi_free_ChardevReturn(ret);
+ g_free(bid);
return chr;
}
},{
.name = "size",
.type = QEMU_OPT_SIZE,
+ },{
+ .name = "chardev",
+ .type = QEMU_OPT_STRING,
},
{ /* end of list */ }
},
case CHARDEV_BACKEND_KIND_VC:
chr = vc_init(backend->vc);
break;
+ case CHARDEV_BACKEND_KIND_RINGBUF:
case CHARDEV_BACKEND_KIND_MEMORY:
- chr = qemu_chr_open_memory(backend->memory, errp);
+ chr = qemu_chr_open_ringbuf(backend->ringbuf, errp);
break;
default:
error_setg(errp, "unknown chardev backend (%d)", backend->kind);
register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL);
register_char_driver("socket", qemu_chr_open_socket);
register_char_driver("udp", qemu_chr_open_udp);
- register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY,
- qemu_chr_parse_memory);
+ register_char_driver_qapi("ringbuf", CHARDEV_BACKEND_KIND_RINGBUF,
+ qemu_chr_parse_ringbuf);
register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE,
qemu_chr_parse_file_out);
register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO,
register_char_driver_qapi("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL);
register_char_driver_qapi("pipe", CHARDEV_BACKEND_KIND_PIPE,
qemu_chr_parse_pipe);
+ register_char_driver_qapi("mux", CHARDEV_BACKEND_KIND_MUX,
+ qemu_chr_parse_mux);
+ /* Bug-compatibility: */
+ register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY,
+ qemu_chr_parse_ringbuf);
}
type_init(register_types);