diff options
Diffstat (limited to 'monitor.c')
-rw-r--r-- | monitor.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/monitor.c b/monitor.c new file mode 100644 index 0000000..f8bd9ff --- /dev/null +++ b/monitor.c @@ -0,0 +1,163 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/socket.h> + +#include <gtk/gtk.h> +#include <vte/vte.h> + +#include "qemu-gtk.h" +#include "tcp.h" + +/* ----------------------------------------------------------------- */ + +static int monitor_parse(struct qemu_window *win, char *buf, int len) +{ + char *reply, *prompt, *cmd; + int off; + + prompt = strstr(buf, "(qemu) "); + if (NULL == prompt) + return 0; + off = prompt - buf; + if (prompt > buf+1 && prompt[-2] == '\r' && prompt[-1] == '\n') + prompt -= 2; + *prompt = 0; + + if (!win->mrun) + goto out; + cmd = win->mrun->cmd; + reply = strstr(buf, "\r\n"); + if (!reply) + goto out; + reply += 2; + +#if 0 + fprintf(stderr, "\"%s\" -> [%s]\n--\n", cmd, reply); +#endif + if (0 == strcmp(cmd, "info version")) { + snprintf(win->version, sizeof(win->version), "%s", reply); + update_status(win); + } else if (0 == strcmp(cmd, "info name")) { + snprintf(win->name, sizeof(win->name), "%s", reply); + update_status(win); + } else if (0 == strcmp(cmd, "info vnc")) { + if (1 == sscanf(reply, "VNC server active on: %127[^\r\n]", + win->vnc_display) && + strstr(reply, "No client connected")) + vnc_connect(win); + } + +out: + return off + 7; +} + +/* ----------------------------------------------------------------- */ + +static void monitor_next(struct qemu_window *win) +{ + char buf[256]; + int len; + + if (win->mrun) + free(win->mrun); + win->mrun = win->mqueue; + if (!win->mrun) + return; + win->mqueue = win->mrun->next; + len = snprintf(buf, sizeof(buf), "%s\n", win->mrun->cmd); + write(win->monitor.handle, buf, len); +} + +void monitor_append(struct qemu_window *win, char *cmd) +{ + struct qemu_mq *mq; + + if (win->mqueue) { + for (mq = win->mqueue; mq->next; mq = mq->next) + ; + mq->next = malloc(sizeof(*mq)); + mq = mq->next; + } else { + win->mqueue = malloc(sizeof(*mq)); + mq = win->mqueue; + } + mq->next = NULL; + snprintf(mq->cmd, sizeof(mq->cmd), "%s", cmd); + + if (0 == win->mused) + monitor_next(win); +} + +static gboolean monitor_watch(GIOChannel *source, GIOCondition condition, + gpointer userdata) +{ + struct qemu_window *win = userdata; + int rc; + + if (win->mused == win->msize) { + if (!win->msize) + win->msize = 4; + win->msize *= 2; + win->mbuf = realloc(win->mbuf, win->msize +1); + } + + rc = read(win->monitor.handle, win->mbuf + win->mused, win->msize - win->mused); + switch(rc) { + case -1: + if (EINTR == errno) + break; + perror("monitor: read"); + goto close; + case 0: + fprintf(stderr, "monitor: EOF\n"); + goto close; + default: + if (win->monitor.vte) + vte_terminal_feed(VTE_TERMINAL(win->monitor.vte), win->mbuf + win->mused, rc); + win->mused += rc; + win->mbuf[win->mused] = 0; + rc = monitor_parse(win, win->mbuf, win->mused); + if (rc) { + if (rc < win->mused) + memmove(win->mbuf, win->mbuf + rc, win->mused - rc); + win->mused -= rc; + } + break; + } + + if (0 == win->mused) + monitor_next(win); + return TRUE; + +close: + if (win->monitor.vte) + vte_terminal_feed(VTE_TERMINAL(win->monitor.vte), "\r\n=== CLOSED ===", 16); + close(win->monitor.handle); + win->monitor.handle = -1; +// gtk_widget_destroy(win->toplevel); + return FALSE; +} + +/* ----------------------------------------------------------------- */ + +int monitor_connect(struct qemu_window *win, char *dest) +{ + int fd; + + fd = conn_init(&win->monitor, "monitor", dest); + if (-1 == fd) + return -1; + + win->monitor.ch = g_io_channel_unix_new(fd); + win->monitor.id = g_io_add_watch(win->monitor.ch, G_IO_IN, monitor_watch, win); + + monitor_append(win, "info version"); + monitor_append(win, "info name"); + monitor_append(win, "info vnc"); + return fd; +} |