xref: /original-bsd/usr.bin/script/script.c (revision c3e32dec)
1 /*
2  * Copyright (c) 1980, 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1992, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)script.c	8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <sys/stat.h>
21 #include <sys/ioctl.h>
22 #include <sys/time.h>
23 
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <paths.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <termios.h>
32 #include <tzfile.h>
33 #include <unistd.h>
34 
35 FILE	*fscript;
36 int	master, slave;
37 int	child, subchild;
38 int	outcc;
39 char	*fname;
40 
41 struct	termios tt;
42 
43 __dead	void done __P((void));
44 	void dooutput __P((void));
45 	void doshell __P((void));
46 	void err __P((const char *, ...));
47 	void fail __P((void));
48 	void finish __P((int));
49 	void scriptflush __P((int));
50 
51 int
52 main(argc, argv)
53 	int argc;
54 	char *argv[];
55 {
56 	register int cc;
57 	struct termios rtt;
58 	struct winsize win;
59 	int aflg, ch;
60 	char ibuf[BUFSIZ];
61 
62 	aflg = 0;
63 	while ((ch = getopt(argc, argv, "a")) != EOF)
64 		switch(ch) {
65 		case 'a':
66 			aflg = 1;
67 			break;
68 		case '?':
69 		default:
70 			(void)fprintf(stderr, "usage: script [-a] [file]\n");
71 			exit(1);
72 		}
73 	argc -= optind;
74 	argv += optind;
75 
76 	if (argc > 0)
77 		fname = argv[0];
78 	else
79 		fname = "typescript";
80 
81 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
82 		err("%s: %s", fname, strerror(errno));
83 
84 	(void)tcgetattr(STDIN_FILENO, &tt);
85 	(void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
86 	if (openpty(&master, &slave, NULL, &tt, &win) == -1)
87 		err("openpty: %s", strerror(errno));
88 
89 	(void)printf("Script started, output file is %s\n", fname);
90 	rtt = tt;
91 	cfmakeraw(&rtt);
92 	rtt.c_lflag &= ~ECHO;
93 	(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
94 
95 	(void)signal(SIGCHLD, finish);
96 	child = fork();
97 	if (child < 0) {
98 		perror("fork");
99 		fail();
100 	}
101 	if (child == 0) {
102 		subchild = child = fork();
103 		if (child < 0) {
104 			perror("fork");
105 			fail();
106 		}
107 		if (child)
108 			dooutput();
109 		else
110 			doshell();
111 	}
112 
113 	(void)fclose(fscript);
114 	while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0)
115 		(void)write(master, ibuf, cc);
116 	done();
117 }
118 
119 void
120 finish(signo)
121 	int signo;
122 {
123 	register int die, pid;
124 	union wait status;
125 
126 	die = 0;
127 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
128 		if (pid == child)
129 			die = 1;
130 
131 	if (die)
132 		done();
133 }
134 
135 void
136 dooutput()
137 {
138 	struct itimerval value;
139 	register int cc;
140 	time_t tvec;
141 	char obuf[BUFSIZ];
142 
143 	(void)close(STDIN_FILENO);
144 	tvec = time(NULL);
145 	(void)fprintf(fscript, "Script started on %s", ctime(&tvec));
146 
147 	(void)signal(SIGALRM, scriptflush);
148 	value.it_interval.tv_sec = SECSPERMIN / 2;
149 	value.it_interval.tv_usec = 0;
150 	value.it_value = value.it_interval;
151 	(void)setitimer(ITIMER_REAL, &value, NULL);
152 	for (;;) {
153 		cc = read(master, obuf, sizeof (obuf));
154 		if (cc <= 0)
155 			break;
156 		(void)write(1, obuf, cc);
157 		(void)fwrite(obuf, 1, cc, fscript);
158 		outcc += cc;
159 	}
160 	done();
161 }
162 
163 void
164 scriptflush(signo)
165 	int signo;
166 {
167 	if (outcc) {
168 		(void)fflush(fscript);
169 		outcc = 0;
170 	}
171 }
172 
173 void
174 doshell()
175 {
176 	char *shell;
177 
178 	shell = getenv("SHELL");
179 	if (shell == NULL)
180 		shell = _PATH_BSHELL;
181 
182 	(void)close(master);
183 	(void)fclose(fscript);
184 	login_tty(slave);
185 	execl(shell, "sh", "-i", NULL);
186 	perror(shell);
187 	fail();
188 }
189 
190 void
191 fail()
192 {
193 
194 	(void)kill(0, SIGTERM);
195 	done();
196 }
197 
198 void
199 done()
200 {
201 	time_t tvec;
202 
203 	if (subchild) {
204 		tvec = time(NULL);
205 		(void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
206 		(void)fclose(fscript);
207 		(void)close(master);
208 	} else {
209 		(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
210 		(void)printf("Script done, output file is %s\n", fname);
211 	}
212 	exit(0);
213 }
214 
215 #if __STDC__
216 #include <stdarg.h>
217 #else
218 #include <varargs.h>
219 #endif
220 
221 void
222 #if __STDC__
223 err(const char *fmt, ...)
224 #else
225 err(fmt, va_alist)
226 	char *fmt;
227 	va_dcl
228 #endif
229 {
230 	va_list ap;
231 #if __STDC__
232 	va_start(ap, fmt);
233 #else
234 	va_start(ap);
235 #endif
236 	(void)fprintf(stderr, "script: ");
237 	(void)vfprintf(stderr, fmt, ap);
238 	va_end(ap);
239 	(void)fprintf(stderr, "\n");
240 	exit(1);
241 	/* NOTREACHED */
242 }
243