# HG changeset patch # User Pascal Bellard # Date 1277322493 -7200 # Node ID 5a12924439fd51890e9adfef744181c39d78dc6f # Parent 932522d70bdb0cb83e4907dcfdc5ff1435882edd busybox: add conspy diff -r 932522d70bdb -r 5a12924439fd busybox/receipt --- a/busybox/receipt Wed Jun 23 16:11:06 2010 +0200 +++ b/busybox/receipt Wed Jun 23 21:48:13 2010 +0200 @@ -36,8 +36,13 @@ EOT cp ../stuff/$PACKAGE-$VERSION.config .config make oldconfig - # "CFLAGS=-O0" is a workaround for GCC 4.5.0 - make -j 4 "CFLAGS=-O0" && make "CFLAGS=-O0" install + if [ "$(gcc --version | awk '{ print $3; exit }')" == "4.5.0" ]; then + # "CFLAGS=-O0" is a workaround for GCC 4.5.0 (sed crach) + # "CFLAGS=-fno-tree-pta" may be a workaround for GCC 4.5.0 (sed garbage) + make -j 4 "CFLAGS=-O0" && make "CFLAGS=-O0" install + else + make -j 4 && make install + fi echo "Chmod 4755 on busybox binary..." chmod 4755 _install/bin/busybox } @@ -88,10 +93,10 @@ [ -e $ROOT$i ] || continue if [ -z "$answer" ]; then echo -n "Keep installed GNU utilities ? " - read answer + read -t 30 answer # by default: keep case "$answer" in - y*|Y*|o*|O*);; - *) break;; + n*|N*) break;; + *) ;; esac fi mv $ROOT$i $ROOT$i-busybox-install diff -r 932522d70bdb -r 5a12924439fd busybox/stuff/busybox-1.16.1-modinfo.u --- a/busybox/stuff/busybox-1.16.1-modinfo.u Wed Jun 23 16:11:06 2010 +0200 +++ b/busybox/stuff/busybox-1.16.1-modinfo.u Wed Jun 23 21:48:13 2010 +0200 @@ -1,6 +1,6 @@ --- busybox-1.16.1/include/applets.h +++ busybox-1.16.1/include/applets.h -@@ -272,6 +272,7 @@ +@@ -273,6 +273,7 @@ IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkpasswd)) IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP)) @@ -11,7 +11,7 @@ --- busybox-1.16.1/include/usage.h +++ busybox-1.16.1/include/usage.h -@@ -2967,6 +2967,20 @@ +@@ -2984,6 +2984,20 @@ " which are the default for alias 'tulip2' overridden by the options 'irq=2 io=0x210'\n\n" \ " from the command line\n" diff -r 932522d70bdb -r 5a12924439fd busybox/stuff/busybox-1.16.1-modprobe.u --- a/busybox/stuff/busybox-1.16.1-modprobe.u Wed Jun 23 16:11:06 2010 +0200 +++ b/busybox/stuff/busybox-1.16.1-modprobe.u Wed Jun 23 21:48:13 2010 +0200 @@ -1,6 +1,6 @@ --- busybox-1.16.1/include/usage.h +++ busybox-1.16.1/include/usage.h -@@ -2881,7 +2881,7 @@ +@@ -2898,7 +2898,7 @@ #define modprobe_trivial_usage \ IF_MODPROBE_SMALL("[-qfwrsv] MODULE [symbol=value]...") \ IF_NOT_MODPROBE_SMALL("[-" \ @@ -9,7 +9,7 @@ IF_FEATURE_MODPROBE_BLACKLIST("b")"] MODULE [symbol=value]...") #define modprobe_full_usage "\n\n" \ "Options:" \ -@@ -2898,6 +2898,7 @@ +@@ -2915,6 +2915,7 @@ "\n -k Make module autoclean-able" \ ) \ "\n -n Dry run" \ diff -r 932522d70bdb -r 5a12924439fd busybox/stuff/busybox-1.16.1-stat.u --- a/busybox/stuff/busybox-1.16.1-stat.u Wed Jun 23 16:11:06 2010 +0200 +++ b/busybox/stuff/busybox-1.16.1-stat.u Wed Jun 23 21:48:13 2010 +0200 @@ -65,7 +65,7 @@ --- busybox-1.16.1/include/usage.h +++ busybox-1.16.1/include/usage.h -@@ -4184,6 +4184,7 @@ +@@ -4201,6 +4201,7 @@ "\n -f Display filesystem status" \ "\n -L Follow links" \ "\n -t Display info in terse form" \ diff -r 932522d70bdb -r 5a12924439fd busybox/stuff/busybox-1.16.1-vcsa2txt.u --- a/busybox/stuff/busybox-1.16.1-vcsa2txt.u Wed Jun 23 16:11:06 2010 +0200 +++ b/busybox/stuff/busybox-1.16.1-vcsa2txt.u Wed Jun 23 21:48:13 2010 +0200 @@ -1,6 +1,14 @@ --- busybox-1.16.1/include/applets.h +++ busybox-1.16.1/include/applets.h -@@ -420,6 +420,7 @@ +@@ -105,6 +105,7 @@ + IF_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + IF_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP)) ++IF_VCSA2TXT(APPLET(conspy, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_DROP, cp)) + IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_DROP)) + IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) +@@ -420,6 +421,7 @@ IF_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) @@ -11,14 +19,38 @@ --- busybox-1.16.1/include/usage.h +++ busybox-1.16.1/include/usage.h -@@ -5011,6 +5011,13 @@ +@@ -440,6 +440,23 @@ + "\n -1 Close stdout" \ + "\n -2 Close stderr" \ + ++#define conspy_trivial_usage \ ++ "[-vcsnd] [-x rows] [-y lines] [virtual_console]" ++#define conspy_full_usage "\n\n" \ ++ "A text-mode VNC like program for Linux virtual terminals.\n" \ ++ "\nTo exit, quickly press escape 3 times.\n" \ ++ "\nvirtual_console:\n" \ ++ " omitted Track the current console.\n" \ ++ " 1..63 Virtual console N.\n" \ ++ "\nOptions:" \ ++ "\n -v Don't send keystrokes to the console." \ ++ "\n -c May create device in /dev." \ ++ "\n -s Open a SHELL session." \ ++ "\n -n No colors. Black & white only." \ ++ "\n -d Dump console to stdout."\ ++ "\n -x r Skip the r first rows."\ ++ "\n -y l Skip the l first lines."\ ++ + #define setuidgid_trivial_usage \ + "USER PROG ARGS" + #define setuidgid_full_usage "\n\n" \ +@@ -5011,6 +5028,13 @@ "\n set_ingress_map [vlan-name] [skb_priority] [vlan_qos]" \ "\n set_name_type [name-type]" \ +#define vcsa2txt_trivial_usage \ + "stdin" +#define vcsa2txt_full_usage \ -+ "Filter /dev/vcsa* to ansi escape sequences" ++ " Filter /dev/vcsa* to ansi escape sequences" +#define vcsa2txt_example_usage \ + "# vcsa2txt < /dev/vcsa1\n" + @@ -33,7 +65,7 @@ Write a message to all users that are logged in. +config VCSA2TXT -+ bool "vcsa2txt" ++ bool "vcsa2txt/conspy" + default n + help + Filter /dev/vcsa* output to ansi escape sequences. @@ -52,83 +84,493 @@ --- busybox-1.16.1/util-linux/vcsa2txt.c +++ busybox-1.16.1/util-linux/vcsa2txt.c -@@ -0,0 +1,79 @@ +@@ -0,0 +1,489 @@ +/* vi: set sw=4 ts=4: */ +/* -+ * /dev/vcsa* filter for busybox ++ * A text-mode VNC like program for Linux virtual terminals. + * + * pascal.bellard@ads-lu.com + * ++ * Based on Russell Stuart's conspy.c ++ * http://ace-host.stuart.id.au/russell/files/conspy.c ++ * + * Licensed under GPLv2 or later, see file License in this tarball for details. ++ * ++ * example : conspy num shared access to console num ++ * or conspy -d num screenshot of console num ++ * or conspy -cs num poor man's GNU screen like + */ -+ ++ ++//applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) ++ ++//kbuild:lib-$(CONFIG_CONSPY) += conspy.o ++ ++//config:config CONSPY ++//config: bool "conspy" ++//config: default n ++//config: help ++//config: A text-mode VNC like program for Linux virtual terminals. ++//config: example : conspy num shared access to console num ++//config: or conspy -d num screenshot of console num ++//config: or conspy -cs num poor man's GNU screen like ++ ++//usage:#define conspy_trivial_usage ++//usage: "[-vcsndf] [-x ROW] [-y LINE] [CONSOLE_NO]" ++//usage:#define conspy_full_usage "\n\n" ++//usage: "A text-mode VNC like program for Linux virtual consoles." ++//usage: "\nTo exit, quickly press ESC 3 times." ++//usage: "\n" ++//usage: "\nOptions:" ++//usage: "\n -v Don't send keystrokes to the console" ++//usage: "\n -c Create missing devices in /dev" ++//usage: "\n -s Open a SHELL session" ++//usage: "\n -n Black & white" ++//usage: "\n -d Dump console to stdout" ++//usage: "\n -f Follow cursor" ++//usage: "\n -x ROW Starting row" ++//usage: "\n -y LINE Starting line" ++ +#include "libbb.h" ++#include ++ ++struct screen_info { ++ unsigned char lines, rows, cursor_x, cursor_y; ++}; ++ ++#define CHAR(x) ((x)[0]) ++#define ATTR(x) ((x)[1]) ++#define NEXT(x) ((x)+=2) ++#define DATA(x) (* (short *) (x)) ++ ++struct globals { ++ char* data; ++ int size; ++ int x, y; ++ int kbd_fd; ++ unsigned width; ++ unsigned height; ++ char last_attr; ++ int ioerror_count; ++ int key_count; ++ int escape_count; ++ int nokeys; ++ int current; ++ int vcsa_fd; ++ struct screen_info info; ++ struct termios term_orig; ++}; ++ ++#define G (*ptr_to_globals) ++#define INIT_G() do { \ ++ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ ++} while (0) ++ ++enum { ++ FLAG_v, // view only ++ FLAG_c, // create device if need ++ FLAG_s, // session ++ FLAG_n, // no colors ++ FLAG_d, // dump screen ++ FLAG_f, // follow cursor ++}; ++#define FLAG(x) (1 << FLAG_##x) ++#define BW (option_mask32 & FLAG(n)) ++ ++static void screen_read_close(void) ++{ ++ unsigned i, j; ++ char *data = G.data + G.current; ++ ++ xread(G.vcsa_fd, data, G.size); ++ G.last_attr = 0; ++ for (i = 0; i < G.info.lines; i++) { ++ for (j = 0; j < G.info.rows; j++, NEXT(data)) { ++ unsigned x = j - G.x; // if will catch j < G.x too ++ unsigned y = i - G.y; // if will catch i < G.y too ++ ++ if (CHAR(data) < ' ') ++ CHAR(data) = ' '; ++ if (y >= G.height || x >= G.width) ++ DATA(data) = 0; ++ } ++ } ++ close(G.vcsa_fd); ++} ++ ++static void screen_char(char *data) ++{ ++ if (!BW && G.last_attr != ATTR(data)) { ++ // BLGCRMOW ++ static const char color[8] = "04261537"; ++ ++ printf("\033[%c;4%c;3%cm", ++ (ATTR(data) & 8) ? '1' // bold ++ : '0', // defaults ++ color[(ATTR(data) >> 4) & 7], color[ATTR(data) & 7]); ++ G.last_attr = ATTR(data); ++ } ++ bb_putchar(CHAR(data)); ++} ++ ++#define clrscr() printf("\033[1;1H" "\033[0J") ++#define curoff() printf("\033[?25l") ++ ++static void curon(void) ++{ ++ printf("\033[?25h"); ++} ++ ++static void gotoxy(int row, int line) ++{ ++ printf("\033[%u;%uH", line + 1, row + 1); ++} ++ ++static void screen_dump(void) ++{ ++ int linefeed_cnt; ++ int line, row; ++ int linecnt = G.info.lines - G.y; ++ char *data = G.data + G.current + (2 * G.y * G.info.rows); ++ ++ linefeed_cnt = 0; ++ for (line = 0; line < linecnt && line < G.height; line++) { ++ int space_cnt = 0; ++ for (row = 0; row < G.info.rows; row++, NEXT(data)) { ++ unsigned tty_row = row - G.x; // if will catch row < G.x too ++ ++ if (tty_row >= G.width) ++ continue; ++ space_cnt++; ++ if (BW && (CHAR(data) | ' ') == ' ') ++ continue; ++ while (linefeed_cnt != 0) { ++ bb_putchar('\r'); ++ bb_putchar('\n'); ++ linefeed_cnt--; ++ } ++ while (--space_cnt) ++ bb_putchar(' '); ++ screen_char(data); ++ } ++ linefeed_cnt++; ++ } ++} ++ ++static void curmove(void) ++{ ++ unsigned cx = G.info.cursor_x - G.x; ++ unsigned cy = G.info.cursor_y - G.y; ++ ++ if (cx >= G.width || cy >= G.height) { ++ curoff(); ++ } else { ++ curon(); ++ gotoxy(cx, cy); ++ } ++ fflush_all(); ++} ++ ++static void cleanup(int code) ++{ ++ curon(); ++ fflush_all(); ++ tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); ++ if (ENABLE_FEATURE_CLEAN_UP) { ++ free(ptr_to_globals); ++ close(G.kbd_fd); ++ } ++ // Reset attributes ++ if (!BW) ++ printf("\033[0m"); ++ bb_putchar('\n'); ++ if (code > 1) ++ kill_myself_with_sig(code); // does not return ++ exit(code); ++} ++ ++static void get_initial_data(const char* vcsa_name) ++{ ++ G.vcsa_fd = xopen(vcsa_name, O_RDONLY); ++ xread(G.vcsa_fd, &G.info, 4); ++ G.size = G.info.rows * G.info.lines * 2; ++ G.width = G.height = UINT_MAX; ++ G.data = xzalloc(2 * G.size); ++ screen_read_close(); ++} ++ ++static void create_cdev_if_doesnt_exist(const char* name, dev_t dev) ++{ ++ int fd = open(name, O_RDONLY); ++ if (fd != -1) ++ close(fd); ++ else if (errno == ENOENT) ++ mknod(name, S_IFCHR | 0660, dev); ++} ++ ++static NOINLINE void start_shell_in_child(const char* tty_name) ++{ ++ int pid = vfork(); ++ if (pid < 0) { ++ bb_perror_msg_and_die("vfork"); ++ } ++ if (pid == 0) { ++ struct termios termchild; ++ char *shell = getenv("SHELL"); ++ ++ if (!shell) ++ shell = (char *) DEFAULT_SHELL; ++ signal(SIGHUP, SIG_IGN); ++ // set tty as a controlling tty ++ setsid(); ++ // make tty to be input, output, error ++ close(0); ++ xopen(tty_name, O_RDWR); // uses fd 0 ++ xdup2(0, 1); ++ xdup2(0, 2); ++ ioctl(0, TIOCSCTTY, 1); ++ tcsetpgrp(0, getpid()); ++ tcgetattr(0, &termchild); ++ termchild.c_lflag |= ECHO; ++ termchild.c_oflag |= ONLCR | XTABS; ++ termchild.c_iflag |= ICRNL; ++ termchild.c_iflag &= ~IXOFF; ++ tcsetattr_stdin_TCSANOW(&termchild); ++ execl(shell, shell, "-i", (char *) NULL); ++ bb_simple_perror_msg_and_die(shell); ++ } ++} + +int vcsa2txt_main(int argc) MAIN_EXTERNALLY_VISIBLE; +int vcsa2txt_main(int argc) +{ -+ struct { -+ unsigned char l, c, x, y; // man 4 console_codes -+ } scrn; -+ unsigned char last = 0, ch[2]; // BLGCRMOW -+ static unsigned char end[5] = "\e[0m\n", color[8] = "04261537"; -+ int sp, lf, x; -+ -+ if (safe_read(0, &scrn, 4) < 0) return 1; -+ for (lf = 0; scrn.l; lf++, scrn.l--) { -+ for (sp = x = 0; ++x <= scrn.c;) { -+ if (safe_read(0, &ch[0], 2) < 0) return 1; -+ if (argc > 1) ch[1] = 0; -+ sp++; -+ if (last == ch[1] && ch[0] == ' ') continue; -+ for (lf++; --lf;) bb_putchar('\n'); -+ while (--sp) bb_putchar(' '); -+#define ENABLE_VCSA_PACKED 1 -+#if ENABLE_VCSA_PACKED -+ if (last ^= ch[1]) { -+ char esc[16],*s; -+ struct offsets { -+ char mask, type, shr; -+ } *p; -+ static struct offsets offset[3] = { -+ {8,0,1}, {0x70,'4',4}, {7,'3',0} -+ }; -+ static char init = 0x7F; ++ INIT_G(); ++ option_mask32 = FLAG(n); ++ if (argc < 2) option_mask32 = 0; ++ xread(0, &G.info, 4); ++ G.size = G.info.rows * G.info.lines * 2; ++ G.width = G.height = UINT_MAX; ++ G.data = xzalloc(G.size); ++ screen_read_close(); ++ screen_dump(); ++ bb_putchar('\n'); ++ if (ENABLE_FEATURE_CLEAN_UP) { ++ free(ptr_to_globals); ++ close(G.kbd_fd); ++ } ++ return 0; ++} ++ ++int conspy_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; ++int conspy_main(int argc UNUSED_PARAM, char **argv) ++{ ++ char vcsa_name[sizeof("/dev/vcsa") + 2]; ++ char tty_name[sizeof("/dev/tty") + 2]; ++#define keybuf bb_common_bufsiz1 ++ struct termios termbuf; ++ unsigned opts; ++ unsigned ttynum; ++ int poll_timeout_ms; ++#if ENABLE_LONG_OPTS ++ static const char getopt_longopts[] ALIGN1 = ++ "viewonly\0" No_argument "v" ++ "createdevice\0" No_argument "c" ++ "session\0" No_argument "s" ++ "nocolors\0" No_argument "n" ++ "dump\0" No_argument "d" ++ "follow\0" No_argument "f" ++ ; ++ ++ applet_long_options = getopt_longopts; ++#endif ++ INIT_G(); ++ ++ opt_complementary = "x+:y+"; // numeric params ++ opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); ++ argv += optind; ++ ttynum = 0; ++ if (argv[0]) { ++ ttynum = xatou_range(argv[0], 0, 63); ++ } ++ sprintf(vcsa_name, "/dev/vcsa%u", ttynum); ++ sprintf(tty_name, "%s%u", "/dev/tty", ttynum); ++ if (opts & FLAG(c)) { ++ if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) ++ create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); ++ create_cdev_if_doesnt_exist(vcsa_name, makedev(7, 128 + ttynum)); ++ } ++ if ((opts & FLAG(s)) && ttynum) { ++ start_shell_in_child(tty_name); ++ } ++ ++ get_initial_data(vcsa_name); ++ G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); ++ if (opts & FLAG(d)) { ++ screen_dump(); ++ bb_putchar('\n'); ++ if (ENABLE_FEATURE_CLEAN_UP) { ++ free(ptr_to_globals); ++ close(G.kbd_fd); ++ } ++ return 0; ++ } ++ ++ bb_signals(BB_FATAL_SIGS, cleanup); ++ // All characters must be passed through to us unaltered ++ tcgetattr(G.kbd_fd, &G.term_orig); ++ termbuf = G.term_orig; ++ termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); ++ termbuf.c_oflag &= ~(OPOST); ++ termbuf.c_lflag &= ~(ISIG|ICANON|ECHO); ++ termbuf.c_cc[VMIN] = 1; ++ termbuf.c_cc[VTIME] = 0; ++ tcsetattr(G.kbd_fd, TCSANOW, &termbuf); ++ poll_timeout_ms = 250; ++ while (1) { ++ struct pollfd pfd; ++ int bytes_read; ++ int i, j; ++ char *data, *old; ++ ++ old = G.data + G.current; ++ G.current = G.size - G.current; ++ data = G.data + G.current; + -+ s = esc+2; -+ *(short *)esc = ntohs(256*'\e'+'['); -+ p = offset; -+ do { -+ if ((init|last) & p->mask) { -+ int c = (ch[1] & p->mask) >> p->shr; -+ -+ if ((*s = p->type) != 0) s++; -+ else if (c == 0) { -+ c = 2; -+ *s++ = '2'; /* normal */ ++ // Close & re-open vcsa in case they have ++ // swapped virtual consoles ++ G.vcsa_fd = xopen(vcsa_name, O_RDONLY); ++ xread(G.vcsa_fd, &G.info, 4); ++ if (G.size != (G.info.rows * G.info.lines * 2)) { ++ cleanup(1); ++ } ++ i = G.width; ++ j = G.height; ++ get_terminal_width_height(G.kbd_fd, &G.width, &G.height); ++ if ((option_mask32 & FLAG(f))) { ++ int nx = G.info.cursor_x - G.width + 1; ++ int ny = G.info.cursor_y - G.height + 1; ++ ++ if (G.info.cursor_x < G.x) { ++ G.x = G.info.cursor_x; ++ i = 0; // force refresh + } -+ *s++ = color[c]; -+ *s++ = ';'; -+ } -+ } while (p++->shr); -+ s[-1] = 'm'; -+ init = 0; -+ fwrite(esc,s-esc,1,stdout); -+ } -+ last = ch[1]; -+#else -+ if (last != ch[1]) { -+ static char esc[10] = "\e[0;47;37m"; -+ -+ esc[2] = ((last = ch[1]) & 8) ? '1' /* bold */ : '0' /* defaults */; -+ esc[sizeof(esc)-5] = color[(ch[1] >> 4) & 7]; -+ esc[sizeof(esc)-2] = color[ch[1] & 7]; -+ fwrite(esc,sizeof(esc),1,stdout); -+ } -+#endif -+ bb_putchar(ch[0]); ++ if (nx > G.x) { ++ G.x = nx; ++ i = 0; // force refresh ++ } ++ if (G.info.cursor_y < G.y) { ++ G.y = G.info.cursor_y; ++ i = 0; // force refresh ++ } ++ if (ny > G.y) { ++ G.y = ny; ++ i = 0; // force refresh ++ } ++ } ++ ++ // Scan console data and redraw our tty where needed ++ screen_read_close(); ++ if (i != G.width || j != G.height) { ++ clrscr(); ++ screen_dump(); ++ } ++ else for (i = 0; i < G.info.lines; i++) { ++ char *last = last; ++ char *first = NULL; ++ int iy = i - G.y; ++ ++ if (iy >= (int) G.height) ++ break; ++ for (j = 0; j < G.info.rows; j++) { ++ last = data; ++ if (DATA(data) != DATA(old) && iy >= 0) { ++ unsigned jx = j - G.x; ++ ++ last = NULL; ++ if (first == NULL && jx < G.width) { ++ first = data; ++ gotoxy(jx, iy); ++ } ++ } ++ NEXT(old); ++ NEXT(data); ++ } ++ if (first == NULL) ++ continue; ++ if (last == NULL) ++ last = data; ++ ++ // Write the data to the screen ++ for (; first < last; NEXT(first)) ++ screen_char(first); ++ } ++ curmove(); ++ ++ // Wait for local user keypresses ++ pfd.fd = G.kbd_fd; ++ pfd.events = POLLIN; ++ bytes_read = 0; ++ switch (poll(&pfd, 1, poll_timeout_ms)) { ++ char *k; ++ case -1: ++ if (errno != EINTR) ++ cleanup(1); ++ break; ++ case 0: ++ if (++G.nokeys >= 4) ++ G.nokeys = G.escape_count = 0; ++ break; ++ default: ++ // Read the keys pressed ++ k = keybuf + G.key_count; ++ bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count); ++ if (bytes_read < 0) ++ cleanup(1); ++ ++ // Do exit processing ++ for (i = 0; i < bytes_read; i++) { ++ if (k[i] != '\033') G.escape_count = 0; ++ else if (++G.escape_count >= 3) ++ cleanup(0); ++ } ++ } ++ poll_timeout_ms = 250; ++ ++ // Insert all keys pressed into the virtual console's input ++ // buffer. Don't do this if the virtual console is in scan ++ // code mode - giving ASCII characters to a program expecting ++ // scan codes will confuse it. ++ if (!(option_mask32 & FLAG(v)) && G.escape_count == 0) { ++ int handle, result; ++ long kbd_mode; ++ ++ G.key_count += bytes_read; ++ handle = xopen(tty_name, O_WRONLY); ++ result = ioctl(handle, KDGKBMODE, &kbd_mode); ++ if (result == -1) ++ /* nothing */; ++ else if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) ++ G.key_count = 0; // scan code mode ++ else { ++ for (i = 0; i < G.key_count && result != -1; i++) ++ result = ioctl(handle, TIOCSTI, keybuf + i); ++ G.key_count -= i; ++ if (G.key_count) ++ memmove(keybuf, keybuf + i, G.key_count); ++ // If there is an application on console which reacts ++ // to keypresses, we need to make our first sleep ++ // shorter to quickly redraw whatever it printed there. ++ poll_timeout_ms = 20; ++ } ++ // Close & re-open tty in case they have ++ // swapped virtual consoles ++ close(handle); ++ ++ // We sometimes get spurious IO errors on the TTY ++ // as programs close and re-open it ++ if (result != -1) ++ G.ioerror_count = 0; ++ else if (errno != EIO || ++G.ioerror_count > 4) ++ cleanup(1); ++ } + } -+ } -+ fwrite(end,sizeof(end),1,stdout); -+ return 0; +}