1 /*
2 * Copyright (c) 1980, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1992, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)script.c 8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <sys/stat.h>
21 #include <sys/ioctl.h>
22 #include <sys/time.h>
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <paths.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <termios.h>
32 #include <tzfile.h>
33 #include <unistd.h>
34
35 FILE *fscript;
36 int master, slave;
37 int child, subchild;
38 int outcc;
39 char *fname;
40
41 struct termios tt;
42
43 __dead void done __P((void));
44 void dooutput __P((void));
45 void doshell __P((void));
46 void err __P((const char *, ...));
47 void fail __P((void));
48 void finish __P((int));
49 void scriptflush __P((int));
50
51 int
main(argc,argv)52 main(argc, argv)
53 int argc;
54 char *argv[];
55 {
56 register int cc;
57 struct termios rtt;
58 struct winsize win;
59 int aflg, ch;
60 char ibuf[BUFSIZ];
61
62 aflg = 0;
63 while ((ch = getopt(argc, argv, "a")) != EOF)
64 switch(ch) {
65 case 'a':
66 aflg = 1;
67 break;
68 case '?':
69 default:
70 (void)fprintf(stderr, "usage: script [-a] [file]\n");
71 exit(1);
72 }
73 argc -= optind;
74 argv += optind;
75
76 if (argc > 0)
77 fname = argv[0];
78 else
79 fname = "typescript";
80
81 if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
82 err("%s: %s", fname, strerror(errno));
83
84 (void)tcgetattr(STDIN_FILENO, &tt);
85 (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
86 if (openpty(&master, &slave, NULL, &tt, &win) == -1)
87 err("openpty: %s", strerror(errno));
88
89 (void)printf("Script started, output file is %s\n", fname);
90 rtt = tt;
91 cfmakeraw(&rtt);
92 rtt.c_lflag &= ~ECHO;
93 (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
94
95 (void)signal(SIGCHLD, finish);
96 child = fork();
97 if (child < 0) {
98 perror("fork");
99 fail();
100 }
101 if (child == 0) {
102 subchild = child = fork();
103 if (child < 0) {
104 perror("fork");
105 fail();
106 }
107 if (child)
108 dooutput();
109 else
110 doshell();
111 }
112
113 (void)fclose(fscript);
114 while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0)
115 (void)write(master, ibuf, cc);
116 done();
117 }
118
119 void
finish(signo)120 finish(signo)
121 int signo;
122 {
123 register int die, pid;
124 union wait status;
125
126 die = 0;
127 while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
128 if (pid == child)
129 die = 1;
130
131 if (die)
132 done();
133 }
134
135 void
dooutput()136 dooutput()
137 {
138 struct itimerval value;
139 register int cc;
140 time_t tvec;
141 char obuf[BUFSIZ];
142
143 (void)close(STDIN_FILENO);
144 tvec = time(NULL);
145 (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
146
147 (void)signal(SIGALRM, scriptflush);
148 value.it_interval.tv_sec = SECSPERMIN / 2;
149 value.it_interval.tv_usec = 0;
150 value.it_value = value.it_interval;
151 (void)setitimer(ITIMER_REAL, &value, NULL);
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 outcc += cc;
159 }
160 done();
161 }
162
163 void
scriptflush(signo)164 scriptflush(signo)
165 int signo;
166 {
167 if (outcc) {
168 (void)fflush(fscript);
169 outcc = 0;
170 }
171 }
172
173 void
doshell()174 doshell()
175 {
176 char *shell;
177
178 shell = getenv("SHELL");
179 if (shell == NULL)
180 shell = _PATH_BSHELL;
181
182 (void)close(master);
183 (void)fclose(fscript);
184 login_tty(slave);
185 execl(shell, "sh", "-i", NULL);
186 perror(shell);
187 fail();
188 }
189
190 void
fail()191 fail()
192 {
193
194 (void)kill(0, SIGTERM);
195 done();
196 }
197
198 void
done()199 done()
200 {
201 time_t tvec;
202
203 if (subchild) {
204 tvec = time(NULL);
205 (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
206 (void)fclose(fscript);
207 (void)close(master);
208 } else {
209 (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
210 (void)printf("Script done, output file is %s\n", fname);
211 }
212 exit(0);
213 }
214
215 #if __STDC__
216 #include <stdarg.h>
217 #else
218 #include <varargs.h>
219 #endif
220
221 void
222 #if __STDC__
err(const char * fmt,...)223 err(const char *fmt, ...)
224 #else
225 err(fmt, va_alist)
226 char *fmt;
227 va_dcl
228 #endif
229 {
230 va_list ap;
231 #if __STDC__
232 va_start(ap, fmt);
233 #else
234 va_start(ap);
235 #endif
236 (void)fprintf(stderr, "script: ");
237 (void)vfprintf(stderr, fmt, ap);
238 va_end(ap);
239 (void)fprintf(stderr, "\n");
240 exit(1);
241 /* NOTREACHED */
242 }
243