aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/Config.src7
-rw-r--r--shell/ash.c33
-rw-r--r--shell/ash_test/ash-read/read_ifs2.right9
-rwxr-xr-xshell/ash_test/ash-read/read_ifs2.tests9
-rw-r--r--shell/ash_test/ash-read/read_t.right8
-rwxr-xr-xshell/ash_test/ash-read/read_t.tests18
-rw-r--r--shell/ash_test/printenv.c4
-rw-r--r--shell/ash_test/recho.c2
-rw-r--r--shell/hush.c48
-rw-r--r--shell/hush_test/hush-read/read_t.right8
-rwxr-xr-xshell/hush_test/hush-read/read_t.tests18
-rw-r--r--shell/shell_common.c22
12 files changed, 129 insertions, 57 deletions
diff --git a/shell/Config.src b/shell/Config.src
index 5efbf9995..5b3fe08f3 100644
--- a/shell/Config.src
+++ b/shell/Config.src
@@ -166,9 +166,10 @@ config FEATURE_SH_HISTFILESIZE
166 default y 166 default y
167 depends on SHELL_ASH || SHELL_HUSH 167 depends on SHELL_ASH || SHELL_HUSH
168 help 168 help
169 This option makes busybox shells to use $HISTFILESIZE variable 169 This option makes busybox shells to use $HISTSIZE and
170 to set shell history size. Note that its max value is capped 170 $HISTFILESIZE variables to set shell history size.
171 by "History size" setting in library tuning section. 171 Note that its max value is capped by "History size" setting
172 in library tuning section.
172 173
173config FEATURE_SH_EMBEDDED_SCRIPTS 174config FEATURE_SH_EMBEDDED_SCRIPTS
174 bool "Embed scripts in the binary" 175 bool "Embed scripts in the binary"
diff --git a/shell/ash.c b/shell/ash.c
index 99fbf6053..0038aa1e9 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4275,7 +4275,7 @@ signal_handler(int signo)
4275 return; 4275 return;
4276 } 4276 }
4277#if ENABLE_FEATURE_EDITING 4277#if ENABLE_FEATURE_EDITING
4278 bb_got_signal = signo; /* for read_line_input: "we got a signal" */ 4278 bb_got_signal = signo; /* for read_line_input / read builtin: "we got a signal" */
4279#endif 4279#endif
4280 gotsig[signo - 1] = 1; 4280 gotsig[signo - 1] = 1;
4281 pending_sig = signo; 4281 pending_sig = signo;
@@ -15821,6 +15821,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
15821 if (pending_sig == 0) 15821 if (pending_sig == 0)
15822 goto again; 15822 goto again;
15823 } 15823 }
15824
15825 if ((uintptr_t)r == 2) /* -t SEC timeout? */
15826 /* bash: "The exit status is greater than 128 if the timeout is exceeded." */
15827 /* The actual value observed with bash 5.2.15: */
15828 return 128 + SIGALRM;
15824#else /* ENABLE_PLATFORM_MINGW32 */ 15829#else /* ENABLE_PLATFORM_MINGW32 */
15825 if ((uintptr_t)r == 2) { 15830 if ((uintptr_t)r == 2) {
15826 /* Timeout, return 128 + SIGALRM */ 15831 /* Timeout, return 128 + SIGALRM */
@@ -15973,8 +15978,25 @@ exitshell(void)
15973 char *p; 15978 char *p;
15974 15979
15975#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 15980#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
15976 save_history(line_input_state); /* may be NULL */ 15981 if (line_input_state) {
15982 const char *hp;
15983# if ENABLE_FEATURE_SH_HISTFILESIZE
15984// in bash:
15985// HISTFILESIZE controls the on-disk history file size (in lines, 0=no history):
15986// "When this variable is assigned a value, the history file is truncated, if necessary"
15987// but we do it only at exit, not on assignment:
15988 /* Use HISTFILESIZE to limit file size */
15989 hp = lookupvar("HISTFILESIZE");
15990 if (hp)
15991 line_input_state->max_history = size_from_HISTFILESIZE(hp);
15992# endif
15993 /* HISTFILE: "If unset, the command history is not saved when a shell exits." */
15994 hp = lookupvar("HISTFILE");
15995 line_input_state->hist_file = hp;
15996 save_history(line_input_state); /* no-op if hist_file is NULL or "" */
15997 }
15977#endif 15998#endif
15999
15978 savestatus = exitstatus; 16000 savestatus = exitstatus;
15979 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); 16001 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
15980 if (setjmp(loc.loc)) 16002 if (setjmp(loc.loc))
@@ -16478,7 +16500,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
16478 if (hp) 16500 if (hp)
16479 line_input_state->hist_file = xstrdup(hp); 16501 line_input_state->hist_file = xstrdup(hp);
16480# if ENABLE_FEATURE_SH_HISTFILESIZE 16502# if ENABLE_FEATURE_SH_HISTFILESIZE
16481 hp = lookupvar("HISTFILESIZE"); 16503 hp = lookupvar("HISTSIZE");
16504 /* Using HISTFILESIZE above to limit max_history would be WRONG:
16505 * users may set HISTFILESIZE=0 in their profile scripts
16506 * to prevent _saving_ of history files, but still want to have
16507 * non-zero history limit for in-memory list.
16508 */
16482 line_input_state->max_history = size_from_HISTFILESIZE(hp); 16509 line_input_state->max_history = size_from_HISTFILESIZE(hp);
16483# endif 16510# endif
16484 } 16511 }
diff --git a/shell/ash_test/ash-read/read_ifs2.right b/shell/ash_test/ash-read/read_ifs2.right
new file mode 100644
index 000000000..797137dae
--- /dev/null
+++ b/shell/ash_test/ash-read/read_ifs2.right
@@ -0,0 +1,9 @@
1|X|Y:Z:|
2|X|Y:Z|
3|X|Y|
4|X|Y|
5|X||
6|X||
7|||
8Whitespace should be trimmed too:
9|X|Y|
diff --git a/shell/ash_test/ash-read/read_ifs2.tests b/shell/ash_test/ash-read/read_ifs2.tests
new file mode 100755
index 000000000..f01a68978
--- /dev/null
+++ b/shell/ash_test/ash-read/read_ifs2.tests
@@ -0,0 +1,9 @@
1echo "X:Y:Z:" | (IFS=": " read x y; echo "|$x|$y|")
2echo "X:Y:Z" | (IFS=": " read x y; echo "|$x|$y|")
3echo "X:Y:" | (IFS=": " read x y; echo "|$x|$y|")
4echo "X:Y" | (IFS=": " read x y; echo "|$x|$y|")
5echo "X:" | (IFS=": " read x y; echo "|$x|$y|")
6echo "X" | (IFS=": " read x y; echo "|$x|$y|")
7echo "" | (IFS=": " read x y; echo "|$x|$y|")
8echo Whitespace should be trimmed too:
9echo "X:Y : " | (IFS=": " read x y; echo "|$x|$y|")
diff --git a/shell/ash_test/ash-read/read_t.right b/shell/ash_test/ash-read/read_t.right
index 04126cbe6..3eedae275 100644
--- a/shell/ash_test/ash-read/read_t.right
+++ b/shell/ash_test/ash-read/read_t.right
@@ -1,4 +1,4 @@
1>< 1>te:142<
2>< 2>:142<
3>test< 3>test:0<
4>test< 4>test:0<
diff --git a/shell/ash_test/ash-read/read_t.tests b/shell/ash_test/ash-read/read_t.tests
index d65f1aeaa..9fbeec517 100755
--- a/shell/ash_test/ash-read/read_t.tests
+++ b/shell/ash_test/ash-read/read_t.tests
@@ -1,10 +1,10 @@
1# bash 3.2 outputs: 1# bash 5.2 outputs:
2 2
3# >< 3# >te:142<
4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<") 4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply:$?<")
5# >< 5# >:142<
6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<") 6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply:$?<")
7# >test< 7# >test:0<
8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<") 8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply:$?<")
9# >test< 9# >test:0<
10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<") 10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply:$?<")
diff --git a/shell/ash_test/printenv.c b/shell/ash_test/printenv.c
index c86308d3b..f0f41984d 100644
--- a/shell/ash_test/printenv.c
+++ b/shell/ash_test/printenv.c
@@ -31,9 +31,7 @@
31extern char **environ; 31extern char **environ;
32 32
33int 33int
34main (argc, argv) 34main (int argc, char **argv)
35 int argc;
36 char **argv;
37{ 35{
38 register char **envp, *eval; 36 register char **envp, *eval;
39 int len; 37 int len;
diff --git a/shell/ash_test/recho.c b/shell/ash_test/recho.c
index 42a5feafd..7e96b14cc 100644
--- a/shell/ash_test/recho.c
+++ b/shell/ash_test/recho.c
@@ -27,7 +27,7 @@
27#include <stdio.h> 27#include <stdio.h>
28#include <stdlib.h> 28#include <stdlib.h>
29 29
30void strprint(); 30void strprint(char *);
31 31
32int main(int argc, char **argv) 32int main(int argc, char **argv)
33{ 33{
diff --git a/shell/hush.c b/shell/hush.c
index 4a97293cc..0b2bc01f5 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1973,7 +1973,7 @@ static void record_pending_signo(int sig)
1973 || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0]) 1973 || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0])
1974 /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */ 1974 /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */
1975 ) { 1975 ) {
1976 bb_got_signal = sig; /* for read_line_input: "we got a signal" */ 1976 bb_got_signal = sig; /* for read_line_input / read builtin: "we got a signal" */
1977 } 1977 }
1978#endif 1978#endif
1979#if ENABLE_HUSH_FAST 1979#if ENABLE_HUSH_FAST
@@ -2099,11 +2099,29 @@ static sighandler_t pick_sighandler(unsigned sig)
2099 return handler; 2099 return handler;
2100} 2100}
2101 2101
2102static const char* FAST_FUNC get_local_var_value(const char *name);
2103
2102/* Restores tty foreground process group, and exits. */ 2104/* Restores tty foreground process group, and exits. */
2103static void hush_exit(int exitcode) 2105static void hush_exit(int exitcode)
2104{ 2106{
2105#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 2107#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
2106 save_history(G.line_input_state); /* may be NULL */ 2108 if (G.line_input_state) {
2109 const char *hp;
2110# if ENABLE_FEATURE_SH_HISTFILESIZE
2111// in bash:
2112// HISTFILESIZE controls the on-disk history file size (in lines, 0=no history):
2113// "When this variable is assigned a value, the history file is truncated, if necessary"
2114// but we do it only at exit, not on every assignment:
2115 /* Use HISTFILESIZE to limit file size */
2116 hp = get_local_var_value("HISTFILESIZE");
2117 if (hp)
2118 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
2119# endif
2120 /* HISTFILE: "If unset, the command history is not saved when a shell exits." */
2121 hp = get_local_var_value("HISTFILE");
2122 G.line_input_state->hist_file = hp;
2123 save_history(G.line_input_state); /* no-op if hist_file is NULL or "" */
2124 }
2107#endif 2125#endif
2108 2126
2109 fflush_all(); 2127 fflush_all();
@@ -10427,7 +10445,7 @@ int hush_main(int argc, char **argv)
10427 if (!get_local_var_value("PATH")) 10445 if (!get_local_var_value("PATH"))
10428 set_local_var_from_halves("PATH", bb_default_root_path); 10446 set_local_var_from_halves("PATH", bb_default_root_path);
10429 10447
10430 /* PS1/PS2 are set later, if we determine that we are interactive */ 10448 /* PS1/PS2/HISTFILE are set later, if we determine that we are interactive */
10431 10449
10432 /* bash also exports SHLVL and _, 10450 /* bash also exports SHLVL and _,
10433 * and sets (but doesn't export) the following variables: 10451 * and sets (but doesn't export) the following variables:
@@ -10449,7 +10467,6 @@ int hush_main(int argc, char **argv)
10449 * BASH_SOURCE=() 10467 * BASH_SOURCE=()
10450 * DIRSTACK=() 10468 * DIRSTACK=()
10451 * PIPESTATUS=([0]="0") 10469 * PIPESTATUS=([0]="0")
10452 * HISTFILE=/<xxx>/.bash_history
10453 * HISTFILESIZE=500 10470 * HISTFILESIZE=500
10454 * HISTSIZE=500 10471 * HISTSIZE=500
10455 * MAILCHECK=60 10472 * MAILCHECK=60
@@ -10809,18 +10826,30 @@ int hush_main(int argc, char **argv)
10809 const char *hp = get_local_var_value("HISTFILE"); 10826 const char *hp = get_local_var_value("HISTFILE");
10810 if (!hp) { 10827 if (!hp) {
10811 hp = get_local_var_value("HOME"); 10828 hp = get_local_var_value("HOME");
10812 if (hp) 10829 if (hp) {
10813 hp = concat_path_file(hp, ".hush_history"); 10830 hp = concat_path_file(hp, ".hush_history");
10831 /* Make HISTFILE set on exit (else history won't be saved) */
10832 set_local_var_from_halves("HISTFILE", hp);
10833 }
10814 } else { 10834 } else {
10815 hp = xstrdup(hp); 10835 hp = xstrdup(hp);
10816 } 10836 }
10817 if (hp) { 10837 if (hp) {
10818 G.line_input_state->hist_file = hp; 10838 G.line_input_state->hist_file = hp;
10819 //set_local_var(xasprintf("HISTFILE=%s", ...));
10820 } 10839 }
10821# if ENABLE_FEATURE_SH_HISTFILESIZE 10840# if ENABLE_FEATURE_SH_HISTFILESIZE
10822 hp = get_local_var_value("HISTFILESIZE"); 10841 hp = get_local_var_value("HISTSIZE");
10842 /* Using HISTFILESIZE above to limit max_history would be WRONG:
10843 * users may set HISTFILESIZE=0 in their profile scripts
10844 * to prevent _saving_ of history files, but still want to have
10845 * non-zero history limit for in-memory list.
10846 */
10847// in bash, runtime history size is controlled by HISTSIZE (0=no history),
10848// HISTFILESIZE controls on-disk history file size (in lines, 0=no history):
10823 G.line_input_state->max_history = size_from_HISTFILESIZE(hp); 10849 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
10850// HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files."
10851// HISTSIZE: "The shell sets the default value to 500 after reading any startup files."
10852// (meaning: if the value wasn't set after startup files, the default value is set as described above)
10824# endif 10853# endif
10825 } 10854 }
10826# endif 10855# endif
@@ -11175,6 +11204,11 @@ static int FAST_FUNC builtin_read(char **argv)
11175 goto again; 11204 goto again;
11176 } 11205 }
11177 11206
11207 if ((uintptr_t)r == 2) /* -t SEC timeout? */
11208 /* bash: "The exit status is greater than 128 if the timeout is exceeded." */
11209 /* The actual value observed with bash 5.2.15: */
11210 return 128 + SIGALRM;
11211
11178 if ((uintptr_t)r > 1) { 11212 if ((uintptr_t)r > 1) {
11179 bb_simple_error_msg(r); 11213 bb_simple_error_msg(r);
11180 r = (char*)(uintptr_t)1; 11214 r = (char*)(uintptr_t)1;
diff --git a/shell/hush_test/hush-read/read_t.right b/shell/hush_test/hush-read/read_t.right
index 04126cbe6..3eedae275 100644
--- a/shell/hush_test/hush-read/read_t.right
+++ b/shell/hush_test/hush-read/read_t.right
@@ -1,4 +1,4 @@
1>< 1>te:142<
2>< 2>:142<
3>test< 3>test:0<
4>test< 4>test:0<
diff --git a/shell/hush_test/hush-read/read_t.tests b/shell/hush_test/hush-read/read_t.tests
index d65f1aeaa..9fbeec517 100755
--- a/shell/hush_test/hush-read/read_t.tests
+++ b/shell/hush_test/hush-read/read_t.tests
@@ -1,10 +1,10 @@
1# bash 3.2 outputs: 1# bash 5.2 outputs:
2 2
3# >< 3# >te:142<
4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<") 4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply:$?<")
5# >< 5# >:142<
6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<") 6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply:$?<")
7# >test< 7# >test:0<
8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<") 8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply:$?<")
9# >test< 9# >test:0<
10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<") 10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply:$?<")
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 2702ef98a..657f0df8f 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -55,7 +55,7 @@ const char* FAST_FUNC
55shell_builtin_read(struct builtin_read_params *params) 55shell_builtin_read(struct builtin_read_params *params)
56{ 56{
57 struct pollfd pfd[1]; 57 struct pollfd pfd[1];
58#define fd (pfd[0].fd) /* -u FD */ 58#define fd (pfd->fd) /* -u FD */
59 unsigned err; 59 unsigned err;
60 unsigned end_ms; /* -t TIMEOUT */ 60 unsigned end_ms; /* -t TIMEOUT */
61 int nchars; /* -n NUM */ 61 int nchars; /* -n NUM */
@@ -144,7 +144,7 @@ shell_builtin_read(struct builtin_read_params *params)
144 * bash seems to ignore -p PROMPT for this use case. 144 * bash seems to ignore -p PROMPT for this use case.
145 */ 145 */
146 int r; 146 int r;
147 pfd[0].events = POLLIN; 147 pfd->events = POLLIN;
148 r = poll(pfd, 1, /*timeout:*/ 0); 148 r = poll(pfd, 1, /*timeout:*/ 0);
149 /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */ 149 /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */
150 return (const char *)(uintptr_t)(r <= 0); 150 return (const char *)(uintptr_t)(r <= 0);
@@ -209,13 +209,8 @@ shell_builtin_read(struct builtin_read_params *params)
209 * 32-bit unix time wrapped (year 2038+). 209 * 32-bit unix time wrapped (year 2038+).
210 */ 210 */
211 if (timeout <= 0) { /* already late? */ 211 if (timeout <= 0) { /* already late? */
212#if ENABLE_PLATFORM_MINGW32
213 retval = (const char *)(uintptr_t)2; 212 retval = (const char *)(uintptr_t)2;
214 break; 213 break;
215#else
216 retval = (const char *)(uintptr_t)1;
217 goto ret;
218#endif
219 } 214 }
220 } 215 }
221 216
@@ -224,8 +219,8 @@ shell_builtin_read(struct builtin_read_params *params)
224 * regardless of SA_RESTART-ness of that signal! 219 * regardless of SA_RESTART-ness of that signal!
225 */ 220 */
226 errno = 0; 221 errno = 0;
227 pfd[0].events = POLLIN; 222 pfd->events = POLLIN;
228//TODO race with a signal arriving just before the poll! 223
229#if ENABLE_PLATFORM_MINGW32 224#if ENABLE_PLATFORM_MINGW32
230 /* Don't poll if timeout is -1, it hurts performance. The 225 /* Don't poll if timeout is -1, it hurts performance. The
231 * caution above about interrupts isn't relevant on Windows 226 * caution above about interrupts isn't relevant on Windows
@@ -233,15 +228,14 @@ shell_builtin_read(struct builtin_read_params *params)
233 */ 228 */
234 if (timeout >= 0) 229 if (timeout >= 0)
235#endif 230#endif
236 if (poll(pfd, 1, timeout) <= 0) { 231 /* test bb_got_signal, then poll(), atomically wrt signals */
237 /* timed out, or EINTR */ 232 if (check_got_signal_and_poll(pfd, timeout) <= 0) {
233 /* timed out, or some error */
238 err = errno; 234 err = errno;
239#if ENABLE_PLATFORM_MINGW32 235 if (!err) { /* timed out */
240 if (!err) {
241 retval = (const char *)(uintptr_t)2; 236 retval = (const char *)(uintptr_t)2;
242 break; 237 break;
243 } 238 }
244#endif
245 retval = (const char *)(uintptr_t)1; 239 retval = (const char *)(uintptr_t)1;
246 goto ret; 240 goto ret;
247 } 241 }