NetBSD-Bugs archive

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

bin/55528: [PATCH] script(1): Enable proper playback [-p] of curses sessions



>Number:         55528
>Category:       bin
>Synopsis:       [PATCH] script(1): Enable proper playback [-p] of curses sessions
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Aug 01 04:35:00 +0000 2020
>Originator:     Soumendra Ganguly
>Release:        9.0
>Organization:
Texas A&M University
>Environment:
NetBSD localhost 9.0 NetBSD 9.0 (GENERIC) #0: Fri Feb 14 00:06:28 UTC 2020  mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
The current manpage of script(1) says the following.

"Certain interactive commands, such as vi(1), create garbage in the typescript file. The script utility works best with commands that do not manipulate the screen. The results are meant to emulate a hardcopy terminal."

script(1) is currently able to record [-r] curses sessions perfectly; only the playback functionality [-p] has the above limitation; this patch removes this restriction by appropriately setting terminal attributes.

Additional notes:

. I submitted a similar patch for "scriptreplay(1)" from util-linux; it has now been merged by the maintainer of the project.

. I recently submitted a similar patch for the FreeBSD script(1): https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=248377
>How-To-Repeat:
I used https://github.com/iiSeymour/game-of-life to reproduce the problem; authored by GitHub user iiSeymour, this, in the words of the author, is "a python implementation of Conway's Game of Life using the curses module with a small evolutionary twist"; it was written for Linux; therefore, one must call "python gol.py" on NetBSD to bypass the "#!".
>Fix:
--- src/usr.bin/script/script.c	2020-07-31 21:46:07.624488522 -0500
+++ script.c	2020-07-31 23:08:02.805513450 -0500
@@ -29,6 +29,11 @@
  * SUCH DAMAGE.
  */
 
+/*
+ * 2020-07-31 Soumendra Ganguly <soumendraganguly%gmail.com@localhost>
+ * - fixed playback of curses sessions
+ */
+
 #include <sys/cdefs.h>
 #ifndef lint
 __COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\
@@ -81,6 +86,7 @@
 static int	quiet, flush;
 static const char *fname;
 
+static int qflg, ttyflg;
 static struct	termios tt;
 
 __dead static void	done(void);
@@ -328,19 +334,51 @@
 }
 
 static void
+termset()
+{
+	struct termios tattr;
+
+	ttyflg = isatty(STDOUT_FILENO);
+	if (!ttyflg)
+		return;
+
+	if (tcgetattr(STDOUT_FILENO, &tt) != 0)
+		err(1, "tcgetattr");
+
+	tattr = tt;
+	cfmakeraw(&tattr);
+	tattr.c_lflag |= ISIG;
+	if (tcsetattr(STDOUT_FILENO, TCSANOW, &tattr) != 0)
+		err(1, "tcsetattr");
+}
+
+static void
+termreset()
+{
+	if (ttyflg)
+		tcsetattr(STDOUT_FILENO, TCSADRAIN, &tt);
+
+	ttyflg = 0;
+}
+
+static void
 consume(FILE *fp, off_t len, char *buf, int reg)
 {
 	size_t l;
 
 	if (reg) {
-		if (fseeko(fp, len, SEEK_CUR) == -1)
+		if (fseeko(fp, len, SEEK_CUR) == -1) {
+			termreset();
 			err(1, NULL);
+		}
 	}
 	else {
 		while (len > 0) {
 			l = MIN(DEF_BUF, len);
-			if (fread(buf, sizeof(char), l, fp) != l)
+			if (fread(buf, sizeof(char), l, fp) != l) {
+				termreset();
 				err(1, "cannot read buffer");
+			}
 			len -= l;
 		}
 	}
@@ -367,24 +405,29 @@
 	time_t tclock;
 	int reg;
 
+	ttyflg = 0;
+
 	if (fstat(fileno(fp), &pst) == -1)
-		err(1, "fstat failed");	
+		err(1, "fstat failed");
 
 	reg = S_ISREG(pst.st_mode);
 
 	for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
 		if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
-			if (reg)
+			if (reg) {
+				termreset();
 				err(1, "reading playback header");
-			else
-				break;
+			}
+			break;
 		}
 		swapstamp(stamp);
 		save_len = sizeof(stamp);
 
 		if (reg && stamp.scr_len >
-		    (uint64_t)(pst.st_size - save_len) - nread)
+		    (uint64_t)(pst.st_size - save_len) - nread) {
+			termreset();
 			errx(1, "invalid stamp");
+		}
 
 		save_len += stamp.scr_len;
 		tclock = stamp.scr_sec;
@@ -393,14 +436,16 @@
 
 		switch (stamp.scr_direction) {
 		case 's':
-			if (!quiet)
+			if (!qflg)
 			    (void)printf("Script started on %s",
 				ctime(&tclock));
 			tsi = tso;
 			(void)consume(fp, stamp.scr_len, buf, reg);
+			termset();
 			break;
 		case 'e':
-			if (!quiet)
+			termreset();
+			if (!qflg)
 				(void)printf("\nScript done on %s",
 				    ctime(&tclock));
 			(void)consume(fp, stamp.scr_len, buf, reg);
@@ -421,17 +466,21 @@
 			tsi = tso;
 			while (stamp.scr_len > 0) {
 				l = MIN(DEF_BUF, stamp.scr_len);
-				if (fread(buf, sizeof(char), l, fp) != l)
+				if (fread(buf, sizeof(char), l, fp) != l) {
+					termreset();
 					err(1, "cannot read buffer");
+				}
 
 				(void)write(STDOUT_FILENO, buf, l);
 				stamp.scr_len -= l;
 			}
 			break;
 		default:
+			termreset();
 			errx(1, "invalid direction");
 		}
 	}
+	termreset();
 	(void)fclose(fp);
 	exit(0);
 }



Home | Main Index | Thread Index | Old Index