diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-27 11:54:59 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-27 11:54:59 +0000 |
commit | 5014dada3fa0bb6f6873e28fe6491f0789239cdc (patch) | |
tree | 25cc7ed4e457d924131f3e7cdbab1e187a617639 /util-linux/script.c | |
parent | 8195d20e36bfeeb30b3424e2635ba4757ec38137 (diff) | |
download | busybox-w32-5014dada3fa0bb6f6873e28fe6491f0789239cdc.tar.gz busybox-w32-5014dada3fa0bb6f6873e28fe6491f0789239cdc.tar.bz2 busybox-w32-5014dada3fa0bb6f6873e28fe6491f0789239cdc.zip |
script: new applet by Pascal Bellard <pascal.bellard AT ads-lu.com>
Diffstat (limited to 'util-linux/script.c')
-rw-r--r-- | util-linux/script.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/util-linux/script.c b/util-linux/script.c new file mode 100644 index 000000000..fda726ed9 --- /dev/null +++ b/util-linux/script.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * script implementation for busybox | ||
4 | * | ||
5 | * pascal.bellard@ads-lu.com | ||
6 | * | ||
7 | * Based on code from util-linux v 2.12r | ||
8 | * Copyright (c) 1980 | ||
9 | * The Regents of the University of California. All rights reserved. | ||
10 | * | ||
11 | * Licensed under GPLv2 or later, see file License in this tarball for details. | ||
12 | */ | ||
13 | |||
14 | #include "libbb.h" | ||
15 | |||
16 | struct globals { | ||
17 | int child_pid; | ||
18 | int attr_ok; /* NB: 0: ok */ | ||
19 | struct termios tt; | ||
20 | const char *fname; | ||
21 | }; | ||
22 | #define G (*ptr_to_globals) | ||
23 | #define child_pid (G.child_pid) | ||
24 | #define attr_ok (G.attr_ok ) | ||
25 | #define tt (G.tt ) | ||
26 | #define fname (G.fname ) | ||
27 | #define INIT_G() do { \ | ||
28 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ | ||
29 | fname = "typescript"; \ | ||
30 | } while (0) | ||
31 | |||
32 | static void done(void) | ||
33 | { | ||
34 | if (child_pid) { /* we are parent */ | ||
35 | if (attr_ok == 0) | ||
36 | tcsetattr(0, TCSAFLUSH, &tt); | ||
37 | if (!(option_mask32 & 8)) /* not -q */ | ||
38 | printf("Script done, file is %s\n", fname); | ||
39 | } | ||
40 | exit(0); | ||
41 | } | ||
42 | |||
43 | #ifdef UNUSED | ||
44 | static void handle_sigchld(int sig) | ||
45 | { | ||
46 | /* wait for the exited child and exit */ | ||
47 | while (wait_any_nohang(&sig) > 0) | ||
48 | continue; | ||
49 | done(); | ||
50 | } | ||
51 | #endif | ||
52 | |||
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" | ||
59 | ; | ||
60 | #endif | ||
61 | |||
62 | int script_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; | ||
63 | int script_main(int argc, char *argv[]) | ||
64 | { | ||
65 | int opt, pty; | ||
66 | int winsz_ok; | ||
67 | int mode; | ||
68 | struct termios rtt; | ||
69 | struct winsize win; | ||
70 | char line[32]; | ||
71 | const char *shell; | ||
72 | char shell_opt[] = "-i"; | ||
73 | char *shell_arg = NULL; | ||
74 | |||
75 | INIT_G(); | ||
76 | #if ENABLE_GETOPT_LONG | ||
77 | applet_long_options = getopt_longopts; | ||
78 | #endif | ||
79 | opt_complementary = "?1"; /* max one arg */ | ||
80 | opt = getopt32(argv, "ac:fq", &shell_arg); | ||
81 | //argc -= optind; | ||
82 | argv += optind; | ||
83 | if (argv[0]) { | ||
84 | fname = argv[0]; | ||
85 | } | ||
86 | mode = O_CREAT|O_TRUNC|O_WRONLY; | ||
87 | if (opt & 1) { | ||
88 | mode = O_CREAT|O_APPEND|O_WRONLY; | ||
89 | } | ||
90 | if (opt & 2) { | ||
91 | shell_opt[1] = 'c'; | ||
92 | } | ||
93 | if (!(opt & 8)) { /* not -q */ | ||
94 | printf("Script started, file is %s\n", fname); | ||
95 | } | ||
96 | shell = getenv("SHELL"); | ||
97 | if (shell == NULL) { | ||
98 | shell = _PATH_BSHELL; | ||
99 | } | ||
100 | |||
101 | pty = getpty(line, sizeof(line)); | ||
102 | if (pty < 0) { | ||
103 | bb_perror_msg_and_die("can't get pty"); | ||
104 | } | ||
105 | |||
106 | /* get current stdin's tty params */ | ||
107 | attr_ok = tcgetattr(0, &tt); | ||
108 | winsz_ok = ioctl(0, TIOCGWINSZ, (char *)&win); | ||
109 | |||
110 | rtt = tt; | ||
111 | cfmakeraw(&rtt); | ||
112 | rtt.c_lflag &= ~ECHO; | ||
113 | tcsetattr(0, TCSAFLUSH, &rtt); | ||
114 | |||
115 | /* We exit as soon as child exits */ | ||
116 | //signal(SIGCHLD, handle_sigchld); | ||
117 | signal(SIGCHLD, (void (*)(int)) done); | ||
118 | |||
119 | child_pid = vfork(); | ||
120 | if (child_pid < 0) { | ||
121 | bb_perror_msg_and_die("vfork"); | ||
122 | } | ||
123 | |||
124 | if (child_pid) { | ||
125 | /* parent */ | ||
126 | char buf[256]; | ||
127 | struct pollfd pfd[2]; | ||
128 | int outfd; | ||
129 | int fd_count = 2; | ||
130 | struct pollfd *ppfd = pfd; | ||
131 | |||
132 | outfd = xopen(fname, mode); | ||
133 | pfd[0].fd = 0; | ||
134 | pfd[0].events = POLLIN; | ||
135 | pfd[1].fd = pty; | ||
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! */ | ||
139 | |||
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)); | ||
146 | if (count <= 0) { | ||
147 | /* err/eof: don't read anymore */ | ||
148 | pfd[0].revents = 0; | ||
149 | ppfd++; | ||
150 | fd_count--; | ||
151 | } else { | ||
152 | full_write(pty, buf, count); | ||
153 | } | ||
154 | } | ||
155 | if (pfd[1].revents) { | ||
156 | int count; | ||
157 | errno = 0; | ||
158 | count = safe_read(pty, buf, sizeof(buf)); | ||
159 | if (count <= 0 && errno != EAGAIN) { | ||
160 | /* err/eof: don't read anymore */ | ||
161 | pfd[1].revents = 0; | ||
162 | fd_count--; | ||
163 | } | ||
164 | if (count > 0) { | ||
165 | full_write(1, buf, count); | ||
166 | full_write(outfd, buf, count); | ||
167 | if (opt & 4) { /* -f */ | ||
168 | fsync(outfd); | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | done(); /* does not return */ | ||
174 | } | ||
175 | |||
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 */ | ||
179 | close(0); | ||
180 | xopen(line, O_RDWR); /* uses fd 0 */ | ||
181 | xdup2(0, 1); | ||
182 | xdup2(0, 2); | ||
183 | /* copy our original stdin tty's parameters to pty */ | ||
184 | if (attr_ok == 0) | ||
185 | tcsetattr(0, TCSAFLUSH, &tt); | ||
186 | if (winsz_ok == 0) | ||
187 | ioctl(0, TIOCSWINSZ, (char *)&win); | ||
188 | /* set pty as a controlling tty */ | ||
189 | setsid(); | ||
190 | ioctl(0, TIOCSCTTY, 0 /* 0: don't forcibly steal */); | ||
191 | |||
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); | ||
195 | } | ||