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