The branch main has been updated by kevans:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=8ceac8e13dccbe4e177c8f2f443b87b7d2e3edb3

commit 8ceac8e13dccbe4e177c8f2f443b87b7d2e3edb3
Author:     Kyle Evans <kev...@freebsd.org>
AuthorDate: 2024-04-26 16:12:00 +0000
Commit:     Kyle Evans <kev...@freebsd.org>
CommitDate: 2024-04-26 16:39:00 +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.beaudo...@klarasystems.com>
    Sponsored by:   Modirum MDPay
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D44167
---
 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 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;
+}

Reply via email to