Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Apr 2024 05:29:28 GMT
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 2c24df87e3f8 - stable/14 - script: handle terminal resize on SIGWINCH
Message-ID:  <202404290529.43T5TS48047180@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=2c24df87e3f8af749cc7fc371aafd023b4331ef5

commit 2c24df87e3f8af749cc7fc371aafd023b4331ef5
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2024-04-26 16:12:00 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2024-04-29 05:29:02 +0000

    script: handle terminal resize on SIGWINCH
    
    Add a -w flag to forward terminal resize events on to the child, which
    can be useful in some circumstances to avoid terminal corruption.
    
    Reviewed by:    des
    Co-authored-by: Xavier Beaudouin <xavier.beaudouin@klarasystems.com>
    Sponsored by:   Modirum MDPay
    Sponsored by:   Klara, Inc.
    
    (cherry picked from commit 8ceac8e13dccbe4e177c8f2f443b87b7d2e3edb3)
---
 usr.bin/script/script.1 |  5 +++-
 usr.bin/script/script.c | 62 ++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 58 insertions(+), 9 deletions(-)

diff --git a/usr.bin/script/script.1 b/usr.bin/script/script.1
index 318ae4d743d9..bc096c0895c5 100644
--- a/usr.bin/script/script.1
+++ b/usr.bin/script/script.1
@@ -35,7 +35,7 @@
 .Nd make typescript of terminal session
 .Sh SYNOPSIS
 .Nm
-.Op Fl aeFfkqr
+.Op Fl aeFfkqrw
 .Op Fl t Ar time
 .Op Ar file Op Ar command ...
 .Nm
@@ -133,6 +133,9 @@ characters, it indicates the default format:
 which is useful for both tools and humans to read, should be used.
 Note that time-stamps will only be output when different from the
 previous one.
+.It Fl w
+Forward terminal size changes on
+.Dv SIGWINCH .
 .El
 .Pp
 The script ends when the forked shell (or command) exits (a
diff --git a/usr.bin/script/script.c b/usr.bin/script/script.c
index 3d82bad9ae2b..62f1399b6dc2 100644
--- a/usr.bin/script/script.c
+++ b/usr.bin/script/script.c
@@ -86,6 +86,7 @@ static char *fmfname;
 static int fflg, qflg, ttyflg;
 static int usesleep, rawout, showexit;
 static TAILQ_HEAD(, buf_elm) obuf_list = TAILQ_HEAD_INITIALIZER(obuf_list);
+static volatile sig_atomic_t doresize;
 
 static struct termios tt;
 
@@ -103,31 +104,43 @@ static void record(FILE *, char *, size_t, int);
 static void consume(FILE *, off_t, char *, int);
 static void playback(FILE *) __dead2;
 static void usage(void) __dead2;
+static void resizeit(int);
 
 int
 main(int argc, char *argv[])
 {
 	struct termios rtt, stt;
 	struct winsize win;
-	struct timeval tv, *tvp;
+	struct timespec tv, *tvp;
 	time_t tvec, start;
 	char obuf[BUFSIZ];
 	char ibuf[BUFSIZ];
+	sigset_t *pselmask, selmask;
 	fd_set rfd, wfd;
 	struct buf_elm *be;
 	ssize_t cc;
-	int aflg, Fflg, kflg, pflg, ch, k, n, fcm;
+	int aflg, Fflg, kflg, pflg, wflg, ch, k, n, fcm;
 	int flushtime, readstdin;
 	int fm_fd, fm_log;
 
-	aflg = Fflg = kflg = pflg = 0;
+	aflg = Fflg = kflg = pflg = wflg = 0;
+	doresize = 0;
 	usesleep = 1;
 	rawout = 0;
 	flushtime = 30;
 	fm_fd = -1;
 	showexit = 0;
 
-	while ((ch = getopt(argc, argv, "adeFfkpqrT:t:")) != -1)
+	/*
+	 * For normal operation, we'll leave pselmask == NULL so that pselect(2)
+	 * leaves the signal mask alone.  If -w is specified, we'll restore the
+	 * process signal mask upon entry with SIGWINCH unblocked so that we can
+	 * forward resize events properly.
+	 */
+	sigemptyset(&selmask);
+	pselmask = NULL;
+
+	while ((ch = getopt(argc, argv, "adeFfkpqrT:t:w")) != -1)
 		switch (ch) {
 		case 'a':
 			aflg = 1;
@@ -166,6 +179,9 @@ main(int argc, char *argv[])
 			if (strchr(optarg, '%'))
 				tstamp_fmt = optarg;
 			break;
+		case 'w':
+			wflg = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -269,6 +285,23 @@ main(int argc, char *argv[])
 	}
 	close(slave);
 
+	if (wflg) {
+		struct sigaction sa = { .sa_handler = resizeit };
+		sigset_t smask;
+
+		sigaction(SIGWINCH, &sa, NULL);
+
+		sigemptyset(&smask);
+		sigaddset(&smask, SIGWINCH);
+
+		if (sigprocmask(SIG_BLOCK, &smask, &selmask) != 0)
+			err(1, "Failed to block SIGWINCH");
+
+		/* Just in case SIGWINCH was blocked before we came in. */
+		sigdelset(&selmask, SIGWINCH);
+		pselmask = &selmask;
+	}
+
 	start = tvec = time(0);
 	readstdin = 1;
 	for (;;) {
@@ -281,19 +314,26 @@ main(int argc, char *argv[])
 			FD_SET(master, &wfd);
 		if (!readstdin && ttyflg) {
 			tv.tv_sec = 1;
-			tv.tv_usec = 0;
+			tv.tv_nsec = 0;
 			tvp = &tv;
 			readstdin = 1;
 		} else if (flushtime > 0) {
 			tv.tv_sec = flushtime - (tvec - start);
-			tv.tv_usec = 0;
+			tv.tv_nsec = 0;
 			tvp = &tv;
 		} else {
 			tvp = NULL;
 		}
-		n = select(master + 1, &rfd, &wfd, NULL, tvp);
+		n = pselect(master + 1, &rfd, &wfd, NULL, tvp, pselmask);
 		if (n < 0 && errno != EINTR)
 			break;
+
+		if (doresize) {
+			if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) != -1)
+				ioctl(master, TIOCSWINSZ, &win);
+			doresize = 0;
+		}
+
 		if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
 			cc = read(STDIN_FILENO, ibuf, BUFSIZ);
 			if (cc < 0)
@@ -368,7 +408,7 @@ static void
 usage(void)
 {
 	(void)fprintf(stderr,
-	    "usage: script [-aeFfkpqr] [-t time] [file [command ...]]\n");
+	    "usage: script [-aeFfkpqrw] [-t time] [file [command ...]]\n");
 	(void)fprintf(stderr,
 	    "       script -p [-deq] [-T fmt] [file]\n");
 	exit(1);
@@ -614,3 +654,9 @@ playback(FILE *fp)
 	(void)fclose(fp);
 	exit(0);
 }
+
+static void
+resizeit(int signo __unused)
+{
+	doresize = 1;
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202404290529.43T5TS48047180>