summaryrefslogtreecommitdiff
path: root/usr.bin/script
diff options
context:
space:
mode:
authoratatat <atatat@NetBSD.org>2002-06-21 18:46:31 +0000
committeratatat <atatat@NetBSD.org>2002-06-21 18:46:31 +0000
commit8f6bada139d693b7973db2f3e8d45376d3075067 (patch)
tree4a94496bf49b2792ea2afdcb2e848d568c40256c /usr.bin/script
parent3d7cdd4ec5be85062a2165f848e54ce5f6137c69 (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.110
-rw-r--r--usr.bin/script/script.c145
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);
+}