xref: /original-bsd/usr.bin/script/script.c (revision fa348642)
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.13 (Berkeley) 03/05/91";
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 	void 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 void
120 finish()
121 {
122 	union wait status;
123 	register int pid;
124 	register int die = 0;
125 
126 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
127 		if (pid == child)
128 			die = 1;
129 
130 	if (die)
131 		done();
132 }
133 
134 dooutput()
135 {
136 	register int cc;
137 	time_t tvec, time();
138 	char obuf[BUFSIZ], *ctime();
139 
140 	(void) close(0);
141 	tvec = time((time_t *)NULL);
142 	fprintf(fscript, "Script started on %s", ctime(&tvec));
143 	for (;;) {
144 		cc = read(master, obuf, sizeof (obuf));
145 		if (cc <= 0)
146 			break;
147 		(void) write(1, obuf, cc);
148 		(void) fwrite(obuf, 1, cc, fscript);
149 	}
150 	done();
151 }
152 
153 doshell()
154 {
155 	int t;
156 
157 	/***
158 	t = open(_PATH_TTY, O_RDWR);
159 	if (t >= 0) {
160 		(void) ioctl(t, TIOCNOTTY, (char *)0);
161 		(void) close(t);
162 	}
163 	***/
164 	getslave();
165 	(void) close(master);
166 	(void) fclose(fscript);
167 	(void) dup2(slave, 0);
168 	(void) dup2(slave, 1);
169 	(void) dup2(slave, 2);
170 	(void) close(slave);
171 	execl(shell, "sh", "-i", 0);
172 	perror(shell);
173 	fail();
174 }
175 
176 fixtty()
177 {
178 	struct termios rtt;
179 
180 	rtt = tt;
181 	cfmakeraw(&rtt);
182 	rtt.c_lflag &= ~ECHO;
183 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
184 }
185 
186 fail()
187 {
188 
189 	(void) kill(0, SIGTERM);
190 	done();
191 }
192 
193 done()
194 {
195 	time_t tvec, time();
196 	char *ctime();
197 
198 	if (subchild) {
199 		tvec = time((time_t *)NULL);
200 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
201 		(void) fclose(fscript);
202 		(void) close(master);
203 	} else {
204 		(void) tcsetattr(0, TCSAFLUSH, &tt);
205 		printf("Script done, file is %s\n", fname);
206 	}
207 	exit(0);
208 }
209 
210 getmaster()
211 {
212 	char *pty, *bank, *cp;
213 	struct stat stb;
214 
215 	pty = &line[strlen("/dev/ptyp")];
216 	for (bank = "pqrs"; *bank; bank++) {
217 		line[strlen("/dev/pty")] = *bank;
218 		*pty = '0';
219 		if (stat(line, &stb) < 0)
220 			break;
221 		for (cp = "0123456789abcdef"; *cp; cp++) {
222 			*pty = *cp;
223 			master = open(line, O_RDWR);
224 			if (master >= 0) {
225 				char *tp = &line[strlen("/dev/")];
226 				int ok;
227 
228 				/* verify slave side is usable */
229 				*tp = 't';
230 				ok = access(line, R_OK|W_OK) == 0;
231 				*tp = 'p';
232 				if (ok) {
233 					(void) tcgetattr(0, &tt);
234 				    	(void) ioctl(0, TIOCGWINSZ,
235 						(char *)&win);
236 					return;
237 				}
238 				(void) close(master);
239 			}
240 		}
241 	}
242 	fprintf(stderr, "Out of pty's\n");
243 	fail();
244 }
245 
246 getslave()
247 {
248 
249 	line[strlen("/dev/")] = 't';
250 	slave = open(line, O_RDWR);
251 	if (slave < 0) {
252 		perror(line);
253 		fail();
254 	}
255 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
256 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
257 	(void) setsid();
258 	(void) ioctl(slave, TIOCSCTTY, 0);
259 }
260