qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] Support redirect -curses over a character driver


From: Anthony Liguori
Subject: [Qemu-devel] [PATCH] Support redirect -curses over a character driver
Date: Tue, 4 Mar 2008 20:34:18 -0600

I love the -curses feature but I really wanted to use it over a telnet:
character device.  This patch enables this and changes the syntax of the
 -curses argument to take a character device.  'stdio' is special cased to not
go through a character device.  The rest use a pty to proxy the data to the
character device.  curses insists on a pty so we limit this feature to
everything but WIN32 since I don't believe Windows supports ptys.

Using this patch, you can now do something like '-curses telnet::1028,nowait'.
To get the old behavior, just use '-curses stdio'.

Signed-off-by: Anthony Liguori <address@hidden>

diff --git a/console.h b/console.h
index b8a5c6d..43e1284 100644
--- a/console.h
+++ b/console.h
@@ -141,7 +141,7 @@ int vnc_display_password(DisplayState *ds, const char 
*password);
 void do_info_vnc(void);
 
 /* curses.c */
-void curses_display_init(DisplayState *ds, int full_screen);
+void curses_display_init(DisplayState *ds, CharDriverState *chr, int 
full_screen);
 
 /* x_keymap.c */
 extern uint8_t _translate_keycode(const int key);
diff --git a/curses.c b/curses.c
index 87aa9b3..a020dd1 100644
--- a/curses.c
+++ b/curses.c
@@ -32,6 +32,7 @@
 #include <signal.h>
 #include <sys/ioctl.h>
 #include <termios.h>
+#include <pty.h>
 #endif
 
 #define FONT_HEIGHT 16
@@ -41,6 +42,7 @@ static console_ch_t screen[160 * 100];
 static WINDOW *screenpad = NULL;
 static int width, height, gwidth, gheight, invalidate;
 static int px, py, sminx, sminy, smaxx, smaxy;
+static int slave;
 
 static void curses_update(DisplayState *ds, int x, int y, int w, int h)
 {
@@ -278,16 +280,102 @@ static void curses_atexit(void)
     curses_cleanup(NULL);
 }
 
-static void curses_setup(void)
+#ifndef _WIN32
+static void pty_read_proxy(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    char buffer[4096];
+    ssize_t len;
+
+    do {
+       len = read(slave, buffer, sizeof(buffer));
+    } while (len == -1 && errno == EINTR);
+
+    if (len > 0)
+       qemu_chr_write(chr, buffer, len);
+}
+
+static void chr_read_proxy(void *opaque, const uint8_t *buf, int size)
+{
+    ssize_t len;
+    size_t offset = 0;
+
+    do {
+       len = write(slave, buf + offset, size - offset);
+       if (len == -1 && (errno == EINTR || errno == EAGAIN))
+           continue;
+       if (len > 0)
+           offset += len;
+    } while (offset < size && len > 0);
+
+    if (offset != size)
+       fprintf(stderr, "curses: short write to slave pty\n");
+}
+
+static int chr_can_read_proxy(void *opaque)
+{
+    return 1024;
+}
+
+static void chr_event_proxy(void *opaque, int event)
+{
+    if (event == CHR_EVENT_RESET)
+       invalidate = 1;
+}
+#endif
+
+static void curses_setup(CharDriverState *chr)
 {
     int i, colour_default[8] = {
         COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
         COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
     };
 
+#ifndef _WIN32
+    if (chr) {
+       struct termios term;
+       FILE *fin, *fout;
+       SCREEN *screen;
+       int master;
+
+       if (openpty(&master, &slave, NULL, NULL, NULL) == -1) {
+           fprintf(stderr, "fatal: could not open pty\n");
+           exit(1);
+       }
+
+       tcgetattr(master, &term);
+       cfmakeraw(&term);
+       tcsetattr(master, 0, &term);
+
+       tcgetattr(slave, &term);
+       cfmakeraw(&term);
+       tcsetattr(slave, 0, &term);
+
+       fout = fdopen(master, "w");
+       fin = fdopen(master, "r");
+
+       if (fout == NULL || fin == NULL) {
+           fprintf(stderr, "fatal: could not reopen pty\n");
+           exit(1);
+       }
+
+       qemu_set_fd_handler2(slave, NULL, pty_read_proxy, NULL, chr);
+       qemu_chr_add_handlers(chr, chr_can_read_proxy, chr_read_proxy,
+                             chr_event_proxy, chr);
+
+       screen = newterm(getenv("TERM"), fout, fin);
+       set_term(screen);
+
+       /* we won't get resizes so we need to start out telling curses the
+          proper size */
+       resize_term(25, 80);
+    } else
+#endif
+       initscr();
+
     /* input as raw as possible, let everything be interpreted
      * by the guest system */
-    initscr(); noecho(); intrflush(stdscr, FALSE);
+    noecho(); intrflush(stdscr, FALSE);
     nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
     start_color(); raw(); scrollok(stdscr, FALSE);
 
@@ -332,7 +420,7 @@ static void curses_keyboard_setup(void)
     }
 }
 
