1 /* $NetBSD: script.c,v 1.18 2009/10/17 19:05:54 christos Exp $ */
4 * Copyright (c) 1980, 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)script.c 8.1 (Berkeley) 6/6/93";
42 __RCSID("$NetBSD: script.c,v 1.18 2009/10/17 19:05:54 christos Exp $");
45 #include <sys/types.h>
48 #include <sys/ioctl.h>
50 #include <sys/param.h>
70 uint64_t scr_len
; /* amount of data */
71 uint64_t scr_sec
; /* time it arrived in seconds... */
72 uint32_t scr_usec
; /* ...and microseconds */
73 uint32_t scr_direction
; /* 'i', 'o', etc (also indicates endianness) */
88 void doshell(const char *);
91 int main(int, char **);
92 void scriptflush(int);
93 void record(FILE *, char *, size_t, int);
94 void consume(FILE *, off_t
, char *, int);
95 void playback(FILE *);
98 main(int argc
, char *argv
[])
114 while ((ch
= getopt(argc
, argv
, "ac:dfpqr")) != -1)
139 (void)fprintf(stderr
,
140 "Usage: %s [-c <command>][-adfpqr] [file]\n",
150 fname
= "typescript";
152 if ((fscript
= fopen(fname
, pflg
? "r" : aflg
? "a" : "w")) == NULL
)
153 err(1, "fopen %s", fname
);
158 (void)tcgetattr(STDIN_FILENO
, &tt
);
159 (void)ioctl(STDIN_FILENO
, TIOCGWINSZ
, &win
);
160 if (openpty(&master
, &slave
, NULL
, &tt
, &win
) == -1)
164 (void)printf("Script started, output file is %s\n", fname
);
167 rtt
.c_lflag
&= ~ECHO
;
168 (void)tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &rtt
);
170 (void)signal(SIGCHLD
, finish
);
177 subchild
= child
= fork();
189 (void)fclose(fscript
);
190 while ((cc
= read(STDIN_FILENO
, ibuf
, BUFSIZ
)) > 0) {
192 record(fscript
, ibuf
, cc
, 'i');
193 (void)write(master
, ibuf
, cc
);
203 int die
, pid
, status
;
206 while ((pid
= wait3(&status
, WNOHANG
, 0)) > 0)
217 struct itimerval value
;
222 (void)close(STDIN_FILENO
);
225 record(fscript
, NULL
, 0, 's');
227 (void)fprintf(fscript
, "Script started on %s", ctime(&tvec
));
229 (void)signal(SIGALRM
, scriptflush
);
230 value
.it_interval
.tv_sec
= SECSPERMIN
/ 2;
231 value
.it_interval
.tv_usec
= 0;
232 value
.it_value
= value
.it_interval
;
233 (void)setitimer(ITIMER_REAL
, &value
, NULL
);
235 cc
= read(master
, obuf
, sizeof (obuf
));
238 (void)write(1, obuf
, cc
);
240 record(fscript
, obuf
, cc
, 'o');
242 (void)fwrite(obuf
, 1, cc
, fscript
);
245 (void)fflush(fscript
);
251 scriptflush(int signo
)
254 (void)fflush(fscript
);
260 doshell(const char *command
)
265 (void)fclose(fscript
);
267 if (command
== NULL
) {
268 shell
= getenv("SHELL");
270 shell
= _PATH_BSHELL
;
271 execl(shell
, shell
, "-i", NULL
);
272 warn("execl `%s'", shell
);
274 if (system(command
) == -1)
275 warn("system `%s'", command
);
285 (void)kill(0, SIGTERM
);
297 record(fscript
, NULL
, 0, 'e');
299 (void)fprintf(fscript
,"\nScript done on %s",
301 (void)fclose(fscript
);
304 (void)tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tt
);
306 (void)printf("Script done, output file is %s\n", fname
);
312 record(FILE *fp
, char *buf
, size_t cc
, int direction
)
318 (void)gettimeofday(&tv
, NULL
);
320 stamp
.scr_sec
= tv
.tv_sec
;
321 stamp
.scr_usec
= tv
.tv_usec
;
322 stamp
.scr_direction
= direction
;
323 iov
[0].iov_len
= sizeof(stamp
);
324 iov
[0].iov_base
= &stamp
;
326 iov
[1].iov_base
= buf
;
327 if (writev(fileno(fp
), &iov
[0], 2) == -1)
332 consume(FILE *fp
, off_t len
, char *buf
, int reg
)
337 if (fseeko(fp
, len
, SEEK_CUR
) == -1)
342 l
= MIN(DEF_BUF
, len
);
343 if (fread(buf
, sizeof(char), l
, fp
) != l
)
344 err(1, "cannot read buffer");
350 #define swapstamp(stamp) do { \
351 if (stamp.scr_direction > 0xff) { \
352 stamp.scr_len = bswap64(stamp.scr_len); \
353 stamp.scr_sec = bswap64(stamp.scr_sec); \
354 stamp.scr_usec = bswap32(stamp.scr_usec); \
355 stamp.scr_direction = bswap32(stamp.scr_direction); \
357 } while (0/*CONSTCOND*/)
362 struct timespec tsi
, tso
;
366 off_t nread
, save_len
;
371 if (fstat(fileno(fp
), &pst
) == -1)
372 err(1, "fstat failed");
374 reg
= S_ISREG(pst
.st_mode
);
376 for (nread
= 0; !reg
|| nread
< pst
.st_size
; nread
+= save_len
) {
377 if (fread(&stamp
, sizeof(stamp
), 1, fp
) != 1) {
379 err(1, "reading playback header");
384 save_len
= sizeof(stamp
);
386 if (reg
&& stamp
.scr_len
>
387 (uint64_t)(pst
.st_size
- save_len
) - nread
)
388 err(1, "invalid stamp");
390 save_len
+= stamp
.scr_len
;
391 tclock
= stamp
.scr_sec
;
392 tso
.tv_sec
= stamp
.scr_sec
;
393 tso
.tv_nsec
= stamp
.scr_usec
* 1000;
395 switch (stamp
.scr_direction
) {
398 (void)printf("Script started on %s",
401 (void)consume(fp
, stamp
.scr_len
, buf
, reg
);
405 (void)printf("\nScript done on %s",
407 (void)consume(fp
, stamp
.scr_len
, buf
, reg
);
410 /* throw input away */
411 (void)consume(fp
, stamp
.scr_len
, buf
, reg
);
414 tsi
.tv_sec
= tso
.tv_sec
- tsi
.tv_sec
;
415 tsi
.tv_nsec
= tso
.tv_nsec
- tsi
.tv_nsec
;
416 if (tsi
.tv_nsec
< 0) {
418 tsi
.tv_nsec
+= 1000000000;
421 (void)nanosleep(&tsi
, NULL
);
423 while (stamp
.scr_len
> 0) {
424 l
= MIN(DEF_BUF
, stamp
.scr_len
);
425 if (fread(buf
, sizeof(char), l
, fp
) != l
)
426 err(1, "cannot read buffer");
428 (void)write(STDOUT_FILENO
, buf
, l
);
433 err(1, "invalid direction");