xref: /original-bsd/usr.bin/script/script.c (revision 4b9b56dc)
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.9 (Berkeley) 08/21/89";
26 #endif /* not lint */
27 
28 /*
29  * script
30  */
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <termios.h>
34 #include <sys/ioctl.h>
35 #include <sys/time.h>
36 #include <sys/file.h>
37 #include <sys/signal.h>
38 #include <stdio.h>
39 #include <paths.h>
40 
41 char	*shell;
42 FILE	*fscript;
43 int	master;
44 int	slave;
45 int	child;
46 int	subchild;
47 char	*fname;
48 
49 struct	termios tt;
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 = _PATH_BSHELL;
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 	/***
167 	t = open(_PATH_TTY, O_RDWR);
168 	if (t >= 0) {
169 		(void) ioctl(t, TIOCNOTTY, (char *)0);
170 		(void) close(t);
171 	}
172 	***/
173 	getslave();
174 	(void) close(master);
175 	(void) fclose(fscript);
176 	(void) dup2(slave, 0);
177 	(void) dup2(slave, 1);
178 	(void) dup2(slave, 2);
179 	(void) close(slave);
180 	execl(shell, "sh", "-i", 0);
181 	perror(shell);
182 	fail();
183 }
184 
185 fixtty()
186 {
187 	struct termios rtt;
188 
189 	rtt = tt;
190 	cfmakeraw(&rtt);
191 	rtt.c_lflag &= ~ECHO;
192 	(void) tcsetattr(0, TCSADFLUSH, &rtt);
193 }
194 
195 fail()
196 {
197 
198 	(void) kill(0, SIGTERM);
199 	done();
200 }
201 
202 done()
203 {
204 	time_t tvec, time();
205 	char *ctime();
206 
207 	if (subchild) {
208 		tvec = time((time_t *)NULL);
209 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
210 		(void) fclose(fscript);
211 		(void) close(master);
212 	} else {
213 		(void) tcsetattr(0, TCSADFLUSH, &tt);
214 		printf("Script done, file is %s\n", fname);
215 	}
216 	exit(0);
217 }
218 
219 getmaster()
220 {
221 	char *pty, *bank, *cp;
222 	struct stat stb;
223 
224 	pty = &line[strlen("/dev/ptyp")];
225 	for (bank = "pqrs"; *bank; bank++) {
226 		line[strlen("/dev/pty")] = *bank;
227 		*pty = '0';
228 		if (stat(line, &stb) < 0)
229 			break;
230 		for (cp = "0123456789abcdef"; *cp; cp++) {
231 			*pty = *cp;
232 			master = open(line, O_RDWR);
233 			if (master >= 0) {
234 				char *tp = &line[strlen("/dev/")];
235 				int ok;
236 
237 				/* verify slave side is usable */
238 				*tp = 't';
239 				ok = access(line, R_OK|W_OK) == 0;
240 				*tp = 'p';
241 				if (ok) {
242 					(void) tcgetattr(0, &tt);
243 				    	(void) ioctl(0, TIOCGWINSZ,
244 						(char *)&win);
245 					return;
246 				}
247 				(void) close(master);
248 			}
249 		}
250 	}
251 	fprintf(stderr, "Out of pty's\n");
252 	fail();
253 }
254 
255 getslave()
256 {
257 
258 	line[strlen("/dev/")] = 't';
259 	slave = open(line, O_RDWR);
260 	if (slave < 0) {
261 		perror(line);
262 		fail();
263 	}
264 	(void) tcsetattr(slave, TCSADFLUSH, &tt);
265 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
266 	(void) setsid();
267 	(void) ioctl(slave, TIOCSCTTY, 0);
268 }
269