Commit | Line | Data |
---|---|---|
22e155fc | 1 | /* |
3cc17513 KB |
2 | * Copyright (c) 1980, 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
c66a959c | 4 | * |
cb956e54 | 5 | * %sccs.include.redist.c% |
22e155fc DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
3cc17513 KB |
9 | static char copyright[] = |
10 | "@(#) Copyright (c) 1980, 1992, 1993\n\ | |
11 | The Regents of the University of California. All rights reserved.\n"; | |
c66a959c | 12 | #endif /* not lint */ |
22e155fc | 13 | |
784bcaee | 14 | #ifndef lint |
3cc17513 | 15 | static char sccsid[] = "@(#)script.c 8.1 (Berkeley) %G%"; |
c66a959c | 16 | #endif /* not lint */ |
4ca10280 | 17 | |
784bcaee | 18 | #include <sys/types.h> |
406b0afb | 19 | #include <sys/wait.h> |
784bcaee BJ |
20 | #include <sys/stat.h> |
21 | #include <sys/ioctl.h> | |
840fc587 | 22 | #include <sys/time.h> |
406b0afb KB |
23 | |
24 | #include <errno.h> | |
25 | #include <fcntl.h> | |
435e8dff | 26 | #include <paths.h> |
406b0afb KB |
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> | |
784bcaee | 34 | |
784bcaee | 35 | FILE *fscript; |
406b0afb KB |
36 | int master, slave; |
37 | int child, subchild; | |
38 | int outcc; | |
c66a959c | 39 | char *fname; |
784bcaee | 40 | |
c1eb5ad2 | 41 | struct termios tt; |
784bcaee | 42 | |
406b0afb KB |
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 | |
784bcaee BJ |
52 | main(argc, argv) |
53 | int argc; | |
54 | char *argv[]; | |
55 | { | |
406b0afb KB |
56 | register int cc; |
57 | struct termios rtt; | |
58 | struct winsize win; | |
59 | int aflg, ch; | |
60 | char ibuf[BUFSIZ]; | |
c66a959c | 61 | |
406b0afb | 62 | aflg = 0; |
c66a959c | 63 | while ((ch = getopt(argc, argv, "a")) != EOF) |
406b0afb | 64 | switch(ch) { |
784bcaee | 65 | case 'a': |
406b0afb | 66 | aflg = 1; |
784bcaee | 67 | break; |
c66a959c | 68 | case '?': |
784bcaee | 69 | default: |
406b0afb | 70 | (void)fprintf(stderr, "usage: script [-a] [file]\n"); |
784bcaee | 71 | exit(1); |
3481eb52 | 72 | } |
c66a959c KB |
73 | argc -= optind; |
74 | argv += optind; | |
75 | ||
784bcaee BJ |
76 | if (argc > 0) |
77 | fname = argv[0]; | |
c66a959c KB |
78 | else |
79 | fname = "typescript"; | |
c66a959c | 80 | |
406b0afb KB |
81 | if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) |
82 | err("%s: %s", fname, strerror(errno)); | |
c66a959c | 83 | |
406b0afb KB |
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)); | |
c0468dfd | 88 | |
406b0afb KB |
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); | |
3481eb52 | 94 | |
406b0afb | 95 | (void)signal(SIGCHLD, finish); |
784bcaee BJ |
96 | child = fork(); |
97 | if (child < 0) { | |
98 | perror("fork"); | |
99 | fail(); | |
100 | } | |
101 | if (child == 0) { | |
5e497b6f JB |
102 | subchild = child = fork(); |
103 | if (child < 0) { | |
784bcaee BJ |
104 | perror("fork"); |
105 | fail(); | |
106 | } | |
5e497b6f | 107 | if (child) |
3481eb52 | 108 | dooutput(); |
784bcaee BJ |
109 | else |
110 | doshell(); | |
3481eb52 | 111 | } |
3481eb52 | 112 | |
406b0afb KB |
113 | (void)fclose(fscript); |
114 | while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) | |
115 | (void)write(master, ibuf, cc); | |
784bcaee BJ |
116 | done(); |
117 | } | |
3481eb52 | 118 | |
4c529d71 | 119 | void |
406b0afb KB |
120 | finish(signo) |
121 | int signo; | |
784bcaee | 122 | { |
406b0afb | 123 | register int die, pid; |
784bcaee | 124 | union wait status; |
3481eb52 | 125 | |
406b0afb | 126 | die = 0; |
4c529d71 | 127 | while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0) |
5e497b6f JB |
128 | if (pid == child) |
129 | die = 1; | |
130 | ||
131 | if (die) | |
132 | done(); | |
3481eb52 BJ |
133 | } |
134 | ||
406b0afb | 135 | void |
3481eb52 BJ |
136 | dooutput() |
137 | { | |
406b0afb | 138 | struct itimerval value; |
c66a959c | 139 | register int cc; |
406b0afb KB |
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); | |
784bcaee BJ |
152 | for (;;) { |
153 | cc = read(master, obuf, sizeof (obuf)); | |
154 | if (cc <= 0) | |
155 | break; | |
406b0afb KB |
156 | (void)write(1, obuf, cc); |
157 | (void)fwrite(obuf, 1, cc, fscript); | |
158 | outcc += cc; | |
3481eb52 | 159 | } |
f640284e | 160 | done(); |
3481eb52 BJ |
161 | } |
162 | ||
406b0afb KB |
163 | void |
164 | scriptflush(signo) | |
165 | int signo; | |
166 | { | |
167 | if (outcc) { | |
168 | (void)fflush(fscript); | |
169 | outcc = 0; | |
170 | } | |
171 | } | |
172 | ||
173 | void | |
3481eb52 BJ |
174 | doshell() |
175 | { | |
406b0afb | 176 | char *shell; |
3481eb52 | 177 | |
406b0afb KB |
178 | shell = getenv("SHELL"); |
179 | if (shell == NULL) | |
180 | shell = _PATH_BSHELL; | |
181 | ||
182 | (void)close(master); | |
183 | (void)fclose(fscript); | |
c0468dfd | 184 | login_tty(slave); |
406b0afb | 185 | execl(shell, "sh", "-i", NULL); |
784bcaee | 186 | perror(shell); |
3481eb52 BJ |
187 | fail(); |
188 | } | |
189 | ||
406b0afb | 190 | void |
3481eb52 BJ |
191 | fail() |
192 | { | |
193 | ||
406b0afb | 194 | (void)kill(0, SIGTERM); |
3481eb52 BJ |
195 | done(); |
196 | } | |
197 | ||
406b0afb | 198 | void |
3481eb52 BJ |
199 | done() |
200 | { | |
406b0afb | 201 | time_t tvec; |
3481eb52 | 202 | |
f640284e | 203 | if (subchild) { |
406b0afb KB |
204 | tvec = time(NULL); |
205 | (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec)); | |
206 | (void)fclose(fscript); | |
207 | (void)close(master); | |
f640284e | 208 | } else { |
406b0afb KB |
209 | (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt); |
210 | (void)printf("Script done, output file is %s\n", fname); | |
5e497b6f | 211 | } |
784bcaee | 212 | exit(0); |
3481eb52 | 213 | } |
406b0afb KB |
214 | |
215 | #if __STDC__ | |
216 | #include <stdarg.h> | |
217 | #else | |
218 | #include <varargs.h> | |
219 | #endif | |
220 | ||
221 | void | |
222 | #if __STDC__ | |
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 | } |