xref: /original-bsd/usr.bin/script/script.c (revision e188a54c)
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 are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)script.c	5.6 (Berkeley) 06/29/88";
26 #endif /* not lint */
27 
28 /*
29  * script
30  */
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/ioctl.h>
34 #include <sys/time.h>
35 #include <sys/file.h>
36 #include <stdio.h>
37 #include <signal.h>
38 
39 char	*shell;
40 FILE	*fscript;
41 int	master;
42 int	slave;
43 int	child;
44 int	subchild;
45 char	*fname;
46 
47 struct	sgttyb b;
48 struct	tchars tc;
49 struct	ltchars lc;
50 struct	winsize win;
51 int	lb;
52 int	l;
53 char	*line = "/dev/ptyXX";
54 int	aflg;
55 
56 main(argc, argv)
57 	int argc;
58 	char *argv[];
59 {
60 	extern char *optarg;
61 	extern int optind;
62 	int ch;
63 	int finish();
64 	char *getenv();
65 
66 	while ((ch = getopt(argc, argv, "a")) != EOF)
67 		switch((char)ch) {
68 		case 'a':
69 			aflg++;
70 			break;
71 		case '?':
72 		default:
73 			fprintf(stderr, "usage: script [-a] [file]\n");
74 			exit(1);
75 		}
76 	argc -= optind;
77 	argv += optind;
78 
79 	if (argc > 0)
80 		fname = argv[0];
81 	else
82 		fname = "typescript";
83 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
84 		perror(fname);
85 		fail();
86 	}
87 
88 	shell = getenv("SHELL");
89 	if (shell == NULL)
90 		shell = "/bin/sh";
91 
92 	getmaster();
93 	printf("Script started, file is %s\n", fname);
94 	fixtty();
95 
96 	(void) signal(SIGCHLD, finish);
97 	child = fork();
98 	if (child < 0) {
99 		perror("fork");
100 		fail();
101 	}
102 	if (child == 0) {
103 		subchild = child = fork();
104 		if (child < 0) {
105 			perror("fork");
106 			fail();
107 		}
108 		if (child)
109 			dooutput();
110 		else
111 			doshell();
112 	}
113 	doinput();
114 }
115 
116 doinput()
117 {
118 	register int cc;
119 	char ibuf[BUFSIZ];
120 
121 	(void) fclose(fscript);
122 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
123 		(void) write(master, ibuf, cc);
124 	done();
125 }
126 
127 #include <sys/wait.h>
128 
129 finish()
130 {
131 	union wait status;
132 	register int pid;
133 	register int die = 0;
134 
135 	while ((pid = wait3(&status, WNOHANG, 0)) > 0)
136 		if (pid == child)
137 			die = 1;
138 
139 	if (die)
140 		done();
141 }
142 
143 dooutput()
144 {
145 	register int cc;
146 	time_t tvec, time();
147 	char obuf[BUFSIZ], *ctime();
148 
149 	(void) close(0);
150 	tvec = time((time_t *)NULL);
151 	fprintf(fscript, "Script started on %s", ctime(&tvec));
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 	}
159 	done();
160 }
161 
162 doshell()
163 {
164 	int t;
165 
166 	t = open("/dev/tty", O_RDWR);
167 	if (t >= 0) {
168 		(void) ioctl(t, TIOCNOTTY, (char *)0);
169 		(void) close(t);
170 	}
171 	getslave();
172 	(void) close(master);
173 	(void) fclose(fscript);
174 	(void) dup2(slave, 0);
175 	(void) dup2(slave, 1);
176 	(void) dup2(slave, 2);
177 	(void) close(slave);
178 	execl(shell, "sh", "-i", 0);
179 	perror(shell);
180 	fail();
181 }
182 
183 fixtty()
184 {
185 	struct sgttyb sbuf;
186 
187 	sbuf = b;
188 	sbuf.sg_flags |= RAW;
189 	sbuf.sg_flags &= ~ECHO;
190 	(void) ioctl(0, TIOCSETP, (char *)&sbuf);
191 }
192 
193 fail()
194 {
195 
196 	(void) kill(0, SIGTERM);
197 	done();
198 }
199 
200 done()
201 {
202 	time_t tvec, time();
203 	char *ctime();
204 
205 	if (subchild) {
206 		tvec = time((time_t *)NULL);
207 		fprintf(fscript,"\nscript done on %s", ctime(&tvec));
208 		(void) fclose(fscript);
209 		(void) close(master);
210 	} else {
211 		(void) ioctl(0, TIOCSETP, (char *)&b);
212 		printf("Script done, file is %s\n", fname);
213 	}
214 	exit(0);
215 }
216 
217 getmaster()
218 {
219 	char *pty, *bank, *cp;
220 	struct stat stb;
221 
222 	pty = &line[strlen("/dev/ptyp")];
223 	for (bank = "pqrs"; *bank; bank++) {
224 		line[strlen("/dev/pty")] = *bank;
225 		*pty = '0';
226 		if (stat(line, &stb) < 0)
227 			break;
228 		for (cp = "0123456789abcdef"; *cp; cp++) {
229 			*pty = *cp;
230 			master = open(line, O_RDWR);
231 			if (master >= 0) {
232 				char *tp = &line[strlen("/dev/")];
233 				int ok;
234 
235 				/* verify slave side is usable */
236 				*tp = 't';
237 				ok = access(line, R_OK|W_OK) == 0;
238 				*tp = 'p';
239 				if (ok) {
240 				    (void) ioctl(0, TIOCGETP, (char *)&b);
241 				    (void) ioctl(0, TIOCGETC, (char *)&tc);
242 				    (void) ioctl(0, TIOCGETD, (char *)&l);
243 				    (void) ioctl(0, TIOCGLTC, (char *)&lc);
244 				    (void) ioctl(0, TIOCLGET, (char *)&lb);
245 				    (void) ioctl(0, TIOCGWINSZ, (char *)&win);
246 					return;
247 				}
248 				(void) close(master);
249 			}
250 		}
251 	}
252 	fprintf(stderr, "Out of pty's\n");
253 	fail();
254 }
255 
256 getslave()
257 {
258 
259 	line[strlen("/dev/")] = 't';
260 	slave = open(line, O_RDWR);
261 	if (slave < 0) {
262 		perror(line);
263 		fail();
264 	}
265 	(void) ioctl(slave, TIOCSETP, (char *)&b);
266 	(void) ioctl(slave, TIOCSETC, (char *)&tc);
267 	(void) ioctl(slave, TIOCSLTC, (char *)&lc);
268 	(void) ioctl(slave, TIOCLSET, (char *)&lb);
269 	(void) ioctl(slave, TIOCSETD, (char *)&l);
270 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
271 }
272