-void curses_display_init(DisplayState *ds, int full_screen)
+void curses_display_init(DisplayState *ds, CharDriverState *chr, int 
full_screen)
 {
 #ifndef _WIN32
     if (!isatty(1)) {
@@ -341,7 +429,7 @@ void curses_display_init(DisplayState *ds, int full_screen)
     }
 #endif
 
-    curses_setup();
+    curses_setup(chr);
     curses_keyboard_setup();
     atexit(curses_atexit);
 
diff --git a/vl.c b/vl.c
index d5a1dbc..16c9900 100644
--- a/vl.c
+++ b/vl.c
@@ -172,7 +172,6 @@ BlockDriverState *bs_snapshots;
 int vga_ram_size;
 static DisplayState display_state;
 int nographic;
-int curses;
 const char* keyboard_layout = NULL;
 int64_t ticks_per_sec;
 int ram_size;
@@ -7691,7 +7690,7 @@ static void help(int exitcode)
            "-no-acpi        disable ACPI\n"
 #endif
 #ifdef CONFIG_CURSES
-           "-curses         use a curses/ncurses interface instead of SDL\n"
+           "-curses dev     use a curses/ncurses to char driver 'dev' instead 
of SDL\n"
 #endif
            "-no-reboot      exit instead of rebooting\n"
            "-loadvm file    start right away with a saved state (loadvm in 
monitor)\n"
@@ -7896,7 +7895,7 @@ const QEMUOption qemu_options[] = {
     { "smp", HAS_ARG, QEMU_OPTION_smp },
     { "vnc", HAS_ARG, QEMU_OPTION_vnc },
 #ifdef CONFIG_CURSES
-    { "curses", 0, QEMU_OPTION_curses },
+    { "curses", HAS_ARG, QEMU_OPTION_curses },
 #endif
 
     /* temporary options */
@@ -8190,6 +8189,7 @@ int main(int argc, char **argv)
     int fds[2];
     const char *pid_file = NULL;
     VLANState *vlan;
+    const char *curses_device = NULL;
 
     LIST_INIT (&vm_change_state_head);
 #ifndef _WIN32
@@ -8234,7 +8234,6 @@ int main(int argc, char **argv)
 #endif
     snapshot = 0;
     nographic = 0;
-    curses = 0;
     kernel_filename = NULL;
     kernel_cmdline = "";
     cyls = heads = secs = 0;
@@ -8411,7 +8410,7 @@ int main(int argc, char **argv)
                 break;
 #ifdef CONFIG_CURSES
             case QEMU_OPTION_curses:
-                curses = 1;
+               curses_device = optarg;
                 break;
 #endif
             case QEMU_OPTION_portrait:
@@ -8956,7 +8955,7 @@ int main(int argc, char **argv)
     /* terminal init */
     memset(&display_state, 0, sizeof(display_state));
     if (nographic) {
-        if (curses) {
+        if (curses_device) {
             fprintf(stderr, "fatal: -nographic can't be used with -curses\n");
             exit(1);
         }
@@ -8968,8 +8967,19 @@ int main(int argc, char **argv)
             exit(1);
     } else
 #if defined(CONFIG_CURSES)
-    if (curses) {
-        curses_display_init(ds, full_screen);
+    if (curses_device) {
+       CharDriverState *chr = NULL;
+
+#ifndef _WIN32
+       if (strcmp(curses_device, "stdio") != 0) {
+           chr = qemu_chr_open(curses_device);
+           if (chr == NULL) {
+               fprintf(stderr, "fatal: could not open curses device\n");
+               exit(1);
+           }
+       }
+#endif
+        curses_display_init(ds, chr, full_screen);
     } else
 #endif
     {




reply via email to

[Prev in Thread] Current Thread [Next in Thread]