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/script.c | |
| 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/script.c')
| -rw-r--r-- | usr.bin/script/script.c | 145 |
1 files changed, 134 insertions, 11 deletions
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); +} |
