xref: /netbsd-src/usr.bin/script/script.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)script.c	5.13 (Berkeley) 3/5/91";*/
42 static char rcsid[] = "$Id: script.c,v 1.2 1993/08/01 18:08:35 mycroft Exp $";
43 #endif /* not lint */
44 
45 /*
46  * script
47  */
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <termios.h>
51 #include <sys/ioctl.h>
52 #include <sys/time.h>
53 #include <sys/file.h>
54 #include <sys/signal.h>
55 #include <stdio.h>
56 #include <paths.h>
57 
58 char	*shell;
59 FILE	*fscript;
60 int	master;
61 int	slave;
62 int	child;
63 int	subchild;
64 char	*fname;
65 
66 struct	termios tt;
67 struct	winsize win;
68 int	lb;
69 int	l;
70 char	line[] = "/dev/ptyXX";
71 int	aflg;
72 
73 main(argc, argv)
74 	int argc;
75 	char *argv[];
76 {
77 	extern char *optarg;
78 	extern int optind;
79 	int ch;
80 	void finish();
81 	char *getenv();
82 
83 	while ((ch = getopt(argc, argv, "a")) != EOF)
84 		switch((char)ch) {
85 		case 'a':
86 			aflg++;
87 			break;
88 		case '?':
89 		default:
90 			fprintf(stderr, "usage: script [-a] [file]\n");
91 			exit(1);
92 		}
93 	argc -= optind;
94 	argv += optind;
95 
96 	if (argc > 0)
97 		fname = argv[0];
98 	else
99 		fname = "typescript";
100 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
101 		perror(fname);
102 		fail();
103 	}
104 
105 	shell = getenv("SHELL");
106 	if (shell == NULL)
107 		shell = _PATH_BSHELL;
108 
109 	getmaster();
110 	printf("Script started, file is %s\n", fname);
111 	fixtty();
112 
113 	(void) signal(SIGCHLD, finish);
114 	child = fork();
115 	if (child < 0) {
116 		perror("fork");
117 		fail();
118 	}
119 	if (child == 0) {
120 		subchild = child = fork();
121 		if (child < 0) {
122 			perror("fork");
123 			fail();
124 		}
125 		if (child)
126 			dooutput();
127 		else
128 			doshell();
129 	}
130 	doinput();
131 }
132 
133 doinput()
134 {
135 	register int cc;
136 	char ibuf[BUFSIZ];
137 
138 	(void) fclose(fscript);
139 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
140 		(void) write(master, ibuf, cc);
141 	done();
142 }
143 
144 #include <sys/wait.h>
145 
146 void
147 finish()
148 {
149 	union wait status;
150 	register int pid;
151 	register int die = 0;
152 
153 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
154 		if (pid == child)
155 			die = 1;
156 
157 	if (die)
158 		done();
159 }
160 
161 dooutput()
162 {
163 	register int cc;
164 	time_t tvec, time();
165 	char obuf[BUFSIZ], *ctime();
166 
167 	(void) close(0);
168 	tvec = time((time_t *)NULL);
169 	fprintf(fscript, "Script started on %s", ctime(&tvec));
170 	for (;;) {
171 		cc = read(master, obuf, sizeof (obuf));
172 		if (cc <= 0)
173 			break;
174 		(void) write(1, obuf, cc);
175 		(void) fwrite(obuf, 1, cc, fscript);
176 	}
177 	done();
178 }
179 
180 doshell()
181 {
182 	int t;
183 
184 	/***
185 	t = open(_PATH_TTY, O_RDWR);
186 	if (t >= 0) {
187 		(void) ioctl(t, TIOCNOTTY, (char *)0);
188 		(void) close(t);
189 	}
190 	***/
191 	getslave();
192 	(void) close(master);
193 	(void) fclose(fscript);
194 	(void) dup2(slave, 0);
195 	(void) dup2(slave, 1);
196 	(void) dup2(slave, 2);
197 	(void) close(slave);
198 	execl(shell, "sh", "-i", 0);
199 	perror(shell);
200 	fail();
201 }
202 
203 fixtty()
204 {
205 	struct termios rtt;
206 
207 	rtt = tt;
208 	cfmakeraw(&rtt);
209 	rtt.c_lflag &= ~ECHO;
210 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
211 }
212 
213 fail()
214 {
215 
216 	(void) kill(0, SIGTERM);
217 	done();
218 }
219 
220 done()
221 {
222 	time_t tvec, time();
223 	char *ctime();
224 
225 	if (subchild) {
226 		tvec = time((time_t *)NULL);
227 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
228 		(void) fclose(fscript);
229 		(void) close(master);
230 	} else {
231 		(void) tcsetattr(0, TCSAFLUSH, &tt);
232 		printf("Script done, file is %s\n", fname);
233 	}
234 	exit(0);
235 }
236 
237 getmaster()
238 {
239 	char *pty, *bank, *cp;
240 	struct stat stb;
241 
242 	pty = &line[strlen("/dev/ptyp")];
243 	for (bank = "pqrs"; *bank; bank++) {
244 		line[strlen("/dev/pty")] = *bank;
245 		*pty = '0';
246 		if (stat(line, &stb) < 0)
247 			break;
248 		for (cp = "0123456789abcdef"; *cp; cp++) {
249 			*pty = *cp;
250 			master = open(line, O_RDWR);
251 			if (master >= 0) {
252 				char *tp = &line[strlen("/dev/")];
253 				int ok;
254 
255 				/* verify slave side is usable */
256 				*tp = 't';
257 				ok = access(line, R_OK|W_OK) == 0;
258 				*tp = 'p';
259 				if (ok) {
260 					(void) tcgetattr(0, &tt);
261 				    	(void) ioctl(0, TIOCGWINSZ,
262 						(char *)&win);
263 					return;
264 				}
265 				(void) close(master);
266 			}
267 		}
268 	}
269 	fprintf(stderr, "Out of pty's\n");
270 	fail();
271 }
272 
273 getslave()
274 {
275 
276 	line[strlen("/dev/")] = 't';
277 	slave = open(line, O_RDWR);
278 	if (slave < 0) {
279 		perror(line);
280 		fail();
281 	}
282 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
283 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
284 	(void) setsid();
285 	(void) ioctl(slave, TIOCSCTTY, 0);
286 }
287