wok diff busybox/stuff/busybox-1.16.1-vcsa2txt.u @ rev 5711

busybox: add conspy
author Pascal Bellard <pascal.bellard@slitaz.org>
date Wed Jun 23 21:48:13 2010 +0200 (2010-06-23)
parents 2a5e098a34ac
children 42de4dc1d8d6
line diff
     1.1 --- a/busybox/stuff/busybox-1.16.1-vcsa2txt.u	Fri Jun 04 17:00:07 2010 +0200
     1.2 +++ b/busybox/stuff/busybox-1.16.1-vcsa2txt.u	Wed Jun 23 21:48:13 2010 +0200
     1.3 @@ -1,6 +1,14 @@
     1.4  --- busybox-1.16.1/include/applets.h
     1.5  +++ busybox-1.16.1/include/applets.h
     1.6 -@@ -420,6 +420,7 @@
     1.7 +@@ -105,6 +105,7 @@
     1.8 + IF_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_DROP))
     1.9 + IF_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_DROP))
    1.10 + IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP))
    1.11 ++IF_VCSA2TXT(APPLET(conspy, _BB_DIR_USR_BIN, _BB_SUID_DROP))
    1.12 + IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_DROP, cp))
    1.13 + IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_DROP))
    1.14 + IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
    1.15 +@@ -420,6 +421,7 @@
    1.16   IF_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_DROP))
    1.17   IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_DROP))
    1.18   IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_DROP))
    1.19 @@ -11,14 +19,38 @@
    1.20  
    1.21  --- busybox-1.16.1/include/usage.h
    1.22  +++ busybox-1.16.1/include/usage.h
    1.23 -@@ -5011,6 +5011,13 @@
    1.24 +@@ -440,6 +440,23 @@
    1.25 +      "\n	-1		Close stdout" \
    1.26 +      "\n	-2		Close stderr" \
    1.27 + 
    1.28 ++#define conspy_trivial_usage \
    1.29 ++	"[-vcsnd] [-x rows] [-y lines] [virtual_console]"
    1.30 ++#define conspy_full_usage "\n\n" \
    1.31 ++	"A text-mode VNC like program for Linux virtual terminals.\n" \
    1.32 ++	"\nTo exit, quickly press escape 3 times.\n" \
    1.33 ++	"\nvirtual_console:\n" \
    1.34 ++	"  omitted  Track the current console.\n" \
    1.35 ++	"  1..63    Virtual console N.\n" \
    1.36 ++	"\nOptions:" \
    1.37 ++	"\n	-v	Don't send keystrokes to the console." \
    1.38 ++	"\n	-c	May create device in /dev." \
    1.39 ++	"\n	-s	Open a SHELL session." \
    1.40 ++	"\n	-n	No colors. Black & white only." \
    1.41 ++	"\n	-d	Dump console to stdout."\
    1.42 ++	"\n	-x r	Skip the r first rows."\
    1.43 ++	"\n	-y l	Skip the l first lines."\
    1.44 ++
    1.45 + #define setuidgid_trivial_usage \
    1.46 +        "USER PROG ARGS"
    1.47 + #define setuidgid_full_usage "\n\n" \
    1.48 +@@ -5011,6 +5028,13 @@
    1.49        "\n	set_ingress_map	[vlan-name] [skb_priority] [vlan_qos]" \
    1.50        "\n	set_name_type	[name-type]" \
    1.51   
    1.52  +#define vcsa2txt_trivial_usage \
    1.53  +       "stdin"
    1.54  +#define vcsa2txt_full_usage \
    1.55 -+       "Filter /dev/vcsa* to ansi escape sequences"
    1.56 ++       "	Filter /dev/vcsa* to ansi escape sequences"
    1.57  +#define vcsa2txt_example_usage \
    1.58  +       "# vcsa2txt < /dev/vcsa1\n"
    1.59  +
    1.60 @@ -33,7 +65,7 @@
    1.61   	  Write a message to all users that are logged in.
    1.62   
    1.63  +config VCSA2TXT
    1.64 -+	bool "vcsa2txt"
    1.65 ++	bool "vcsa2txt/conspy"
    1.66  +	default n
    1.67  +	help
    1.68  +	  Filter /dev/vcsa* output to ansi escape sequences.
    1.69 @@ -52,83 +84,493 @@
    1.70  
    1.71  --- busybox-1.16.1/util-linux/vcsa2txt.c
    1.72  +++ busybox-1.16.1/util-linux/vcsa2txt.c
    1.73 -@@ -0,0 +1,79 @@
    1.74 +@@ -0,0 +1,489 @@
    1.75  +/* vi: set sw=4 ts=4: */
    1.76  +/*
    1.77 -+ * /dev/vcsa* filter for busybox
    1.78 ++ * A text-mode VNC like program for Linux virtual terminals.
    1.79  + *
    1.80  + * pascal.bellard@ads-lu.com
    1.81  + *
    1.82 ++ * Based on Russell Stuart's conspy.c
    1.83 ++ *   http://ace-host.stuart.id.au/russell/files/conspy.c
    1.84 ++ *
    1.85  + * Licensed under GPLv2 or later, see file License in this tarball for details.
    1.86 ++ *
    1.87 ++ * example :	conspy num		shared access to console num
    1.88 ++ * or		conspy -d num		screenshot of console num
    1.89 ++ * or		conspy -cs num		poor man's GNU screen like
    1.90  + */
    1.91 -+ 
    1.92 ++
    1.93 ++//applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP))
    1.94 ++
    1.95 ++//kbuild:lib-$(CONFIG_CONSPY) += conspy.o
    1.96 ++
    1.97 ++//config:config CONSPY
    1.98 ++//config:	bool "conspy"
    1.99 ++//config:	default n
   1.100 ++//config:	help
   1.101 ++//config:	  A text-mode VNC like program for Linux virtual terminals.
   1.102 ++//config:	  example : conspy num      shared access to console num
   1.103 ++//config:	  or        conspy -d num   screenshot of console num
   1.104 ++//config:	  or        conspy -cs num  poor man's GNU screen like
   1.105 ++
   1.106 ++//usage:#define conspy_trivial_usage
   1.107 ++//usage:     "[-vcsndf] [-x ROW] [-y LINE] [CONSOLE_NO]"
   1.108 ++//usage:#define conspy_full_usage "\n\n"
   1.109 ++//usage:     "A text-mode VNC like program for Linux virtual consoles."
   1.110 ++//usage:     "\nTo exit, quickly press ESC 3 times."
   1.111 ++//usage:     "\n"
   1.112 ++//usage:     "\nOptions:"
   1.113 ++//usage:     "\n	-v	Don't send keystrokes to the console"
   1.114 ++//usage:     "\n	-c	Create missing devices in /dev"
   1.115 ++//usage:     "\n	-s	Open a SHELL session"
   1.116 ++//usage:     "\n	-n	Black & white"
   1.117 ++//usage:     "\n	-d	Dump console to stdout"
   1.118 ++//usage:     "\n	-f	Follow cursor"
   1.119 ++//usage:     "\n	-x ROW	Starting row"
   1.120 ++//usage:     "\n	-y LINE	Starting line"
   1.121 ++
   1.122  +#include "libbb.h"
   1.123 ++#include <sys/kd.h>
   1.124 ++
   1.125 ++struct screen_info {
   1.126 ++	unsigned char lines, rows, cursor_x, cursor_y;
   1.127 ++};
   1.128 ++
   1.129 ++#define CHAR(x) ((x)[0])
   1.130 ++#define ATTR(x) ((x)[1])
   1.131 ++#define NEXT(x) ((x)+=2)
   1.132 ++#define DATA(x) (* (short *) (x))
   1.133 ++
   1.134 ++struct globals {
   1.135 ++	char* data;
   1.136 ++	int size;
   1.137 ++	int x, y;
   1.138 ++	int kbd_fd;
   1.139 ++	unsigned width;
   1.140 ++	unsigned height;
   1.141 ++	char last_attr;
   1.142 ++	int ioerror_count;
   1.143 ++	int key_count;
   1.144 ++	int escape_count;
   1.145 ++	int nokeys;
   1.146 ++	int current;
   1.147 ++	int vcsa_fd;
   1.148 ++	struct screen_info info;
   1.149 ++	struct termios term_orig;
   1.150 ++};
   1.151 ++
   1.152 ++#define G (*ptr_to_globals)
   1.153 ++#define INIT_G() do { \
   1.154 ++	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
   1.155 ++} while (0)
   1.156 ++
   1.157 ++enum {
   1.158 ++	FLAG_v,  // view only
   1.159 ++	FLAG_c,  // create device if need
   1.160 ++	FLAG_s,  // session
   1.161 ++	FLAG_n,  // no colors
   1.162 ++	FLAG_d,  // dump screen
   1.163 ++	FLAG_f,  // follow cursor
   1.164 ++};
   1.165 ++#define FLAG(x) (1 << FLAG_##x)
   1.166 ++#define BW (option_mask32 & FLAG(n))
   1.167 ++
   1.168 ++static void screen_read_close(void)
   1.169 ++{
   1.170 ++	unsigned i, j;
   1.171 ++	char *data = G.data + G.current;
   1.172 ++
   1.173 ++	xread(G.vcsa_fd, data, G.size);
   1.174 ++	G.last_attr = 0;
   1.175 ++	for (i = 0; i < G.info.lines; i++) {
   1.176 ++		for (j = 0; j < G.info.rows; j++, NEXT(data)) {
   1.177 ++			unsigned x = j - G.x; // if will catch j < G.x too
   1.178 ++			unsigned y = i - G.y; // if will catch i < G.y too
   1.179 ++
   1.180 ++			if (CHAR(data) < ' ')
   1.181 ++				CHAR(data) = ' ';
   1.182 ++			if (y >= G.height || x >= G.width)
   1.183 ++				DATA(data) = 0;
   1.184 ++		}
   1.185 ++	}
   1.186 ++	close(G.vcsa_fd);
   1.187 ++}
   1.188 ++
   1.189 ++static void screen_char(char *data)
   1.190 ++{
   1.191 ++	if (!BW && G.last_attr != ATTR(data)) {
   1.192 ++		//                            BLGCRMOW
   1.193 ++		static const char color[8] = "04261537";
   1.194 ++
   1.195 ++		printf("\033[%c;4%c;3%cm",
   1.196 ++			(ATTR(data) & 8) ? '1'  // bold
   1.197 ++					 : '0', // defaults
   1.198 ++			color[(ATTR(data) >> 4) & 7], color[ATTR(data) & 7]);
   1.199 ++		G.last_attr = ATTR(data);
   1.200 ++	}
   1.201 ++	bb_putchar(CHAR(data));
   1.202 ++}
   1.203 ++
   1.204 ++#define clrscr()  printf("\033[1;1H" "\033[0J")
   1.205 ++#define curoff()  printf("\033[?25l")
   1.206 ++
   1.207 ++static void curon(void)
   1.208 ++{
   1.209 ++	printf("\033[?25h");
   1.210 ++}
   1.211 ++
   1.212 ++static void gotoxy(int row, int line)
   1.213 ++{
   1.214 ++	printf("\033[%u;%uH", line + 1, row + 1);
   1.215 ++}
   1.216 ++
   1.217 ++static void screen_dump(void)
   1.218 ++{
   1.219 ++	int linefeed_cnt;
   1.220 ++	int line, row;
   1.221 ++	int linecnt = G.info.lines - G.y;
   1.222 ++	char *data = G.data + G.current + (2 * G.y * G.info.rows);
   1.223 ++
   1.224 ++	linefeed_cnt = 0;
   1.225 ++	for (line = 0; line < linecnt && line < G.height; line++) {
   1.226 ++		int space_cnt = 0;
   1.227 ++		for (row = 0; row < G.info.rows; row++, NEXT(data)) {
   1.228 ++			unsigned tty_row = row - G.x; // if will catch row < G.x too
   1.229 ++
   1.230 ++			if (tty_row >= G.width)
   1.231 ++				continue;
   1.232 ++			space_cnt++;
   1.233 ++			if (BW && (CHAR(data) | ' ') == ' ')
   1.234 ++				continue;
   1.235 ++			while (linefeed_cnt != 0) {
   1.236 ++				bb_putchar('\r');
   1.237 ++				bb_putchar('\n');
   1.238 ++				linefeed_cnt--;
   1.239 ++			}
   1.240 ++			while (--space_cnt)
   1.241 ++				bb_putchar(' ');
   1.242 ++			screen_char(data);
   1.243 ++		}
   1.244 ++		linefeed_cnt++;
   1.245 ++	}
   1.246 ++}
   1.247 ++
   1.248 ++static void curmove(void)
   1.249 ++{
   1.250 ++	unsigned cx = G.info.cursor_x - G.x;
   1.251 ++	unsigned cy = G.info.cursor_y - G.y;
   1.252 ++
   1.253 ++	if (cx >= G.width || cy >= G.height) {
   1.254 ++		curoff();
   1.255 ++	} else {
   1.256 ++		curon();
   1.257 ++		gotoxy(cx, cy);
   1.258 ++	}
   1.259 ++	fflush_all();
   1.260 ++}
   1.261 ++
   1.262 ++static void cleanup(int code)
   1.263 ++{
   1.264 ++	curon();
   1.265 ++	fflush_all();
   1.266 ++	tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig);
   1.267 ++	if (ENABLE_FEATURE_CLEAN_UP) {
   1.268 ++		free(ptr_to_globals);
   1.269 ++		close(G.kbd_fd);
   1.270 ++	}
   1.271 ++	// Reset attributes
   1.272 ++	if (!BW)
   1.273 ++		printf("\033[0m");
   1.274 ++	bb_putchar('\n');
   1.275 ++	if (code > 1)
   1.276 ++		kill_myself_with_sig(code); // does not return
   1.277 ++	exit(code);
   1.278 ++}
   1.279 ++
   1.280 ++static void get_initial_data(const char* vcsa_name)
   1.281 ++{
   1.282 ++	G.vcsa_fd = xopen(vcsa_name, O_RDONLY);
   1.283 ++	xread(G.vcsa_fd, &G.info, 4);
   1.284 ++	G.size = G.info.rows * G.info.lines * 2;
   1.285 ++	G.width = G.height = UINT_MAX;
   1.286 ++	G.data = xzalloc(2 * G.size);
   1.287 ++	screen_read_close();
   1.288 ++}
   1.289 ++
   1.290 ++static void create_cdev_if_doesnt_exist(const char* name, dev_t dev)
   1.291 ++{
   1.292 ++	int fd = open(name, O_RDONLY);
   1.293 ++	if (fd != -1)
   1.294 ++		close(fd);
   1.295 ++	else if (errno == ENOENT)
   1.296 ++		mknod(name, S_IFCHR | 0660, dev);
   1.297 ++}
   1.298 ++
   1.299 ++static NOINLINE void start_shell_in_child(const char* tty_name)
   1.300 ++{
   1.301 ++	int pid = vfork();
   1.302 ++	if (pid < 0) {
   1.303 ++		bb_perror_msg_and_die("vfork");
   1.304 ++	}
   1.305 ++	if (pid == 0) {
   1.306 ++		struct termios termchild;
   1.307 ++		char *shell = getenv("SHELL");
   1.308 ++
   1.309 ++		if (!shell)
   1.310 ++			shell = (char *) DEFAULT_SHELL;
   1.311 ++		signal(SIGHUP, SIG_IGN);
   1.312 ++		// set tty as a controlling tty
   1.313 ++		setsid();
   1.314 ++		// make tty to be input, output, error
   1.315 ++		close(0);
   1.316 ++		xopen(tty_name, O_RDWR); // uses fd 0
   1.317 ++		xdup2(0, 1);
   1.318 ++		xdup2(0, 2);
   1.319 ++		ioctl(0, TIOCSCTTY, 1);
   1.320 ++		tcsetpgrp(0, getpid());
   1.321 ++		tcgetattr(0, &termchild);
   1.322 ++		termchild.c_lflag |= ECHO;
   1.323 ++		termchild.c_oflag |= ONLCR | XTABS;
   1.324 ++		termchild.c_iflag |= ICRNL;
   1.325 ++		termchild.c_iflag &= ~IXOFF;
   1.326 ++		tcsetattr_stdin_TCSANOW(&termchild);
   1.327 ++		execl(shell, shell, "-i", (char *) NULL);
   1.328 ++		bb_simple_perror_msg_and_die(shell);
   1.329 ++	}
   1.330 ++}
   1.331  +
   1.332  +int vcsa2txt_main(int argc) MAIN_EXTERNALLY_VISIBLE;
   1.333  +int vcsa2txt_main(int argc)
   1.334  +{
   1.335 -+    struct {
   1.336 -+	unsigned char l, c, x, y; // man 4 console_codes
   1.337 -+    } scrn;
   1.338 -+    unsigned char last = 0, ch[2];                     // BLGCRMOW
   1.339 -+    static  unsigned char end[5] = "\e[0m\n", color[8] = "04261537";
   1.340 -+    int sp, lf, x;
   1.341 -+    
   1.342 -+    if (safe_read(0, &scrn, 4) < 0) return 1;
   1.343 -+    for (lf = 0; scrn.l; lf++, scrn.l--) {
   1.344 -+	for (sp = x = 0; ++x <= scrn.c;) {
   1.345 -+	    if (safe_read(0, &ch[0], 2) < 0) return 1;
   1.346 -+	    if (argc > 1) ch[1] = 0;
   1.347 -+	    sp++;
   1.348 -+	    if (last == ch[1] && ch[0] == ' ') continue;
   1.349 -+	    for (lf++; --lf;) bb_putchar('\n');
   1.350 -+	    while (--sp) bb_putchar(' ');
   1.351 -+#define ENABLE_VCSA_PACKED 1
   1.352 -+#if ENABLE_VCSA_PACKED
   1.353 -+	    if (last ^= ch[1]) {
   1.354 -+		char esc[16],*s;
   1.355 -+		struct offsets {
   1.356 -+		    char mask, type, shr;
   1.357 -+		} *p;
   1.358 -+		static struct offsets offset[3] = {
   1.359 -+		    {8,0,1}, {0x70,'4',4}, {7,'3',0}
   1.360 -+		};
   1.361 -+		static char init = 0x7F;
   1.362 ++	INIT_G();
   1.363 ++	option_mask32 = FLAG(n);
   1.364 ++	if (argc < 2) option_mask32 = 0;
   1.365 ++	xread(0, &G.info, 4);
   1.366 ++	G.size = G.info.rows * G.info.lines * 2;
   1.367 ++	G.width = G.height = UINT_MAX;
   1.368 ++	G.data = xzalloc(G.size);
   1.369 ++	screen_read_close();
   1.370 ++	screen_dump();
   1.371 ++	bb_putchar('\n');
   1.372 ++	if (ENABLE_FEATURE_CLEAN_UP) {
   1.373 ++		free(ptr_to_globals);
   1.374 ++		close(G.kbd_fd);
   1.375 ++	}
   1.376 ++	return 0;
   1.377 ++}
   1.378 ++
   1.379 ++int conspy_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE;
   1.380 ++int conspy_main(int argc UNUSED_PARAM, char **argv)
   1.381 ++{
   1.382 ++	char vcsa_name[sizeof("/dev/vcsa") + 2];
   1.383 ++	char tty_name[sizeof("/dev/tty") + 2];
   1.384 ++#define keybuf bb_common_bufsiz1
   1.385 ++	struct termios termbuf;
   1.386 ++	unsigned opts;
   1.387 ++	unsigned ttynum;
   1.388 ++	int poll_timeout_ms;
   1.389 ++#if ENABLE_LONG_OPTS
   1.390 ++	static const char getopt_longopts[] ALIGN1 =
   1.391 ++		"viewonly\0"     No_argument "v"
   1.392 ++		"createdevice\0" No_argument "c"
   1.393 ++		"session\0"      No_argument "s"
   1.394 ++		"nocolors\0"     No_argument "n"
   1.395 ++		"dump\0"         No_argument "d"
   1.396 ++		"follow\0"       No_argument "f"
   1.397 ++		;
   1.398 ++
   1.399 ++	applet_long_options = getopt_longopts;
   1.400 ++#endif
   1.401 ++	INIT_G();
   1.402 ++
   1.403 ++	opt_complementary = "x+:y+"; // numeric params
   1.404 ++	opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y);
   1.405 ++	argv += optind;
   1.406 ++	ttynum = 0;
   1.407 ++	if (argv[0]) {
   1.408 ++		ttynum = xatou_range(argv[0], 0, 63);
   1.409 ++	}
   1.410 ++	sprintf(vcsa_name, "/dev/vcsa%u", ttynum);
   1.411 ++	sprintf(tty_name, "%s%u", "/dev/tty", ttynum);
   1.412 ++	if (opts & FLAG(c)) {
   1.413 ++		if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v))
   1.414 ++			create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum));
   1.415 ++		create_cdev_if_doesnt_exist(vcsa_name, makedev(7, 128 + ttynum));
   1.416 ++	}
   1.417 ++	if ((opts & FLAG(s)) && ttynum) {
   1.418 ++		start_shell_in_child(tty_name);
   1.419 ++	}
   1.420 ++
   1.421 ++	get_initial_data(vcsa_name);
   1.422 ++	G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY);
   1.423 ++	if (opts & FLAG(d)) {
   1.424 ++		screen_dump();
   1.425 ++		bb_putchar('\n');
   1.426 ++		if (ENABLE_FEATURE_CLEAN_UP) {
   1.427 ++			free(ptr_to_globals);
   1.428 ++			close(G.kbd_fd);
   1.429 ++		}
   1.430 ++		return 0;
   1.431 ++	}
   1.432 ++
   1.433 ++	bb_signals(BB_FATAL_SIGS, cleanup);
   1.434 ++	// All characters must be passed through to us unaltered
   1.435 ++	tcgetattr(G.kbd_fd, &G.term_orig);
   1.436 ++	termbuf = G.term_orig;
   1.437 ++	termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL);
   1.438 ++	termbuf.c_oflag &= ~(OPOST);
   1.439 ++	termbuf.c_lflag &= ~(ISIG|ICANON|ECHO);
   1.440 ++	termbuf.c_cc[VMIN] = 1;
   1.441 ++	termbuf.c_cc[VTIME] = 0;
   1.442 ++	tcsetattr(G.kbd_fd, TCSANOW, &termbuf);
   1.443 ++	poll_timeout_ms = 250;
   1.444 ++	while (1) {
   1.445 ++		struct pollfd pfd;
   1.446 ++		int bytes_read;
   1.447 ++		int i, j;
   1.448 ++		char *data, *old;
   1.449 ++
   1.450 ++		old = G.data + G.current;
   1.451 ++		G.current = G.size - G.current;
   1.452 ++		data = G.data + G.current;
   1.453  +		
   1.454 -+		s = esc+2;
   1.455 -+		*(short *)esc = ntohs(256*'\e'+'[');
   1.456 -+		p = offset;
   1.457 -+		do {
   1.458 -+		    if ((init|last) & p->mask) {
   1.459 -+			int c = (ch[1] & p->mask) >> p->shr;
   1.460 -+		    
   1.461 -+			if ((*s = p->type) != 0) s++;
   1.462 -+			else if (c == 0) {
   1.463 -+			    c = 2;
   1.464 -+			    *s++ = '2'; /* normal */
   1.465 ++		// Close & re-open vcsa in case they have
   1.466 ++		// swapped virtual consoles
   1.467 ++		G.vcsa_fd = xopen(vcsa_name, O_RDONLY);
   1.468 ++		xread(G.vcsa_fd, &G.info, 4);
   1.469 ++		if (G.size != (G.info.rows * G.info.lines * 2)) {
   1.470 ++			cleanup(1);
   1.471 ++		}
   1.472 ++		i = G.width;
   1.473 ++		j = G.height;
   1.474 ++		get_terminal_width_height(G.kbd_fd, &G.width, &G.height);
   1.475 ++		if ((option_mask32 & FLAG(f))) {
   1.476 ++			int nx = G.info.cursor_x - G.width + 1;
   1.477 ++			int ny = G.info.cursor_y - G.height + 1;
   1.478 ++
   1.479 ++			if (G.info.cursor_x < G.x) {
   1.480 ++				G.x = G.info.cursor_x;
   1.481 ++				i = 0;	// force refresh
   1.482  +			}
   1.483 -+			*s++ = color[c];
   1.484 -+			*s++ = ';'; 
   1.485 -+		    }
   1.486 -+		} while (p++->shr);
   1.487 -+		s[-1] = 'm';
   1.488 -+		init = 0;
   1.489 -+		fwrite(esc,s-esc,1,stdout);
   1.490 -+	    }
   1.491 -+	    last = ch[1];
   1.492 -+#else
   1.493 -+	    if (last != ch[1]) {
   1.494 -+		static char esc[10] = "\e[0;47;37m";
   1.495 -+		
   1.496 -+		esc[2] = ((last = ch[1]) & 8) ? '1' /* bold */ : '0' /* defaults */;
   1.497 -+		esc[sizeof(esc)-5] = color[(ch[1] >> 4) & 7];
   1.498 -+		esc[sizeof(esc)-2] = color[ch[1] & 7];
   1.499 -+		fwrite(esc,sizeof(esc),1,stdout);
   1.500 -+	    }
   1.501 -+#endif
   1.502 -+	    bb_putchar(ch[0]);
   1.503 ++			if (nx > G.x) {
   1.504 ++				G.x = nx;
   1.505 ++				i = 0;	// force refresh
   1.506 ++			}
   1.507 ++			if (G.info.cursor_y < G.y) {
   1.508 ++				G.y = G.info.cursor_y;
   1.509 ++				i = 0;	// force refresh
   1.510 ++			}
   1.511 ++			if (ny > G.y) {
   1.512 ++				G.y = ny;
   1.513 ++				i = 0;	// force refresh
   1.514 ++			}
   1.515 ++		}
   1.516 ++
   1.517 ++		// Scan console data and redraw our tty where needed
   1.518 ++		screen_read_close();
   1.519 ++		if (i != G.width || j != G.height) {
   1.520 ++			clrscr();
   1.521 ++			screen_dump();
   1.522 ++		}
   1.523 ++		else for (i = 0; i < G.info.lines; i++) {
   1.524 ++			char *last = last;
   1.525 ++			char *first = NULL;
   1.526 ++			int iy = i - G.y;
   1.527 ++
   1.528 ++			if (iy >= (int) G.height)
   1.529 ++				break;
   1.530 ++			for (j = 0; j < G.info.rows; j++) {
   1.531 ++				last = data;
   1.532 ++				if (DATA(data) != DATA(old) && iy >= 0) {
   1.533 ++					unsigned jx = j - G.x;
   1.534 ++
   1.535 ++					last = NULL;
   1.536 ++					if (first == NULL && jx < G.width) {
   1.537 ++						first = data;
   1.538 ++						gotoxy(jx, iy);
   1.539 ++					}
   1.540 ++				}
   1.541 ++				NEXT(old);
   1.542 ++				NEXT(data);
   1.543 ++			}
   1.544 ++			if (first == NULL)
   1.545 ++				continue;
   1.546 ++			if (last == NULL)
   1.547 ++				last = data;
   1.548 ++
   1.549 ++			// Write the data to the screen
   1.550 ++			for (; first < last; NEXT(first))
   1.551 ++				screen_char(first);
   1.552 ++		}
   1.553 ++		curmove();
   1.554 ++
   1.555 ++		// Wait for local user keypresses
   1.556 ++		pfd.fd = G.kbd_fd;
   1.557 ++		pfd.events = POLLIN;
   1.558 ++		bytes_read = 0;
   1.559 ++		switch (poll(&pfd, 1, poll_timeout_ms)) {
   1.560 ++			char *k;
   1.561 ++		case -1:
   1.562 ++			if (errno != EINTR)
   1.563 ++				cleanup(1);
   1.564 ++			break;
   1.565 ++		case 0:
   1.566 ++			if (++G.nokeys >= 4)
   1.567 ++				G.nokeys = G.escape_count = 0;
   1.568 ++			break;
   1.569 ++		default:
   1.570 ++			// Read the keys pressed
   1.571 ++			k = keybuf + G.key_count;
   1.572 ++			bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count);
   1.573 ++			if (bytes_read < 0)
   1.574 ++				cleanup(1);
   1.575 ++
   1.576 ++			// Do exit processing
   1.577 ++			for (i = 0; i < bytes_read; i++) {
   1.578 ++				if (k[i] != '\033') G.escape_count = 0;
   1.579 ++				else if (++G.escape_count >= 3)
   1.580 ++					cleanup(0);
   1.581 ++			}
   1.582 ++		}
   1.583 ++		poll_timeout_ms = 250;
   1.584 ++
   1.585 ++		// Insert all keys pressed into the virtual console's input
   1.586 ++		// buffer.  Don't do this if the virtual console is in scan
   1.587 ++		// code mode - giving ASCII characters to a program expecting
   1.588 ++		// scan codes will confuse it.
   1.589 ++		if (!(option_mask32 & FLAG(v)) && G.escape_count == 0) {
   1.590 ++			int handle, result;
   1.591 ++			long kbd_mode;
   1.592 ++
   1.593 ++			G.key_count += bytes_read;
   1.594 ++			handle = xopen(tty_name, O_WRONLY);
   1.595 ++			result = ioctl(handle, KDGKBMODE, &kbd_mode);
   1.596 ++			if (result == -1)
   1.597 ++				/* nothing */;
   1.598 ++			else if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE)
   1.599 ++				G.key_count = 0; // scan code mode
   1.600 ++			else {
   1.601 ++				for (i = 0; i < G.key_count && result != -1; i++)
   1.602 ++					result = ioctl(handle, TIOCSTI, keybuf + i);
   1.603 ++				G.key_count -= i;
   1.604 ++				if (G.key_count)
   1.605 ++					memmove(keybuf, keybuf + i, G.key_count);
   1.606 ++				// If there is an application on console which reacts
   1.607 ++				// to keypresses, we need to make our first sleep
   1.608 ++				// shorter to quickly redraw whatever it printed there.
   1.609 ++				poll_timeout_ms = 20;
   1.610 ++			}
   1.611 ++			// Close & re-open tty in case they have
   1.612 ++			// swapped virtual consoles
   1.613 ++			close(handle);
   1.614 ++
   1.615 ++			// We sometimes get spurious IO errors on the TTY
   1.616 ++			// as programs close and re-open it
   1.617 ++			if (result != -1)
   1.618 ++				G.ioerror_count = 0;
   1.619 ++			else if (errno != EIO || ++G.ioerror_count > 4)
   1.620 ++				cleanup(1);
   1.621 ++		}
   1.622  +	}
   1.623 -+    }
   1.624 -+    fwrite(end,sizeof(end),1,stdout);
   1.625 -+    return 0;
   1.626  +}