aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-05-19 17:36:16 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-05-19 17:36:16 +0200
commit5e61115ea45c621867941e52e6ac016680415656 (patch)
tree7e92d0ee0720d907b4b35bfa510c3969c79eaaa8
parent5a49d284a6a9f6cf2076f23561f95aebdfd44592 (diff)
downloadbusybox-w32-5e61115ea45c621867941e52e6ac016680415656.tar.gz
busybox-w32-5e61115ea45c621867941e52e6ac016680415656.tar.bz2
busybox-w32-5e61115ea45c621867941e52e6ac016680415656.zip
scriptreplay: new applet. +423 bytes
Signed-off-by: Pascal Bellard <pascal.bellard@ads-lu.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--include/applets.h1
-rw-r--r--include/usage.h10
-rw-r--r--util-linux/Config.in7
-rw-r--r--util-linux/Kbuild1
-rw-r--r--util-linux/script.c59
-rw-r--r--util-linux/scriptreplay.c38
6 files changed, 95 insertions, 21 deletions
diff --git a/include/applets.h b/include/applets.h
index 359440def..7838757f5 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -326,6 +326,7 @@ IF_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
326IF_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 326IF_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
327IF_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 327IF_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
328IF_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 328IF_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
329IF_SCRIPTREPLAY(APPLET(scriptreplay, _BB_DIR_BIN, _BB_SUID_NEVER))
329IF_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER)) 330IF_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER))
330IF_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 331IF_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
331IF_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 332IF_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
diff --git a/include/usage.h b/include/usage.h
index 123462a02..1e327fb97 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3512,6 +3512,11 @@
3512 "\n -g Process group id(s)" \ 3512 "\n -g Process group id(s)" \
3513 "\n -u Process user name(s) and/or id(s)" \ 3513 "\n -u Process user name(s) and/or id(s)" \
3514 3514
3515#define scriptreplay_trivial_usage \
3516 "timingfile [typescript [divisor]]"
3517#define scriptreplay_full_usage "\n\n" \
3518 "Play back typescripts, using timing information"
3519
3515#define reset_trivial_usage \ 3520#define reset_trivial_usage \
3516 "" 3521 ""
3517#define reset_full_usage "\n\n" \ 3522#define reset_full_usage "\n\n" \
@@ -3706,13 +3711,16 @@
3706 "$ rx /tmp/foo\n" 3711 "$ rx /tmp/foo\n"
3707 3712
3708#define script_trivial_usage \ 3713#define script_trivial_usage \
3709 "[-afq] [-c COMMAND] [OUTFILE]" 3714 "[-afq" IF_SCRIPTREPLAY("t") "] [-c COMMAND] [OUTFILE]"
3710#define script_full_usage "\n\n" \ 3715#define script_full_usage "\n\n" \
3711 "Options:" \ 3716 "Options:" \
3712 "\n -a Append output" \ 3717 "\n -a Append output" \
3713 "\n -c Run COMMAND, not shell" \ 3718 "\n -c Run COMMAND, not shell" \
3714 "\n -f Flush output after each write" \ 3719 "\n -f Flush output after each write" \
3715 "\n -q Quiet" \ 3720 "\n -q Quiet" \
3721 IF_SCRIPTREPLAY( \
3722 "\n -t Send timing to stderr" \
3723 )
3716 3724
3717#define sed_trivial_usage \ 3725#define sed_trivial_usage \
3718 "[-efinr] pattern [files...]" 3726 "[-efinr] pattern [files...]"
diff --git a/util-linux/Config.in b/util-linux/Config.in
index e5c053fcf..024550172 100644
--- a/util-linux/Config.in
+++ b/util-linux/Config.in
@@ -764,6 +764,13 @@ config SCRIPT
764 help 764 help
765 The script makes typescript of terminal session. 765 The script makes typescript of terminal session.
766 766
767config SCRIPTREPLAY
768 bool "scriptreplay"
769 default n
770 help
771 This program replays a typescript, using timing information
772 given by script -t.
773
767config SETARCH 774config SETARCH
768 bool "setarch" 775 bool "setarch"
769 default n 776 default n
diff --git a/util-linux/Kbuild b/util-linux/Kbuild
index ac071c620..eaad3319d 100644
--- a/util-linux/Kbuild
+++ b/util-linux/Kbuild
@@ -33,6 +33,7 @@ lib-$(CONFIG_RDEV) += rdev.o
33lib-$(CONFIG_READPROFILE) += readprofile.o 33lib-$(CONFIG_READPROFILE) += readprofile.o
34lib-$(CONFIG_RTCWAKE) += rtcwake.o 34lib-$(CONFIG_RTCWAKE) += rtcwake.o
35lib-$(CONFIG_SCRIPT) += script.o 35lib-$(CONFIG_SCRIPT) += script.o
36lib-$(CONFIG_SCRIPTREPLAY) += scriptreplay.o
36lib-$(CONFIG_SETARCH) += setarch.o 37lib-$(CONFIG_SETARCH) += setarch.o
37lib-$(CONFIG_SWAPONOFF) += swaponoff.o 38lib-$(CONFIG_SWAPONOFF) += swaponoff.o
38lib-$(CONFIG_SWITCH_ROOT) += switch_root.o 39lib-$(CONFIG_SWITCH_ROOT) += switch_root.o
diff --git a/util-linux/script.c b/util-linux/script.c
index a9f24b10e..d16a2914a 100644
--- a/util-linux/script.c
+++ b/util-linux/script.c
@@ -10,16 +10,8 @@
10 * 10 *
11 * Licensed under GPLv2 or later, see file License in this tarball for details. 11 * Licensed under GPLv2 or later, see file License in this tarball for details.
12 */ 12 */
13
14#include "libbb.h" 13#include "libbb.h"
15 14
16static smallint fd_count = 2;
17
18static void handle_sigchld(int sig UNUSED_PARAM)
19{
20 fd_count = 0;
21}
22
23int script_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 15int script_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
24int script_main(int argc UNUSED_PARAM, char **argv) 16int script_main(int argc UNUSED_PARAM, char **argv)
25{ 17{
@@ -36,6 +28,15 @@ int script_main(int argc UNUSED_PARAM, char **argv)
36 const char *shell; 28 const char *shell;
37 char shell_opt[] = "-i"; 29 char shell_opt[] = "-i";
38 char *shell_arg = NULL; 30 char *shell_arg = NULL;
31 enum {
32 OPT_a = (1 << 0),
33 OPT_c = (1 << 1),
34 OPT_f = (1 << 2),
35 OPT_q = (1 << 3),
36#if ENABLE_SCRIPTREPLAY
37 OPT_t = (1 << 4),
38#endif
39 };
39 40
40#if ENABLE_GETOPT_LONG 41#if ENABLE_GETOPT_LONG
41 static const char getopt_longopts[] ALIGN1 = 42 static const char getopt_longopts[] ALIGN1 =
@@ -43,25 +44,28 @@ int script_main(int argc UNUSED_PARAM, char **argv)
43 "command\0" Required_argument "c" 44 "command\0" Required_argument "c"
44 "flush\0" No_argument "f" 45 "flush\0" No_argument "f"
45 "quiet\0" No_argument "q" 46 "quiet\0" No_argument "q"
47# if ENABLE_SCRIPTREPLAY
48 "timing\0" No_argument "t"
49# endif
46 ; 50 ;
47 51
48 applet_long_options = getopt_longopts; 52 applet_long_options = getopt_longopts;
49#endif 53#endif
50 opt_complementary = "?1"; /* max one arg */ 54 opt_complementary = "?1"; /* max one arg */
51 opt = getopt32(argv, "ac:fq", &shell_arg); 55 opt = getopt32(argv, "ac:fq" IF_SCRIPTREPLAY("t") , &shell_arg);
52 //argc -= optind; 56 //argc -= optind;
53 argv += optind; 57 argv += optind;
54 if (argv[0]) { 58 if (argv[0]) {
55 fname = argv[0]; 59 fname = argv[0];
56 } 60 }
57 mode = O_CREAT|O_TRUNC|O_WRONLY; 61 mode = O_CREAT|O_TRUNC|O_WRONLY;
58 if (opt & 1) { 62 if (opt & OPT_a) {
59 mode = O_CREAT|O_APPEND|O_WRONLY; 63 mode = O_CREAT|O_APPEND|O_WRONLY;
60 } 64 }
61 if (opt & 2) { 65 if (opt & OPT_c) {
62 shell_opt[1] = 'c'; 66 shell_opt[1] = 'c';
63 } 67 }
64 if (!(opt & 8)) { /* not -q */ 68 if (!(opt & OPT_q)) {
65 printf("Script started, file is %s\n", fname); 69 printf("Script started, file is %s\n", fname);
66 } 70 }
67 shell = getenv("SHELL"); 71 shell = getenv("SHELL");
@@ -83,7 +87,7 @@ int script_main(int argc UNUSED_PARAM, char **argv)
83 /* "script" from util-linux exits when child exits, 87 /* "script" from util-linux exits when child exits,
84 * we wouldn't wait for EOF from slave pty 88 * we wouldn't wait for EOF from slave pty
85 * (output may be produced by grandchildren of child) */ 89 * (output may be produced by grandchildren of child) */
86 signal(SIGCHLD, handle_sigchld); 90 signal(SIGCHLD, record_signo);
87 91
88 /* TODO: SIGWINCH? pass window size changes down to slave? */ 92 /* TODO: SIGWINCH? pass window size changes down to slave? */
89 93
@@ -97,19 +101,23 @@ int script_main(int argc UNUSED_PARAM, char **argv)
97#define buf bb_common_bufsiz1 101#define buf bb_common_bufsiz1
98 struct pollfd pfd[2]; 102 struct pollfd pfd[2];
99 int outfd, count, loop; 103 int outfd, count, loop;
104#if ENABLE_SCRIPTREPLAY
105 double oldtime = time(NULL);
106#endif
107 smallint fd_count = 2;
100 108
101 outfd = xopen(fname, mode); 109 outfd = xopen(fname, mode);
102 pfd[0].fd = pty; 110 pfd[0].fd = pty;
103 pfd[0].events = POLLIN; 111 pfd[0].events = POLLIN;
104 pfd[1].fd = 0; 112 pfd[1].fd = STDIN_FILENO;
105 pfd[1].events = POLLIN; 113 pfd[1].events = POLLIN;
106 ndelay_on(pty); /* this descriptor is not shared, can do this */ 114 ndelay_on(pty); /* this descriptor is not shared, can do this */
107 /* ndelay_on(0); - NO, stdin can be shared! Pity :( */ 115 /* ndelay_on(STDIN_FILENO); - NO, stdin can be shared! Pity :( */
108 116
109 /* copy stdin to pty master input, 117 /* copy stdin to pty master input,
110 * copy pty master output to stdout and file */ 118 * copy pty master output to stdout and file */
111 /* TODO: don't use full_write's, use proper write buffering */ 119 /* TODO: don't use full_write's, use proper write buffering */
112 while (fd_count) { 120 while (fd_count && !bb_got_signal) {
113 /* not safe_poll! we want SIGCHLD to EINTR poll */ 121 /* not safe_poll! we want SIGCHLD to EINTR poll */
114 if (poll(pfd, fd_count, -1) < 0 && errno != EINTR) { 122 if (poll(pfd, fd_count, -1) < 0 && errno != EINTR) {
115 /* If child exits too quickly, we may get EIO: 123 /* If child exits too quickly, we may get EIO:
@@ -124,9 +132,20 @@ int script_main(int argc UNUSED_PARAM, char **argv)
124 goto restore; 132 goto restore;
125 } 133 }
126 if (count > 0) { 134 if (count > 0) {
135#if ENABLE_SCRIPTREPLAY
136 if (opt & OPT_t) {
137 struct timeval tv;
138 double newtime;
139
140 gettimeofday(&tv, NULL);
141 newtime = tv.tv_sec + (double) tv.tv_usec / 1000000;
142 fprintf(stderr, "%f %u\n", newtime - oldtime, count);
143 oldtime = newtime;
144 }
145#endif
127 full_write(STDOUT_FILENO, buf, count); 146 full_write(STDOUT_FILENO, buf, count);
128 full_write(outfd, buf, count); 147 full_write(outfd, buf, count);
129 if (opt & 4) { /* -f */ 148 if (opt & OPT_f) {
130 fsync(outfd); 149 fsync(outfd);
131 } 150 }
132 } 151 }
@@ -142,8 +161,8 @@ int script_main(int argc UNUSED_PARAM, char **argv)
142 } 161 }
143 } 162 }
144 } 163 }
145 /* If loop was exited because SIGCHLD handler set fd_count to 0, 164 /* If loop was exited because SIGCHLD handler set bb_got_signal,
146 * there still can be some buffered output. But not loop forever: 165 * there still can be some buffered output. But dont loop forever:
147 * we won't pump orphaned grandchildren's output indefinitely. 166 * we won't pump orphaned grandchildren's output indefinitely.
148 * Testcase: running this in script: 167 * Testcase: running this in script:
149 * exec dd if=/dev/zero bs=1M count=1 168 * exec dd if=/dev/zero bs=1M count=1
@@ -158,7 +177,7 @@ int script_main(int argc UNUSED_PARAM, char **argv)
158 restore: 177 restore:
159 if (attr_ok == 0) 178 if (attr_ok == 0)
160 tcsetattr(0, TCSAFLUSH, &tt); 179 tcsetattr(0, TCSAFLUSH, &tt);
161 if (!(opt & 8)) /* not -q */ 180 if (!(opt & OPT_q))
162 printf("Script done, file is %s\n", fname); 181 printf("Script done, file is %s\n", fname);
163 return EXIT_SUCCESS; 182 return EXIT_SUCCESS;
164 } 183 }
diff --git a/util-linux/scriptreplay.c b/util-linux/scriptreplay.c
new file mode 100644
index 000000000..038dbdfe1
--- /dev/null
+++ b/util-linux/scriptreplay.c
@@ -0,0 +1,38 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * scriptreplay - play back typescripts, using timing information
4 *
5 * pascal.bellard@ads-lu.com
6 *
7 * Licensed under GPLv2 or later, see file License in this tarball for details.
8 *
9 */
10#include "libbb.h"
11
12int scriptreplay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13int scriptreplay_main(int argc UNUSED_PARAM, char **argv)
14{
15 const char *script = "typescript";
16 double delay, factor = 1000000.0;
17 int fd;
18 unsigned long count;
19 FILE *tfp;
20
21 if (argv[2]) {
22 script = argv[2];
23 if (argv[3])
24 factor /= atof(argv[3]);
25 }
26
27 tfp = xfopen_for_read(argv[1]);
28 fd = xopen(script, O_RDONLY);
29 while (fscanf(tfp, "%lf %lu\n", &delay, &count) == 2) {
30 usleep(delay * factor);
31 bb_copyfd_exact_size(fd, STDOUT_FILENO, count);
32 }
33#if ENABLE_FEATURE_CLEAN_UP
34 close(fd);
35 fclose(tfp);
36#endif
37 return EXIT_SUCCESS;
38}