diff options
| author | atatat <atatat@NetBSD.org> | 2002-06-21 18:46:31 +0000 |
|---|---|---|
| committer | atatat <atatat@NetBSD.org> | 2002-06-21 18:46:31 +0000 |
| commit | 8f6bada139d693b7973db2f3e8d45376d3075067 (patch) | |
| tree | 4a94496bf49b2792ea2afdcb2e848d568c40256c /usr.bin/script | |
| parent | 3d7cdd4ec5be85062a2165f848e54ce5f6137c69 (diff) | |
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 (limited to 'usr.bin/script')
| -rw-r--r-- | usr.bin/script/script.1 | 10 | ||||
| -rw-r--r-- | usr.bin/script/script.c | 145 |
2 files changed, 142 insertions, 13 deletions
diff --git a/usr.bin/script/script.1 b/usr.bin/script/script.1 index 2f85aa7b29f..03bb7c0c2c4 100644 --- a/usr.bin/script/script.1 +++ b/usr.bin/script/script.1 @@ -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 @@ Append the output to 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 --git a/usr.bin/script/script.c b/usr.bin/script/script.c index 99b1ee67ff7..05703331da6 100644 --- a/usr.bin/script/script.c +++ b/usr.bin/script/script.c @@ -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 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\n\ #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 @@ __RCSID("$NetBSD: script.c,v 1.7 1998/12/19 21:53:56 christos Exp $"); #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 @@ __RCSID("$NetBSD: script.c,v 1.7 1998/12/19 21:53:56 christos Exp $"); #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 fail __P((void)); 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 @@ main(argc, argv) 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 @@ main(argc, argv) 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 @@ main(argc, argv) 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 @@ dooutput() (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 @@ dooutput() 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 @@ done() 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 @@ done() } 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); +} |
