aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/applets.h1
-rw-r--r--include/libbb.h1
-rw-r--r--include/usage.h9
-rw-r--r--libbb/Kbuild1
-rw-r--r--miscutils/Config.in6
-rw-r--r--networking/telnetd.c47
-rw-r--r--util-linux/Kbuild1
-rw-r--r--util-linux/script.c195
8 files changed, 214 insertions, 47 deletions
diff --git a/include/applets.h b/include/applets.h
index b2e89ee85..d4b6dbeaa 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -305,6 +305,7 @@ USE_RUNLEVEL(APPLET(runlevel, _BB_DIR_SBIN, _BB_SUID_NEVER))
305USE_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 305USE_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
306USE_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 306USE_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
307USE_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 307USE_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
308USE_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
308USE_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER)) 309USE_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER))
309USE_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 310USE_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
310USE_SENDMAIL(APPLET_ODDNAME(sendmail, sendgetmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sendmail)) 311USE_SENDMAIL(APPLET_ODDNAME(sendmail, sendgetmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sendmail))
diff --git a/include/libbb.h b/include/libbb.h
index 978cd2d87..707e8d69b 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -237,6 +237,7 @@ extern int recursive_action(const char *fileName, unsigned flags,
237 int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData, int depth), 237 int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData, int depth),
238 void* userData, unsigned depth); 238 void* userData, unsigned depth);
239extern int device_open(const char *device, int mode); 239extern int device_open(const char *device, int mode);
240extern int getpty(char *line, int size);
240extern int get_console_fd(void); 241extern int get_console_fd(void);
241extern char *find_block_device(const char *path); 242extern char *find_block_device(const char *path);
242/* bb_copyfd_XX print read/write errors and return -1 if they occur */ 243/* bb_copyfd_XX print read/write errors and return -1 if they occur */
diff --git a/include/usage.h b/include/usage.h
index 95cb69c73..4eac17401 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3234,6 +3234,15 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when
3234#define rx_example_usage \ 3234#define rx_example_usage \
3235 "$ rx /tmp/foo\n" 3235 "$ rx /tmp/foo\n"
3236 3236
3237#define script_trivial_usage \
3238 "[-afq] [-c COMMAND] [OUTFILE]"
3239#define script_full_usage \
3240 "Options:" \
3241 "\n -a Append output" \
3242 "\n -c Run COMMAND, not shell" \
3243 "\n -f Flush output after each write" \
3244 "\n -q Quiet"
3245
3237#define sed_trivial_usage \ 3246#define sed_trivial_usage \
3238 "[-efinr] pattern [files...]" 3247 "[-efinr] pattern [files...]"
3239#define sed_full_usage \ 3248#define sed_full_usage \
diff --git a/libbb/Kbuild b/libbb/Kbuild
index aab016e85..fc87f625b 100644
--- a/libbb/Kbuild
+++ b/libbb/Kbuild
@@ -39,6 +39,7 @@ lib-y += get_console.o
39lib-y += get_last_path_component.o 39lib-y += get_last_path_component.o
40lib-y += get_line_from_file.o 40lib-y += get_line_from_file.o
41lib-y += getopt32.o 41lib-y += getopt32.o
42lib-y += getpty.o
42lib-y += herror_msg.o 43lib-y += herror_msg.o
43lib-y += herror_msg_and_die.o 44lib-y += herror_msg_and_die.o
44lib-y += human_readable.o 45lib-y += human_readable.o
diff --git a/miscutils/Config.in b/miscutils/Config.in
index 73c765f2c..ac1e2b57c 100644
--- a/miscutils/Config.in
+++ b/miscutils/Config.in
@@ -410,6 +410,12 @@ config RX
410 help 410 help
411 Receive files using the Xmodem protocol. 411 Receive files using the Xmodem protocol.
412 412
413config SCRIPT
414 bool "script"
415 default n
416 help
417 The script makes typescript of terminal session.
418
413config STRINGS 419config STRINGS
414 bool "strings" 420 bool "strings"
415 default n 421 default n
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 0bffa9700..05de49e8a 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -153,53 +153,6 @@ remove_iacs(struct tsession *ts, int *pnum_totty)
153} 153}
154 154
155 155
156static int
157getpty(char *line, int size)
158{
159 int p;
160#if ENABLE_FEATURE_DEVPTS
161 p = open("/dev/ptmx", O_RDWR);
162 if (p > 0) {
163 const char *name;
164 grantpt(p);
165 unlockpt(p);
166 name = ptsname(p);
167 if (!name) {
168 bb_perror_msg("ptsname error (is /dev/pts mounted?)");
169 return -1;
170 }
171 safe_strncpy(line, name, size);
172 return p;
173 }
174#else
175 struct stat stb;
176 int i;
177 int j;
178
179 strcpy(line, "/dev/ptyXX");
180
181 for (i = 0; i < 16; i++) {
182 line[8] = "pqrstuvwxyzabcde"[i];
183 line[9] = '0';
184 if (stat(line, &stb) < 0) {
185 continue;
186 }
187 for (j = 0; j < 16; j++) {
188 line[9] = j < 10 ? j + '0' : j - 10 + 'a';
189 if (DEBUG)
190 fprintf(stderr, "Trying to open device: %s\n", line);
191 p = open(line, O_RDWR | O_NOCTTY);
192 if (p >= 0) {
193 line[5] = 't';
194 return p;
195 }
196 }
197 }
198#endif /* FEATURE_DEVPTS */
199 return -1;
200}
201
202
203static struct tsession * 156static struct tsession *
204make_new_session( 157make_new_session(
205 USE_FEATURE_TELNETD_STANDALONE(int sock) 158 USE_FEATURE_TELNETD_STANDALONE(int sock)
diff --git a/util-linux/Kbuild b/util-linux/Kbuild
index c71186e86..0f33c6be2 100644
--- a/util-linux/Kbuild
+++ b/util-linux/Kbuild
@@ -28,6 +28,7 @@ lib-$(CONFIG_PIVOT_ROOT) +=pivot_root.o
28lib-$(CONFIG_RDATE) +=rdate.o 28lib-$(CONFIG_RDATE) +=rdate.o
29lib-$(CONFIG_READPROFILE) +=readprofile.o 29lib-$(CONFIG_READPROFILE) +=readprofile.o
30lib-$(CONFIG_RTCWAKE) +=rtcwake.o 30lib-$(CONFIG_RTCWAKE) +=rtcwake.o
31lib-$(CONFIG_SCRIPT) +=script.o
31lib-$(CONFIG_SETARCH) +=setarch.o 32lib-$(CONFIG_SETARCH) +=setarch.o
32lib-$(CONFIG_SWAPONOFF) +=swaponoff.o 33lib-$(CONFIG_SWAPONOFF) +=swaponoff.o
33lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o 34lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o
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
16struct 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
32static 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
44static 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
54static 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
62int script_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE;
63int 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}