aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2024-04-26 16:12:00 +0000
committerKyle Evans <kevans@FreeBSD.org>2024-04-26 16:39:00 +0000
commit8ceac8e13dccbe4e177c8f2f443b87b7d2e3edb3 (patch)
tree67ef5d150a6840cbb1569c3392b3a2eaa2250339
parent4459abe334eb4dbd416fa8094a64afc065ccd1cc (diff)
downloadsrc-8ceac8e13dccbe4e177c8f2f443b87b7d2e3edb3.tar.gz
src-8ceac8e13dccbe4e177c8f2f443b87b7d2e3edb3.zip
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. Differential Revision: https://reviews.freebsd.org/D44167
-rw-r--r--usr.bin/script/script.15
-rw-r--r--usr.bin/script/script.c62
2 files changed, 58 insertions, 9 deletions
diff --git a/usr.bin/script/script.1 b/usr.bin/script/script.1
index 78e2feef3712..5f40e5af28ff 100644
--- a/usr.bin/script/script.1
+++ b/usr.bin/script/script.1
@@ -33,7 +33,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
@@ -131,6 +131,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 0373a6667784..cca265b8941b 100644
--- a/usr.bin/script/script.c
+++ b/usr.bin/script/script.c
@@ -77,6 +77,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;
@@ -94,31 +95,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;
@@ -157,6 +170,9 @@ main(int argc, char *argv[])
if (strchr(optarg, '%'))
tstamp_fmt = optarg;
break;
+ case 'w':
+ wflg = 1;
+ break;
case '?':
default:
usage();
@@ -260,6 +276,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 (;;) {
@@ -272,19 +305,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)
@@ -359,7 +399,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);
@@ -605,3 +645,9 @@ playback(FILE *fp)
(void)fclose(fp);
exit(0);
}
+
+static void
+resizeit(int signo __unused)
+{
+ doresize = 1;
+}