xref: /386bsd/usr/src/usr.bin/script/script.c (revision a2142627)
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[] = "@(#)script.c	5.13 (Berkeley) 3/5/91";
42 #endif /* not lint */
43 
44 /*
45  * script
46  */
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <termios.h>
50 #include <sys/ioctl.h>
51 #include <sys/time.h>
52 #include <sys/file.h>
53 #include <sys/signal.h>
54 #include <stdio.h>
55 #include <paths.h>
56 
57 char	*shell;
58 FILE	*fscript;
59 int	master;
60 int	slave;
61 int	child;
62 int	subchild;
63 char	*fname;
64 
65 struct	termios tt;
66 struct	winsize win;
67 int	lb;
68 int	l;
69 char	line[] = "/dev/ptyXX";
70 int	aflg;
71 
main(argc,argv)72 main(argc, argv)
73 	int argc;
74 	char *argv[];
75 {
76 	extern char *optarg;
77 	extern int optind;
78 	int ch;
79 	void finish();
80 	char *getenv();
81 
82 	while ((ch = getopt(argc, argv, "a")) != EOF)
83 		switch((char)ch) {
84 		case 'a':
85 			aflg++;
86 			break;
87 		case '?':
88 		default:
89 			fprintf(stderr, "usage: script [-a] [file]\n");
90 			exit(1);
91 		}
92 	argc -= optind;
93 	argv += optind;
94 
95 	if (argc > 0)
96 		fname = argv[0];
97 	else
98 		fname = "typescript";
99 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
100 		perror(fname);
101 		fail();
102 	}
103 
104 	shell = getenv("SHELL");
105 	if (shell == NULL)
106 		shell = _PATH_BSHELL;
107 
108 	getmaster();
109 	printf("Script started, file is %s\n", fname);
110 	fixtty();
111 
112 	(void) signal(SIGCHLD, finish);
113 	child = fork();
114 	if (child < 0) {
115 		perror("fork");
116 		fail();
117 	}
118 	if (child == 0) {
119 		subchild = child = fork();
120 		if (child < 0) {
121 			perror("fork");
122 			fail();
123 		}
124 		if (child)
125 			dooutput();
126 		else
127 			doshell();
128 	}
129 	doinput();
130 }
131 
doinput()132 doinput()
133 {
134 	register int cc;
135 	char ibuf[BUFSIZ];
136 
137 	(void) fclose(fscript);
138 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
139 		(void) write(master, ibuf, cc);
140 	done();
141 }
142 
143 #include <sys/wait.h>
144 
145 void
finish()146 finish()
147 {
148 	union wait status;
149 	register int pid;
150 	register int die = 0;
151 
152 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
153 		if (pid == child)
154 			die = 1;
155 
156 	if (die)
157 		done();
158 }
159 
dooutput()160 dooutput()
161 {
162 	register int cc;
163 	time_t tvec, time();
164 	char obuf[BUFSIZ], *ctime();
165 
166 	(void) close(0);
167 	tvec = time((time_t *)NULL);
168 	fprintf(fscript, "Script started on %s", ctime(&tvec));
169 	for (;;) {
170 		cc = read(master, obuf, sizeof (obuf));
171 		if (cc <= 0)
172 			break;
173 		(void) write(1, obuf, cc);
174 		(void) fwrite(obuf, 1, cc, fscript);
175 	}
176 	done();
177 }
178 
doshell()179 doshell()
180 {
181 	int t;
182 
183 	/***
184 	t = open(_PATH_TTY, O_RDWR);
185 	if (t >= 0) {
186 		(void) ioctl(t, TIOCNOTTY, (char *)0);
187 		(void) close(t);
188 	}
189 	***/
190 	getslave();
191 	(void) close(master);
192 	(void) fclose(fscript);
193 	(void) dup2(slave, 0);
194 	(void) dup2(slave, 1);
195 	(void) dup2(slave, 2);
196 	(void) close(slave);
197 	execl(shell, "sh", "-i", 0);
198 	perror(shell);
199 	fail();
200 }
201 
fixtty()202 fixtty()
203 {
204 	struct termios rtt;
205 
206 	rtt = tt;
207 	cfmakeraw(&rtt);
208 	rtt.c_lflag &= ~ECHO;
209 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
210 }
211 
fail()212 fail()
213 {
214 
215 	(void) kill(0, SIGTERM);
216 	done();
217 }
218 
done()219 done()
220 {
221 	time_t tvec, time();
222 	char *ctime();
223 
224 	if (subchild) {
225 		tvec = time((time_t *)NULL);
226 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
227 		(void) fclose(fscript);
228 		(void) close(master);
229 	} else {
230 		(void) tcsetattr(0, TCSAFLUSH, &tt);
231 		printf("Script done, file is %s\n", fname);
232 	}
233 	exit(0);
234 }
235 
getmaster()236 getmaster()
237 {
238 	char *pty, *bank, *cp;
239 	struct stat stb;
240 
241 	pty = &line[strlen("/dev/ptyp")];
242 	for (bank = "pqrs"; *bank; bank++) {
243 		line[strlen("/dev/pty")] = *bank;
244 		*pty = '0';
245 		if (stat(line, &stb) < 0)
246 			break;
247 		for (cp = "0123456789abcdef"; *cp; cp++) {
248 			*pty = *cp;
249 			master = open(line, O_RDWR);
250 			if (master >= 0) {
251 				char *tp = &line[strlen("/dev/")];
252 				int ok;
253 
254 				/* verify slave side is usable */
255 				*tp = 't';
256 				ok = access(line, R_OK|W_OK) == 0;
257 				*tp = 'p';
258 				if (ok) {
259 					(void) tcgetattr(0, &tt);
260 				    	(void) ioctl(0, TIOCGWINSZ,
261 						(char *)&win);
262 					return;
263 				}
264 				(void) close(master);
265 			}
266 		}
267 	}
268 	fprintf(stderr, "Out of pty's\n");
269 	fail();
270 }
271 
getslave()272 getslave()
273 {
274 
275 	line[strlen("/dev/")] = 't';
276 	slave = open(line, O_RDWR);
277 	if (slave < 0) {
278 		perror(line);
279 		fail();
280 	}
281 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
282 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
283 	(void) setsid();
284 	(void) ioctl(slave, TIOCSCTTY, 0);
285 }
286