aboutsummaryrefslogtreecommitdiffstats
path: root/monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'monitor.c')
-rw-r--r--monitor.c163
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;
+}