1 /* vi: set sw=4 ts=4: */
3 * script implementation for busybox
5 * pascal.bellard@ads-lu.com
7 * Based on code from util-linux v 2.12r
9 * The Regents of the University of California. All rights reserved.
11 * Licensed under GPLv2 or later, see file License in this tarball for details.
18 int attr_ok; /* NB: 0: ok */
22 #define G (*ptr_to_globals)
23 #define child_pid (G.child_pid)
24 #define attr_ok (G.attr_ok )
26 #define fname (G.fname )
27 #define INIT_G() do { \
28 PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
29 fname = "typescript"; \
32 static void done(void)
34 if (child_pid) { /* we are parent */
36 tcsetattr(0, TCSAFLUSH, &tt);
37 if (!(option_mask32 & 8)) /* not -q */
38 printf("Script done, file is %s\n", fname);
44 static void handle_sigchld(int sig)
46 /* wait for the exited child and exit */
47 while (wait_any_nohang(&sig) > 0)
53 #if ENABLE_GETOPT_LONG
54 static const char getopt_longopts[] ALIGN1 =
55 "append\0" No_argument "a"
56 "command\0" Required_argument "c"
57 "flush\0" No_argument "f"
58 "quiet\0" No_argument "q"
62 int script_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE;
63 int script_main(int argc, char *argv[])
72 char shell_opt[] = "-i";
73 char *shell_arg = NULL;
76 #if ENABLE_GETOPT_LONG
77 applet_long_options = getopt_longopts;
79 opt_complementary = "?1"; /* max one arg */
80 opt = getopt32(argv, "ac:fq", &shell_arg);
86 mode = O_CREAT|O_TRUNC|O_WRONLY;
88 mode = O_CREAT|O_APPEND|O_WRONLY;
93 if (!(opt & 8)) { /* not -q */
94 printf("Script started, file is %s\n", fname);
96 shell = getenv("SHELL");
101 pty = getpty(line, sizeof(line));
103 bb_perror_msg_and_die("can't get pty");
106 /* get current stdin's tty params */
107 attr_ok = tcgetattr(0, &tt);
108 winsz_ok = ioctl(0, TIOCGWINSZ, (char *)&win);
112 rtt.c_lflag &= ~ECHO;
113 tcsetattr(0, TCSAFLUSH, &rtt);
115 /* We exit as soon as child exits */
116 //signal(SIGCHLD, handle_sigchld);
117 signal(SIGCHLD, (void (*)(int)) done);
121 bb_perror_msg_and_die("vfork");
127 struct pollfd pfd[2];
130 struct pollfd *ppfd = pfd;
132 outfd = xopen(fname, mode);
134 pfd[0].events = POLLIN;
136 pfd[1].events = POLLIN;
137 ndelay_on(pty); /* this descriptor is not shared, can do this */
138 /* ndelay_on(0); - NO, stdin can be shared! */
140 /* copy stdin to pty master input,
141 * copy pty master output to stdout and file */
142 /* TODO: don't use full_write's, use proper write buffering */
143 while (fd_count && safe_poll(ppfd, fd_count, -1) > 0) {
144 if (pfd[0].revents) {
145 int count = safe_read(0, buf, sizeof(buf));
147 /* err/eof: don't read anymore */
152 full_write(pty, buf, count);
155 if (pfd[1].revents) {
158 count = safe_read(pty, buf, sizeof(buf));
159 if (count <= 0 && errno != EAGAIN) {
160 /* err/eof: don't read anymore */
165 full_write(1, buf, count);
166 full_write(outfd, buf, count);
167 if (opt & 4) { /* -f */
173 done(); /* does not return */
176 /* child: make pty slave to be input, output, error; run shell */
177 close(pty); /* close pty master */
178 /* open pty slave to fd 0,1,2 */
180 xopen(line, O_RDWR); /* uses fd 0 */
183 /* copy our original stdin tty's parameters to pty */
185 tcsetattr(0, TCSAFLUSH, &tt);
187 ioctl(0, TIOCSWINSZ, (char *)&win);
188 /* set pty as a controlling tty */
190 ioctl(0, TIOCSCTTY, 0 /* 0: don't forcibly steal */);
192 /* signal(SIGCHLD, SIG_DFL); - exec does this for us */
193 execl(shell, shell, shell_opt, shell_arg, NULL);
194 bb_simple_perror_msg_and_die(shell);