diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/Config.src | 7 | ||||
-rw-r--r-- | shell/ash.c | 39 | ||||
-rw-r--r-- | shell/ash_test/ash-read/read_ifs2.right | 9 | ||||
-rwxr-xr-x | shell/ash_test/ash-read/read_ifs2.tests | 9 | ||||
-rw-r--r-- | shell/ash_test/ash-read/read_t.right | 8 | ||||
-rwxr-xr-x | shell/ash_test/ash-read/read_t.tests | 18 | ||||
-rw-r--r-- | shell/ash_test/printenv.c | 4 | ||||
-rw-r--r-- | shell/ash_test/recho.c | 2 | ||||
-rw-r--r-- | shell/hush.c | 48 | ||||
-rw-r--r-- | shell/hush_test/hush-read/read_t.right | 8 | ||||
-rwxr-xr-x | shell/hush_test/hush-read/read_t.tests | 18 | ||||
-rw-r--r-- | shell/shell_common.c | 48 |
12 files changed, 157 insertions, 61 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 | ||
173 | config FEATURE_SH_EMBEDDED_SCRIPTS | 174 | config 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 3919118f0..0038aa1e9 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -929,6 +929,7 @@ raise_interrupt(void) | |||
929 | raise(SIGINT); | 929 | raise(SIGINT); |
930 | #else | 930 | #else |
931 | fflush_all(); | 931 | fflush_all(); |
932 | kill(-getpid(), SIGINT); | ||
932 | _exit(SIGINT << 24); | 933 | _exit(SIGINT << 24); |
933 | #endif | 934 | #endif |
934 | } | 935 | } |
@@ -4274,7 +4275,7 @@ signal_handler(int signo) | |||
4274 | return; | 4275 | return; |
4275 | } | 4276 | } |
4276 | #if ENABLE_FEATURE_EDITING | 4277 | #if ENABLE_FEATURE_EDITING |
4277 | 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" */ |
4278 | #endif | 4279 | #endif |
4279 | gotsig[signo - 1] = 1; | 4280 | gotsig[signo - 1] = 1; |
4280 | pending_sig = signo; | 4281 | pending_sig = signo; |
@@ -15812,6 +15813,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
15812 | r = shell_builtin_read(¶ms); | 15813 | r = shell_builtin_read(¶ms); |
15813 | INT_ON; | 15814 | INT_ON; |
15814 | 15815 | ||
15816 | #if !ENABLE_PLATFORM_MINGW32 | ||
15815 | if ((uintptr_t)r == 1 && errno == EINTR) { | 15817 | if ((uintptr_t)r == 1 && errno == EINTR) { |
15816 | /* To get SIGCHLD: sleep 1 & read x; echo $x | 15818 | /* To get SIGCHLD: sleep 1 & read x; echo $x |
15817 | * Correct behavior is to not exit "read" | 15819 | * Correct behavior is to not exit "read" |
@@ -15820,8 +15822,15 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
15820 | goto again; | 15822 | goto again; |
15821 | } | 15823 | } |
15822 | 15824 | ||
15823 | #if ENABLE_PLATFORM_MINGW32 | 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; | ||
15829 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
15824 | if ((uintptr_t)r == 2) { | 15830 | if ((uintptr_t)r == 2) { |
15831 | /* Timeout, return 128 + SIGALRM */ | ||
15832 | return 142; | ||
15833 | } else if ((uintptr_t)r == 3) { | ||
15825 | /* ^C pressed, propagate event */ | 15834 | /* ^C pressed, propagate event */ |
15826 | if (trap[SIGINT]) { | 15835 | if (trap[SIGINT]) { |
15827 | write(STDOUT_FILENO, "^C", 2); | 15836 | write(STDOUT_FILENO, "^C", 2); |
@@ -15969,8 +15978,25 @@ exitshell(void) | |||
15969 | char *p; | 15978 | char *p; |
15970 | 15979 | ||
15971 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 15980 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
15972 | 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 | } | ||
15973 | #endif | 15998 | #endif |
15999 | |||
15974 | savestatus = exitstatus; | 16000 | savestatus = exitstatus; |
15975 | TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); | 16001 | TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); |
15976 | if (setjmp(loc.loc)) | 16002 | if (setjmp(loc.loc)) |
@@ -16474,7 +16500,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
16474 | if (hp) | 16500 | if (hp) |
16475 | line_input_state->hist_file = xstrdup(hp); | 16501 | line_input_state->hist_file = xstrdup(hp); |
16476 | # if ENABLE_FEATURE_SH_HISTFILESIZE | 16502 | # if ENABLE_FEATURE_SH_HISTFILESIZE |
16477 | 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 | */ | ||
16478 | line_input_state->max_history = size_from_HISTFILESIZE(hp); | 16509 | line_input_state->max_history = size_from_HISTFILESIZE(hp); |
16479 | # endif | 16510 | # endif |
16480 | } | 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 | ||| | ||
8 | Whitespace 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 @@ | |||
1 | echo "X:Y:Z:" | (IFS=": " read x y; echo "|$x|$y|") | ||
2 | echo "X:Y:Z" | (IFS=": " read x y; echo "|$x|$y|") | ||
3 | echo "X:Y:" | (IFS=": " read x y; echo "|$x|$y|") | ||
4 | echo "X:Y" | (IFS=": " read x y; echo "|$x|$y|") | ||
5 | echo "X:" | (IFS=": " read x y; echo "|$x|$y|") | ||
6 | echo "X" | (IFS=": " read x y; echo "|$x|$y|") | ||
7 | echo "" | (IFS=": " read x y; echo "|$x|$y|") | ||
8 | echo Whitespace should be trimmed too: | ||
9 | echo "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 @@ | |||
31 | extern char **environ; | 31 | extern char **environ; |
32 | 32 | ||
33 | int | 33 | int |
34 | main (argc, argv) | 34 | main (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 | ||
30 | void strprint(); | 30 | void strprint(char *); |
31 | 31 | ||
32 | int main(int argc, char **argv) | 32 | int 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 | ||
2102 | static 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. */ |
2103 | static void hush_exit(int exitcode) | 2105 | static 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 7fb5f8c58..657f0df8f 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -55,7 +55,7 @@ const char* FAST_FUNC | |||
55 | shell_builtin_read(struct builtin_read_params *params) | 55 | shell_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,8 +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 | retval = (const char *)(uintptr_t)1; | 212 | retval = (const char *)(uintptr_t)2; |
213 | goto ret; | 213 | break; |
214 | } | 214 | } |
215 | } | 215 | } |
216 | 216 | ||
@@ -219,15 +219,23 @@ shell_builtin_read(struct builtin_read_params *params) | |||
219 | * regardless of SA_RESTART-ness of that signal! | 219 | * regardless of SA_RESTART-ness of that signal! |
220 | */ | 220 | */ |
221 | errno = 0; | 221 | errno = 0; |
222 | pfd[0].events = POLLIN; | 222 | pfd->events = POLLIN; |
223 | //TODO race with a signal arriving just before the poll! | 223 | |
224 | #if ENABLE_PLATFORM_MINGW32 | 224 | #if ENABLE_PLATFORM_MINGW32 |
225 | /* Don't poll if timeout is -1, it hurts performance. */ | 225 | /* Don't poll if timeout is -1, it hurts performance. The |
226 | * caution above about interrupts isn't relevant on Windows | ||
227 | * where Ctrl-C causes an event, not a signal. | ||
228 | */ | ||
226 | if (timeout >= 0) | 229 | if (timeout >= 0) |
227 | #endif | 230 | #endif |
228 | if (poll(pfd, 1, timeout) <= 0) { | 231 | /* test bb_got_signal, then poll(), atomically wrt signals */ |
229 | /* timed out, or EINTR */ | 232 | if (check_got_signal_and_poll(pfd, timeout) <= 0) { |
233 | /* timed out, or some error */ | ||
230 | err = errno; | 234 | err = errno; |
235 | if (!err) { /* timed out */ | ||
236 | retval = (const char *)(uintptr_t)2; | ||
237 | break; | ||
238 | } | ||
231 | retval = (const char *)(uintptr_t)1; | 239 | retval = (const char *)(uintptr_t)1; |
232 | goto ret; | 240 | goto ret; |
233 | } | 241 | } |
@@ -238,15 +246,18 @@ shell_builtin_read(struct builtin_read_params *params) | |||
238 | key = windows_read_key(fd, NULL, timeout); | 246 | key = windows_read_key(fd, NULL, timeout); |
239 | if (key == 0x03) { | 247 | if (key == 0x03) { |
240 | /* ^C pressed */ | 248 | /* ^C pressed */ |
241 | retval = (const char *)(uintptr_t)2; | 249 | retval = (const char *)(uintptr_t)3; |
242 | goto ret; | 250 | goto ret; |
243 | } | 251 | } |
244 | else if (key == -1 || (key == 0x1a && bufpos == 0)) { | 252 | else if (key == -1) { |
245 | /* timeout or ^Z at start of buffer */ | 253 | /* timeout */ |
254 | retval = (const char *)(uintptr_t)2; | ||
255 | break; | ||
256 | } else if (key == 0x1a && bufpos == 0) { | ||
257 | /* ^Z at start of buffer */ | ||
246 | retval = (const char *)(uintptr_t)1; | 258 | retval = (const char *)(uintptr_t)1; |
247 | goto ret; | 259 | break; |
248 | } | 260 | } else if (key == '\b') { |
249 | else if (key == '\b') { | ||
250 | if (bufpos > 0) { | 261 | if (bufpos > 0) { |
251 | --bufpos; | 262 | --bufpos; |
252 | ++nchars; | 263 | ++nchars; |
@@ -278,7 +289,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
278 | * and exit BS context. | 289 | * and exit BS context. |
279 | * - CR LF not in BS context: replace CR with LF */ | 290 | * - CR LF not in BS context: replace CR with LF */ |
280 | buffer[--bufpos] = c; | 291 | buffer[--bufpos] = c; |
281 | ++nchars; | 292 | nchars += 1 + (backslash == 2); |
282 | } | 293 | } |
283 | } else if (backslash == 2) { | 294 | } else if (backslash == 2) { |
284 | /* We saw BS CR ??, keep escaped CR, exit BS context, | 295 | /* We saw BS CR ??, keep escaped CR, exit BS context, |
@@ -298,6 +309,9 @@ shell_builtin_read(struct builtin_read_params *params) | |||
298 | backslash = 0; | 309 | backslash = 0; |
299 | if (c != '\n') | 310 | if (c != '\n') |
300 | goto put; | 311 | goto put; |
312 | #if ENABLE_PLATFORM_MINGW32 | ||
313 | ++nchars; | ||
314 | #endif | ||
301 | continue; | 315 | continue; |
302 | } | 316 | } |
303 | if (c == '\\') { | 317 | if (c == '\\') { |
@@ -338,7 +352,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
338 | } | 352 | } |
339 | put: | 353 | put: |
340 | bufpos++; | 354 | bufpos++; |
341 | } while (--nchars); | 355 | } while (IF_PLATFORM_MINGW32(backslash ||) --nchars); |
342 | 356 | ||
343 | if (argv[0]) { | 357 | if (argv[0]) { |
344 | /* Remove trailing space $IFS chars */ | 358 | /* Remove trailing space $IFS chars */ |