Source-Changes-HG archive

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

[src/trunk]: src/usr.bin/script Add an alternate "typescript mode" that conta...



details:   https://anonhg.NetBSD.org/src/rev/1c46c2d77605
branches:  trunk
changeset: 533114:1c46c2d77605
user:      atatat <atatat%NetBSD.org@localhost>
date:      Fri Jun 21 18:46:31 2002 +0000

description:
Add an alternate "typescript mode" that contains timestamps and other
data interleaved between chunks of actual output (and input), and
teach script how to read the new format so that sessions can be played
back at "proper" time.

diffstat:

 usr.bin/script/script.1 |   10 ++-
 usr.bin/script/script.c |  145 ++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 142 insertions(+), 13 deletions(-)

diffs (273 lines):

diff -r c8f50dbadfce -r 1c46c2d77605 usr.bin/script/script.1
--- a/usr.bin/script/script.1   Fri Jun 21 16:03:33 2002 +0000
+++ b/usr.bin/script/script.1   Fri Jun 21 18:46:31 2002 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: script.1,v 1.6 2001/12/01 16:43:24 wiz Exp $
+.\"    $NetBSD: script.1,v 1.7 2002/06/21 18:46:31 atatat Exp $
 .\"
 .\" Copyright (c) 1980, 1990, 1993
 .\"    The Regents of the University of California.  All rights reserved.
@@ -41,7 +41,7 @@
 .Nd make typescript of terminal session
 .Sh SYNOPSIS
 .Nm
-.Op Fl a
+.Op Fl adpr
 .Op Ar file
 .Sh DESCRIPTION
 .Nm
@@ -68,6 +68,12 @@
 or
 .Pa typescript ,
 retaining the prior contents.
+.It Fl d
+Don't sleep between records when playing back a timestamped session.
+.It Fl p
+Play back a recorded session in real time.
+.It Fl r
+Record a session with input, output, and timestamping.
 .El
 .Pp
 The script ends when the forked shell exits (a
diff -r c8f50dbadfce -r 1c46c2d77605 usr.bin/script/script.c
--- a/usr.bin/script/script.c   Fri Jun 21 16:03:33 2002 +0000
+++ b/usr.bin/script/script.c   Fri Jun 21 18:46:31 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: script.c,v 1.7 1998/12/19 21:53:56 christos Exp $      */
+/*     $NetBSD: script.c,v 1.8 2002/06/21 18:46:31 atatat Exp $        */
 
 /*
  * Copyright (c) 1980, 1992, 1993
@@ -43,7 +43,7 @@
 #if 0
 static char sccsid[] = "@(#)script.c   8.1 (Berkeley) 6/6/93";
 #endif
-__RCSID("$NetBSD: script.c,v 1.7 1998/12/19 21:53:56 christos Exp $");
+__RCSID("$NetBSD: script.c,v 1.8 2002/06/21 18:46:31 atatat Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -51,6 +51,7 @@
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
+#include <sys/uio.h>
 
 #include <err.h>
 #include <errno.h>
@@ -66,10 +67,18 @@
 #include <unistd.h>
 #include <util.h>
 
+struct stamp {
+       uint64_t scr_len;       /* amount of data */
+       uint64_t scr_sec;       /* time it arrived in seconds... */
+       uint32_t scr_usec;      /* ...and microseconds */
+       uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
+};
+
 FILE   *fscript;
 int    master, slave;
 int    child, subchild;
 int    outcc;
+int    usesleep, rawout;
 char   *fname;
 
 struct termios tt;
@@ -81,6 +90,8 @@
 void   finish __P((int));
 int    main __P((int, char **));
 void   scriptflush __P((int));
+void   record __P((FILE *, char *, size_t, int));
+void   playback __P((FILE *));
 
 int
 main(argc, argv)
@@ -90,18 +101,30 @@
        int cc;
        struct termios rtt;
        struct winsize win;
-       int aflg, ch;
+       int aflg, pflg, ch;
        char ibuf[BUFSIZ];
 
        aflg = 0;
-       while ((ch = getopt(argc, argv, "a")) != -1)
+       pflg = 0;
+       usesleep = 1;
+       rawout = 0;
+       while ((ch = getopt(argc, argv, "adpr")) != -1)
                switch(ch) {
                case 'a':
                        aflg = 1;
                        break;
+               case 'd':
+                       usesleep = 0;
+                       break;
+               case 'p':
+                       pflg = 1;
+                       break;
+               case 'r':
+                       rawout = 1;
+                       break;
                case '?':
                default:
-                       (void)fprintf(stderr, "usage: script [-a] [file]\n");
+                       (void)fprintf(stderr, "usage: script [-apr] [file]\n");
                        exit(1);
                }
        argc -= optind;
