1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#include "libbb.h"
45#include "common_bufsiz.h"
46
47int script_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
48int script_main(int argc UNUSED_PARAM, char **argv)
49{
50 int opt;
51 int mode;
52 int child_pid;
53 int attr_ok;
54 int winsz_ok;
55 int pty;
56 char pty_line[GETPTY_BUFSIZE];
57 struct termios tt, rtt;
58 struct winsize win;
59 FILE *timing_fp;
60 const char *str_t = NULL;
61 const char *fname = "typescript";
62 const char *shell;
63 char shell_opt[] = "-i";
64 char *shell_arg = NULL;
65 enum {
66 OPT_a = (1 << 0),
67 OPT_c = (1 << 1),
68 OPT_f = (1 << 2),
69 OPT_q = (1 << 3),
70 OPT_t = (1 << 4),
71 };
72
73#if ENABLE_LONG_OPTS
74 static const char script_longopts[] ALIGN1 =
75 "append\0" No_argument "a"
76 "command\0" Required_argument "c"
77 "flush\0" No_argument "f"
78 "quiet\0" No_argument "q"
79 "timing\0" Optional_argument "t"
80 ;
81#endif
82
83 opt = getopt32long(argv, "^" "ac:fqt::" "\0" "?1",
84 script_longopts,
85 &shell_arg, &str_t
86 );
87
88 argv += optind;
89 if (argv[0]) {
90 fname = argv[0];
91 }
92 mode = O_CREAT|O_TRUNC|O_WRONLY;
93 if (opt & OPT_a) {
94 mode = O_CREAT|O_APPEND|O_WRONLY;
95 }
96 if (opt & OPT_c) {
97 shell_opt[1] = 'c';
98 }
99 if (!(opt & OPT_q)) {
100 printf("Script started, file is %s\n", fname);
101 }
102 timing_fp = stderr;
103 if (str_t) {
104 timing_fp = xfopen_for_write(str_t);
105 }
106
107 shell = get_shell_name();
108
109
110
111
112
113 bb_sanitize_stdio();
114
115 pty = xgetpty(pty_line);
116
117
118 attr_ok = tcgetattr(0, &tt);
119 winsz_ok = ioctl(0, TIOCGWINSZ, (char *)&win);
120
121 rtt = tt;
122 cfmakeraw(&rtt);
123 rtt.c_lflag &= ~ECHO;
124 tcsetattr(0, TCSAFLUSH, &rtt);
125
126
127
128
129 signal(SIGCHLD, record_signo);
130
131
132
133 child_pid = xvfork();
134
135 if (child_pid) {
136
137 struct pollfd pfd[2];
138 int outfd, count, loop;
139 double oldtime = time(NULL);
140 smallint fd_count = 2;
141
142#define buf bb_common_bufsiz1
143 setup_common_bufsiz();
144
145 outfd = xopen(fname, mode);
146 pfd[0].fd = pty;
147 pfd[0].events = POLLIN;
148 pfd[1].fd = STDIN_FILENO;
149 pfd[1].events = POLLIN;
150 ndelay_on(pty);
151
152
153
154
155
156 while (fd_count && !bb_got_signal) {
157
158 if (poll(pfd, fd_count, -1) < 0 && errno != EINTR) {
159
160
161 break;
162 }
163 if (pfd[0].revents) {
164 errno = 0;
165 count = safe_read(pty, buf, COMMON_BUFSIZE);
166 if (count <= 0 && errno != EAGAIN) {
167
168 goto restore;
169 }
170 if (count > 0) {
171 if (opt & OPT_t) {
172 struct timeval tv;
173 double newtime;
174
175 gettimeofday(&tv, NULL);
176 newtime = tv.tv_sec + (double) tv.tv_usec / 1000000;
177 fprintf(timing_fp, "%f %u\n", newtime - oldtime, count);
178 oldtime = newtime;
179 }
180 full_write(STDOUT_FILENO, buf, count);
181 full_write(outfd, buf, count);
182
183
184
185
186 }
187 }
188 if (pfd[1].revents) {
189 count = safe_read(STDIN_FILENO, buf, COMMON_BUFSIZE);
190 if (count <= 0) {
191
192 pfd[1].revents = 0;
193 fd_count--;
194 } else {
195 full_write(pty, buf, count);
196 }
197 }
198 }
199
200
201
202
203
204
205
206 loop = 999;
207
208 while (--loop && (count = safe_read(pty, buf, COMMON_BUFSIZE)) > 0) {
209 full_write(STDOUT_FILENO, buf, count);
210 full_write(outfd, buf, count);
211 }
212 restore:
213 if (attr_ok == 0)
214 tcsetattr(0, TCSAFLUSH, &tt);
215 if (!(opt & OPT_q))
216 printf("Script done, file is %s\n", fname);
217 return EXIT_SUCCESS;
218 }
219
220
221 close(pty);
222
223 close(0);
224 xopen(pty_line, O_RDWR);
225 xdup2(0, 1);
226 xdup2(0, 2);
227
228 if (attr_ok == 0)
229 tcsetattr(0, TCSAFLUSH, &tt);
230 if (winsz_ok == 0)
231 ioctl(0, TIOCSWINSZ, (char *)&win);
232
233 setsid();
234 ioctl(0, TIOCSCTTY, 0 );
235
236
237
238 execl(shell, shell, shell_opt, shell_arg, (char *) NULL);
239 bb_simple_perror_msg_and_die(shell);
240}
241