386BSD 0.1 development
[unix-history] / usr / src / usr.bin / script / script.c
CommitLineData
b0af5071
WJ
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
35char 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
41static 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
57char *shell;
58FILE *fscript;
59int master;
60int slave;
61int child;
62int subchild;
63char *fname;
64
65struct termios tt;
66struct winsize win;
67int lb;
68int l;
69char line[] = "/dev/ptyXX";
70int aflg;
71
72main(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
132doinput()
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
145void
146finish()
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
160dooutput()
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
179doshell()
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
202fixtty()
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
212fail()
213{
214
215 (void) kill(0, SIGTERM);
216 done();
217}
218
219done()
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
236getmaster()
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
272getslave()
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}