@@ -112,9 +135,12 @@
        else
                fname = "typescript";
 
-       if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
+       if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
                err(1, "fopen %s", fname);
 
+       if (pflg)
+               playback(fscript);
+
        (void)tcgetattr(STDIN_FILENO, &tt);
        (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
        if (openpty(&master, &slave, NULL, &tt, &win) == -1)
@@ -144,9 +170,13 @@
                        doshell();
        }
 
-       (void)fclose(fscript);
-       while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0)
+       if (!rawout)
+               (void)fclose(fscript);
+       while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) {
+               if (rawout)
+                       record(fscript, ibuf, cc, 'i');
                (void)write(master, ibuf, cc);
+       }
        done();
        /* NOTREACHED */
        return (0);
@@ -177,7 +207,10 @@
 
        (void)close(STDIN_FILENO);
        tvec = time(NULL);
-       (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
+       if (rawout)
+               record(fscript, NULL, 0, 's');
+       else
+               (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
 
        (void)signal(SIGALRM, scriptflush);
        value.it_interval.tv_sec = SECSPERMIN / 2;
@@ -189,7 +222,10 @@
                if (cc <= 0)
                        break;
                (void)write(1, obuf, cc);
-               (void)fwrite(obuf, 1, cc, fscript);
+               if (rawout)
+                       record(fscript, obuf, cc, 'o');
+               else
+                       (void)fwrite(obuf, 1, cc, fscript);
                outcc += cc;
        }
        done();
@@ -237,7 +273,11 @@
 
        if (subchild) {
                tvec = time(NULL);
-               (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
+               if (rawout)
+                       record(fscript, NULL, 0, 'e');
+               else
+                       (void)fprintf(fscript,"\nScript done on %s",
+                           ctime(&tvec));
                (void)fclose(fscript);
                (void)close(master);
        } else {
@@ -246,3 +286,86 @@
        }
        exit(0);
 }
+
+void
+record(fscript, buf, cc, direction)
+       FILE *fscript;
+       char *buf;
+       size_t cc;
+       int direction;
+{
+       struct iovec iov[2];
+       struct stamp stamp;
+       struct timeval tv;
+
+       (void)gettimeofday(&tv, NULL);
+       stamp.scr_len = cc;
+       stamp.scr_sec = tv.tv_sec;
+       stamp.scr_usec = tv.tv_usec;
+       stamp.scr_direction = direction;
+       iov[0].iov_len = sizeof(stamp);
+       iov[0].iov_base = &stamp;
+       iov[1].iov_len = cc;
+       iov[1].iov_base = buf;
+       if (writev(fileno(fscript), &iov[0], 2) == -1)
+               err(1, "writev");
+}
+
+#define swapstamp(stamp) do { \
+       if (stamp.scr_direction > 0xff) { \
+               stamp.scr_len = bswap64(stamp.scr_len); \
+               stamp.scr_sec = bswap64(stamp.scr_sec); \
+               stamp.scr_usec = bswap32(stamp.scr_usec); \
+               stamp.scr_direction = bswap32(stamp.scr_direction); \
+       } \
+} while (0/*CONSTCOND*/)
+
+void
+playback(fscript)
+       FILE *fscript;
+{
+       struct timespec tsi, tso;
+       struct stamp stamp;
+       char buf[BUFSIZ];
+       size_t l;
+       time_t clock;
+
+       do {
+               if (fread(&stamp, sizeof(stamp), 1, fscript) != 1)
+                       err(1, "reading playback header");
+
+               swapstamp(stamp);
+               l = fread(buf, 1, stamp.scr_len, fscript);
+               clock = stamp.scr_sec;
+               tso.tv_sec = stamp.scr_sec;
+               tso.tv_nsec = stamp.scr_usec * 1000;
+
+               switch (stamp.scr_direction) {
+               case 's':
+                       (void)printf("Script started on %s", ctime(&clock));
+                       tsi = tso;
+                       break;
+               case 'e':
+                       (void)printf("\nScript done on %s", ctime(&clock));
+                       break;
+               case 'i':
+                       /* throw input away */
+                       break;
+               case 'o':
+                       tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
+                       tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
+                       if (tsi.tv_nsec < 0) {
+                               tsi.tv_sec -= 1;
+                               tsi.tv_nsec += 1000000000;
+                       }
+                       if (usesleep)
+                               (void)nanosleep(&tsi, NULL);
+                       tsi = tso;
+                       (void)write(STDOUT_FILENO, buf, l);
+                       break;
+               }
+       } while (stamp.scr_direction != 'e');
+
+       (void)fclose(fscript);
+       exit(0);
+}



Home | Main Index | Thread Index | Old Index