xref: /csrg-svn/usr.bin/script/script.c (revision 56926)
121575Sdist /*
2*56926Sbostic  * Copyright (c) 1980, 1992 Regents of the University of California.
334628Sbostic  * All rights reserved.
434628Sbostic  *
542765Sbostic  * %sccs.include.redist.c%
621575Sdist  */
721575Sdist 
86318Swnj #ifndef lint
921575Sdist char copyright[] =
10*56926Sbostic "@(#) Copyright (c) 1980, 1992 Regents of the University of California.\n\
1121575Sdist  All rights reserved.\n";
1234628Sbostic #endif /* not lint */
1312990Ssam 
1421575Sdist #ifndef lint
15*56926Sbostic static char sccsid[] = "@(#)script.c	5.15 (Berkeley) 11/30/92";
1634628Sbostic #endif /* not lint */
1721575Sdist 
186318Swnj #include <sys/types.h>
19*56926Sbostic #include <sys/wait.h>
206318Swnj #include <sys/stat.h>
216318Swnj #include <sys/ioctl.h>
2213621Ssam #include <sys/time.h>
23*56926Sbostic 
24*56926Sbostic #include <errno.h>
25*56926Sbostic #include <fcntl.h>
26*56926Sbostic #include <paths.h>
27*56926Sbostic #include <signal.h>
2834628Sbostic #include <stdio.h>
29*56926Sbostic #include <stdlib.h>
30*56926Sbostic #include <string.h>
31*56926Sbostic #include <termios.h>
32*56926Sbostic #include <tzfile.h>
33*56926Sbostic #include <unistd.h>
341089Sbill 
356318Swnj FILE	*fscript;
36*56926Sbostic int	master, slave;
37*56926Sbostic int	child, subchild;
38*56926Sbostic int	outcc;
3934628Sbostic char	*fname;
401089Sbill 
4137141Smarc struct	termios tt;
421089Sbill 
43*56926Sbostic __dead	void done __P((void));
44*56926Sbostic 	void dooutput __P((void));
45*56926Sbostic 	void doshell __P((void));
46*56926Sbostic 	void err __P((const char *, ...));
47*56926Sbostic 	void fail __P((void));
48*56926Sbostic 	void finish __P((int));
49*56926Sbostic 	void scriptflush __P((int));
50*56926Sbostic 
51*56926Sbostic int
526318Swnj main(argc, argv)
536318Swnj 	int argc;
546318Swnj 	char *argv[];
556318Swnj {
56*56926Sbostic 	register int cc;
57*56926Sbostic 	struct termios rtt;
58*56926Sbostic 	struct winsize win;
59*56926Sbostic 	int aflg, ch;
60*56926Sbostic 	char ibuf[BUFSIZ];
611089Sbill 
62*56926Sbostic 	aflg = 0;
6334628Sbostic 	while ((ch = getopt(argc, argv, "a")) != EOF)
64*56926Sbostic 		switch(ch) {
656318Swnj 		case 'a':
66*56926Sbostic 			aflg = 1;
676318Swnj 			break;
6834628Sbostic 		case '?':
696318Swnj 		default:
70*56926Sbostic 			(void)fprintf(stderr, "usage: script [-a] [file]\n");
716318Swnj 			exit(1);
721089Sbill 		}
7334628Sbostic 	argc -= optind;
7434628Sbostic 	argv += optind;
7534628Sbostic 
766318Swnj 	if (argc > 0)
776318Swnj 		fname = argv[0];
7834628Sbostic 	else
7934628Sbostic 		fname = "typescript";
8034628Sbostic 
81*56926Sbostic 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
82*56926Sbostic 		err("%s: %s", fname, strerror(errno));
8334628Sbostic 
84*56926Sbostic 	(void)tcgetattr(STDIN_FILENO, &tt);
85*56926Sbostic 	(void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
86*56926Sbostic 	if (openpty(&master, &slave, NULL, &tt, &win) == -1)
87*56926Sbostic 		err("openpty: %s", strerror(errno));
8850403Smarc 
89*56926Sbostic 	(void)printf("Script started, output file is %s\n", fname);
90*56926Sbostic 	rtt = tt;
91*56926Sbostic 	cfmakeraw(&rtt);
92*56926Sbostic 	rtt.c_lflag &= ~ECHO;
93*56926Sbostic 	(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
941089Sbill 
95*56926Sbostic 	(void)signal(SIGCHLD, finish);
966318Swnj 	child = fork();
976318Swnj 	if (child < 0) {
986318Swnj 		perror("fork");
996318Swnj 		fail();
1001089Sbill 	}
1016318Swnj 	if (child == 0) {
10224450Sbloom 		subchild = child = fork();
10324450Sbloom 		if (child < 0) {
1046318Swnj 			perror("fork");
1056318Swnj 			fail();
1066318Swnj 		}
10724450Sbloom 		if (child)
1081089Sbill 			dooutput();
1096318Swnj 		else
1106318Swnj 			doshell();
1111089Sbill 	}
1121089Sbill 
113*56926Sbostic 	(void)fclose(fscript);
114*56926Sbostic 	while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0)
115*56926Sbostic 		(void)write(master, ibuf, cc);
1166318Swnj 	done();
1176318Swnj }
1181089Sbill 
11946853Sbostic void
120*56926Sbostic finish(signo)
121*56926Sbostic 	int signo;
1226318Swnj {
123*56926Sbostic 	register int die, pid;
1246318Swnj 	union wait status;
1251089Sbill 
126*56926Sbostic 	die = 0;
12746853Sbostic 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
12824450Sbloom 		if (pid == child)
12924450Sbloom 			die = 1;
13024450Sbloom 
13124450Sbloom 	if (die)
13224450Sbloom 		done();
1331089Sbill }
1341089Sbill 
135*56926Sbostic void
1361089Sbill dooutput()
1371089Sbill {
138*56926Sbostic 	struct itimerval value;
13934628Sbostic 	register int cc;
140*56926Sbostic 	time_t tvec;
141*56926Sbostic 	char obuf[BUFSIZ];
1421089Sbill 
143*56926Sbostic 	(void)close(STDIN_FILENO);
144*56926Sbostic 	tvec = time(NULL);
145*56926Sbostic 	(void)fprintf(fscript, "Script started on %s", ctime(&tvec));
146*56926Sbostic 
147*56926Sbostic 	(void)signal(SIGALRM, scriptflush);
148*56926Sbostic 	value.it_interval.tv_sec = SECSPERMIN / 2;
149*56926Sbostic 	value.it_interval.tv_usec = 0;
150*56926Sbostic 	value.it_value = value.it_interval;
151*56926Sbostic 	(void)setitimer(ITIMER_REAL, &value, NULL);
1526318Swnj 	for (;;) {
1536318Swnj 		cc = read(master, obuf, sizeof (obuf));
1546318Swnj 		if (cc <= 0)
1556318Swnj 			break;
156*56926Sbostic 		(void)write(1, obuf, cc);
157*56926Sbostic 		(void)fwrite(obuf, 1, cc, fscript);
158*56926Sbostic 		outcc += cc;
1591089Sbill 	}
16025473Sserge 	done();
1611089Sbill }
1621089Sbill 
163*56926Sbostic void
164*56926Sbostic scriptflush(signo)
165*56926Sbostic 	int signo;
166*56926Sbostic {
167*56926Sbostic 	if (outcc) {
168*56926Sbostic 		(void)fflush(fscript);
169*56926Sbostic 		outcc = 0;
170*56926Sbostic 	}
171*56926Sbostic }
172*56926Sbostic 
173*56926Sbostic void
1741089Sbill doshell()
1751089Sbill {
176*56926Sbostic 	char *shell;
1771089Sbill 
178*56926Sbostic 	shell = getenv("SHELL");
179*56926Sbostic 	if (shell == NULL)
180*56926Sbostic 		shell = _PATH_BSHELL;
181*56926Sbostic 
182*56926Sbostic 	(void)close(master);
183*56926Sbostic 	(void)fclose(fscript);
18450403Smarc 	login_tty(slave);
185*56926Sbostic 	execl(shell, "sh", "-i", NULL);
1866318Swnj 	perror(shell);
1871089Sbill 	fail();
1881089Sbill }
1891089Sbill 
190*56926Sbostic void
1911089Sbill fail()
1921089Sbill {
1931089Sbill 
194*56926Sbostic 	(void)kill(0, SIGTERM);
1951089Sbill 	done();
1961089Sbill }
1971089Sbill 
198*56926Sbostic void
1991089Sbill done()
2001089Sbill {
201*56926Sbostic 	time_t tvec;
2021089Sbill 
20325473Sserge 	if (subchild) {
204*56926Sbostic 		tvec = time(NULL);
205*56926Sbostic 		(void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
206*56926Sbostic 		(void)fclose(fscript);
207*56926Sbostic 		(void)close(master);
20825473Sserge 	} else {
209*56926Sbostic 		(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
210*56926Sbostic 		(void)printf("Script done, output file is %s\n", fname);
21124450Sbloom 	}
2126318Swnj 	exit(0);
2131089Sbill }
214*56926Sbostic 
215*56926Sbostic #if __STDC__
216*56926Sbostic #include <stdarg.h>
217*56926Sbostic #else
218*56926Sbostic #include <varargs.h>
219*56926Sbostic #endif
220*56926Sbostic 
221*56926Sbostic void
222*56926Sbostic #if __STDC__
223*56926Sbostic err(const char *fmt, ...)
224*56926Sbostic #else
225*56926Sbostic err(fmt, va_alist)
226*56926Sbostic 	char *fmt;
227*56926Sbostic 	va_dcl
228*56926Sbostic #endif
229*56926Sbostic {
230*56926Sbostic 	va_list ap;
231*56926Sbostic #if __STDC__
232*56926Sbostic 	va_start(ap, fmt);
233*56926Sbostic #else
234*56926Sbostic 	va_start(ap);
235*56926Sbostic #endif
236*56926Sbostic 	(void)fprintf(stderr, "script: ");
237*56926Sbostic 	(void)vfprintf(stderr, fmt, ap);
238*56926Sbostic 	va_end(ap);
239*56926Sbostic 	(void)fprintf(stderr, "\n");
240*56926Sbostic 	exit(1);
241*56926Sbostic 	/* NOTREACHED */
242*56926Sbostic }
243