diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 13:19:57 +1000 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 13:19:57 +1000 |
commit | ec71cb6575290eb6ad716e4f620db445d8e1bcd3 (patch) | |
tree | 219a5dba000e0ad98ff563bc6f7d45d274d3a178 /shell | |
parent | b5139d7cd8982d9b683cb1babf0bd759076aaab0 (diff) | |
parent | 6814cbc9288601840aedb372e2bd84dab76ffa43 (diff) | |
download | busybox-w32-ec71cb6575290eb6ad716e4f620db445d8e1bcd3.tar.gz busybox-w32-ec71cb6575290eb6ad716e4f620db445d8e1bcd3.tar.bz2 busybox-w32-ec71cb6575290eb6ad716e4f620db445d8e1bcd3.zip |
Merge branch 'origin/master' (early part)
Diffstat (limited to 'shell')
-rw-r--r-- | shell/Config.src | 59 | ||||
-rw-r--r-- | shell/Kbuild.src | 1 | ||||
-rw-r--r-- | shell/ash.c | 87 | ||||
-rwxr-xr-x[-rw-r--r--] | shell/ash_test/ash-redir/redir9.tests | 0 | ||||
-rw-r--r-- | shell/ash_test/ash-signals/signal7.right | 1 | ||||
-rwxr-xr-x | shell/ash_test/ash-signals/signal7.tests | 18 | ||||
-rw-r--r-- | shell/ash_test/ash-vars/var_bash3.right | 40 | ||||
-rwxr-xr-x | shell/ash_test/ash-vars/var_bash3.tests | 47 | ||||
-rw-r--r-- | shell/ash_test/ash-vars/var_bash4.right | 4 | ||||
-rwxr-xr-x | shell/ash_test/ash-vars/var_bash4.tests | 6 | ||||
-rw-r--r-- | shell/cttyhack.c | 66 | ||||
-rw-r--r-- | shell/hush.c | 19 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/break1.tests | 1 | ||||
-rw-r--r-- | shell/hush_test/hush-trap/signal7.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-trap/signal7.tests | 18 | ||||
-rw-r--r-- | shell/shell_common.c | 7 |
16 files changed, 235 insertions, 140 deletions
diff --git a/shell/Config.src b/shell/Config.src index 6389d943a..c9c2439e7 100644 --- a/shell/Config.src +++ b/shell/Config.src | |||
@@ -62,29 +62,6 @@ config FEATURE_BASH_IS_NONE | |||
62 | endchoice | 62 | endchoice |
63 | 63 | ||
64 | 64 | ||
65 | config LASH | ||
66 | bool "lash (deprecated: aliased to hush)" | ||
67 | default n | ||
68 | select HUSH | ||
69 | help | ||
70 | lash is deprecated and will be removed, please migrate to hush. | ||
71 | |||
72 | config MSH | ||
73 | bool "msh (deprecated: please use hush)" | ||
74 | default n | ||
75 | select HUSH | ||
76 | help | ||
77 | msh is deprecated and will be removed, please migrate to hush. | ||
78 | If there is a feature msh has but hush does not, please let us know. | ||
79 | |||
80 | # The minix shell (adds just 30k) is quite complete and handles things | ||
81 | # like for/do/done, case/esac and all the things you expect a Bourne | ||
82 | # shell to do. It is not always pedantically correct about Bourne | ||
83 | # shell grammar (try running the shell testscript "tests/sh.testcases" | ||
84 | # on it and compare vs bash) but for most things it works quite well. | ||
85 | # It uses only vfork, so it can be used on uClinux systems. | ||
86 | |||
87 | |||
88 | config SH_MATH_SUPPORT | 65 | config SH_MATH_SUPPORT |
89 | bool "POSIX math support" | 66 | bool "POSIX math support" |
90 | default y | 67 | default y |
@@ -158,40 +135,4 @@ config FEATURE_SH_NOFORK | |||
158 | 135 | ||
159 | This feature is relatively new. Use with care. | 136 | This feature is relatively new. Use with care. |
160 | 137 | ||
161 | config CTTYHACK | ||
162 | bool "cttyhack" | ||
163 | default y | ||
164 | help | ||
165 | One common problem reported on the mailing list is "can't access tty; | ||
166 | job control turned off" error message which typically appears when | ||
167 | one tries to use shell with stdin/stdout opened to /dev/console. | ||
168 | This device is special - it cannot be a controlling tty. | ||
169 | |||
170 | Proper solution is to use correct device instead of /dev/console. | ||
171 | |||
172 | cttyhack provides "quick and dirty" solution to this problem. | ||
173 | It analyzes stdin with various ioctls, trying to determine whether | ||
174 | it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). | ||
175 | If it detects one, it closes stdin/out/err and reopens that device. | ||
176 | Then it executes given program. Opening the device will make | ||
177 | that device a controlling tty. This may require cttyhack | ||
178 | to be a session leader. | ||
179 | |||
180 | Example for /etc/inittab (for busybox init): | ||
181 | |||
182 | ::respawn:/bin/cttyhack /bin/sh | ||
183 | |||
184 | Starting an interactive shell from boot shell script: | ||
185 | |||
186 | setsid cttyhack sh | ||
187 | |||
188 | Giving controlling tty to shell running with PID 1: | ||
189 | |||
190 | # exec cttyhack sh | ||
191 | |||
192 | Without cttyhack, you need to know exact tty name, | ||
193 | and do something like this: | ||
194 | |||
195 | # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1' | ||
196 | |||
197 | endmenu | 138 | endmenu |
diff --git a/shell/Kbuild.src b/shell/Kbuild.src index bce99240f..a669bdfb0 100644 --- a/shell/Kbuild.src +++ b/shell/Kbuild.src | |||
@@ -8,5 +8,4 @@ lib-y:= | |||
8 | 8 | ||
9 | INSERT | 9 | INSERT |
10 | 10 | ||
11 | lib-$(CONFIG_CTTYHACK) += cttyhack.o | ||
12 | lib-$(CONFIG_SH_MATH_SUPPORT) += math.o | 11 | lib-$(CONFIG_SH_MATH_SUPPORT) += math.o |
diff --git a/shell/ash.c b/shell/ash.c index 2cee0c42f..308cc0273 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -193,6 +193,7 @@ | |||
193 | //config: "PS#" may contain volatile content, such as backquote commands. | 193 | //config: "PS#" may contain volatile content, such as backquote commands. |
194 | //config: This option recreates the prompt string from the environment | 194 | //config: This option recreates the prompt string from the environment |
195 | //config: variable each time it is displayed. | 195 | //config: variable each time it is displayed. |
196 | //config: | ||
196 | 197 | ||
197 | //usage:#define ash_trivial_usage NOUSAGE_STR | 198 | //usage:#define ash_trivial_usage NOUSAGE_STR |
198 | //usage:#define ash_full_usage "" | 199 | //usage:#define ash_full_usage "" |
@@ -4844,6 +4845,7 @@ clear_traps(void) | |||
4844 | INT_ON; | 4845 | INT_ON; |
4845 | } | 4846 | } |
4846 | } | 4847 | } |
4848 | may_have_traps = 0; | ||
4847 | } | 4849 | } |
4848 | 4850 | ||
4849 | /* Lives far away from here, needed for forkchild */ | 4851 | /* Lives far away from here, needed for forkchild */ |
@@ -6615,13 +6617,14 @@ parse_sub_pattern(char *arg, int inquotes) | |||
6615 | #endif /* ENABLE_ASH_BASH_COMPAT */ | 6617 | #endif /* ENABLE_ASH_BASH_COMPAT */ |
6616 | 6618 | ||
6617 | static const char * | 6619 | static const char * |
6618 | subevalvar(char *p, char *str, int strloc, int subtype, | 6620 | subevalvar(char *p, char *varname, int strloc, int subtype, |
6619 | int startloc, int varflags, int quotes, struct strlist *var_str_list) | 6621 | int startloc, int varflags, int quotes, struct strlist *var_str_list) |
6620 | { | 6622 | { |
6621 | struct nodelist *saveargbackq = argbackq; | 6623 | struct nodelist *saveargbackq = argbackq; |
6622 | char *startp; | 6624 | char *startp; |
6623 | char *loc; | 6625 | char *loc; |
6624 | char *rmesc, *rmescend; | 6626 | char *rmesc, *rmescend; |
6627 | char *str; | ||
6625 | IF_ASH_BASH_COMPAT(const char *repl = NULL;) | 6628 | IF_ASH_BASH_COMPAT(const char *repl = NULL;) |
6626 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) | 6629 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) |
6627 | int saveherefd = herefd; | 6630 | int saveherefd = herefd; |
@@ -6629,6 +6632,9 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6629 | int zero; | 6632 | int zero; |
6630 | char *(*scan)(char*, char*, char*, char*, int, int); | 6633 | char *(*scan)(char*, char*, char*, char*, int, int); |
6631 | 6634 | ||
6635 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d", | ||
6636 | // p, varname, strloc, subtype, startloc, varflags, quotes); | ||
6637 | |||
6632 | herefd = -1; | 6638 | herefd = -1; |
6633 | argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, | 6639 | argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, |
6634 | var_str_list); | 6640 | var_str_list); |
@@ -6639,11 +6645,15 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6639 | 6645 | ||
6640 | switch (subtype) { | 6646 | switch (subtype) { |
6641 | case VSASSIGN: | 6647 | case VSASSIGN: |
6642 | setvar(str, startp, 0); | 6648 | setvar(varname, startp, 0); |
6643 | amount = startp - expdest; | 6649 | amount = startp - expdest; |
6644 | STADJUST(amount, expdest); | 6650 | STADJUST(amount, expdest); |
6645 | return startp; | 6651 | return startp; |
6646 | 6652 | ||
6653 | case VSQUESTION: | ||
6654 | varunset(p, varname, startp, varflags); | ||
6655 | /* NOTREACHED */ | ||
6656 | |||
6647 | #if ENABLE_ASH_BASH_COMPAT | 6657 | #if ENABLE_ASH_BASH_COMPAT |
6648 | case VSSUBSTR: | 6658 | case VSSUBSTR: |
6649 | loc = str = stackblock() + strloc; | 6659 | loc = str = stackblock() + strloc; |
@@ -6704,11 +6714,8 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6704 | STADJUST(amount, expdest); | 6714 | STADJUST(amount, expdest); |
6705 | return loc; | 6715 | return loc; |
6706 | #endif | 6716 | #endif |
6707 | |||
6708 | case VSQUESTION: | ||
6709 | varunset(p, str, startp, varflags); | ||
6710 | /* NOTREACHED */ | ||
6711 | } | 6717 | } |
6718 | |||
6712 | resetloc = expdest - (char *)stackblock(); | 6719 | resetloc = expdest - (char *)stackblock(); |
6713 | 6720 | ||
6714 | /* We'll comeback here if we grow the stack while handling | 6721 | /* We'll comeback here if we grow the stack while handling |
@@ -6742,13 +6749,14 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6742 | 6749 | ||
6743 | if (!repl) { | 6750 | if (!repl) { |
6744 | repl = parse_sub_pattern(str, varflags & VSQUOTE); | 6751 | repl = parse_sub_pattern(str, varflags & VSQUOTE); |
6752 | //bb_error_msg("repl:'%s'", repl); | ||
6745 | if (!repl) | 6753 | if (!repl) |
6746 | repl = nullstr; | 6754 | repl = nullstr; |
6747 | } | 6755 | } |
6748 | 6756 | ||
6749 | /* If there's no pattern to match, return the expansion unmolested */ | 6757 | /* If there's no pattern to match, return the expansion unmolested */ |
6750 | if (str[0] == '\0') | 6758 | if (str[0] == '\0') |
6751 | return 0; | 6759 | return NULL; |
6752 | 6760 | ||
6753 | len = 0; | 6761 | len = 0; |
6754 | idx = startp; | 6762 | idx = startp; |
@@ -6756,6 +6764,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6756 | while (idx < end) { | 6764 | while (idx < end) { |
6757 | try_to_match: | 6765 | try_to_match: |
6758 | loc = scanright(idx, rmesc, rmescend, str, quotes, 1); | 6766 | loc = scanright(idx, rmesc, rmescend, str, quotes, 1); |
6767 | //bb_error_msg("scanright('%s'):'%s'", str, loc); | ||
6759 | if (!loc) { | 6768 | if (!loc) { |
6760 | /* No match, advance */ | 6769 | /* No match, advance */ |
6761 | char *restart_detect = stackblock(); | 6770 | char *restart_detect = stackblock(); |
@@ -6794,6 +6803,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6794 | idx = loc; | 6803 | idx = loc; |
6795 | } | 6804 | } |
6796 | 6805 | ||
6806 | //bb_error_msg("repl:'%s'", repl); | ||
6797 | for (loc = (char*)repl; *loc; loc++) { | 6807 | for (loc = (char*)repl; *loc; loc++) { |
6798 | char *restart_detect = stackblock(); | 6808 | char *restart_detect = stackblock(); |
6799 | if (quotes && *loc == '\\') { | 6809 | if (quotes && *loc == '\\') { |
@@ -6829,6 +6839,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |||
6829 | STPUTC('\0', expdest); | 6839 | STPUTC('\0', expdest); |
6830 | startp = (char *)stackblock() + startloc; | 6840 | startp = (char *)stackblock() + startloc; |
6831 | memmove(startp, (char *)stackblock() + workloc, len + 1); | 6841 | memmove(startp, (char *)stackblock() + workloc, len + 1); |
6842 | //bb_error_msg("startp:'%s'", startp); | ||
6832 | amount = expdest - (startp + len); | 6843 | amount = expdest - (startp + len); |
6833 | STADJUST(-amount, expdest); | 6844 | STADJUST(-amount, expdest); |
6834 | return startp; | 6845 | return startp; |
@@ -7129,7 +7140,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7129 | */ | 7140 | */ |
7130 | STPUTC('\0', expdest); | 7141 | STPUTC('\0', expdest); |
7131 | patloc = expdest - (char *)stackblock(); | 7142 | patloc = expdest - (char *)stackblock(); |
7132 | if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype, | 7143 | if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, |
7133 | startloc, varflags, | 7144 | startloc, varflags, |
7134 | //TODO: | EXP_REDIR too? All other such places do it too | 7145 | //TODO: | EXP_REDIR too? All other such places do it too |
7135 | /* quotes: */ flags & (EXP_FULL | EXP_CASE), | 7146 | /* quotes: */ flags & (EXP_FULL | EXP_CASE), |
@@ -11577,8 +11588,11 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11577 | USTPUTC('\\', out); | 11588 | USTPUTC('\\', out); |
11578 | } | 11589 | } |
11579 | #endif | 11590 | #endif |
11580 | if (dblquote && c != '\\' | 11591 | /* Backslash is retained if we are in "str" and next char isn't special */ |
11581 | && c != '`' && c != '$' | 11592 | if (dblquote |
11593 | && c != '\\' | ||
11594 | && c != '`' | ||
11595 | && c != '$' | ||
11582 | && (c != '"' || eofmark != NULL) | 11596 | && (c != '"' || eofmark != NULL) |
11583 | ) { | 11597 | ) { |
11584 | USTPUTC(CTLESC, out); | 11598 | USTPUTC(CTLESC, out); |
@@ -11650,7 +11664,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11650 | } else { | 11664 | } else { |
11651 | /* | 11665 | /* |
11652 | * unbalanced parens | 11666 | * unbalanced parens |
11653 | * (don't 2nd guess - no error) | 11667 | * (don't 2nd guess - no error) |
11654 | */ | 11668 | */ |
11655 | pungetc(); | 11669 | pungetc(); |
11656 | USTPUTC(')', out); | 11670 | USTPUTC(')', out); |
@@ -11678,7 +11692,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11678 | } | 11692 | } |
11679 | IF_ASH_ALIAS(if (c != PEOA)) | 11693 | IF_ASH_ALIAS(if (c != PEOA)) |
11680 | USTPUTC(c, out); | 11694 | USTPUTC(c, out); |
11681 | |||
11682 | } | 11695 | } |
11683 | c = pgetc_fast(); | 11696 | c = pgetc_fast(); |
11684 | } /* for (;;) */ | 11697 | } /* for (;;) */ |
@@ -11844,8 +11857,6 @@ parsesub: { | |||
11844 | unsigned char subtype; | 11857 | unsigned char subtype; |
11845 | int typeloc; | 11858 | int typeloc; |
11846 | int flags; | 11859 | int flags; |
11847 | char *p; | ||
11848 | static const char types[] ALIGN1 = "}-+?="; | ||
11849 | 11860 | ||
11850 | c = pgetc(); | 11861 | c = pgetc(); |
11851 | if (c > 255 /* PEOA or PEOF */ | 11862 | if (c > 255 /* PEOA or PEOF */ |
@@ -11858,7 +11869,8 @@ parsesub: { | |||
11858 | #endif | 11869 | #endif |
11859 | USTPUTC('$', out); | 11870 | USTPUTC('$', out); |
11860 | pungetc(); | 11871 | pungetc(); |
11861 | } else if (c == '(') { /* $(command) or $((arith)) */ | 11872 | } else if (c == '(') { |
11873 | /* $(command) or $((arith)) */ | ||
11862 | if (pgetc() == '(') { | 11874 | if (pgetc() == '(') { |
11863 | #if ENABLE_SH_MATH_SUPPORT | 11875 | #if ENABLE_SH_MATH_SUPPORT |
11864 | PARSEARITH(); | 11876 | PARSEARITH(); |
@@ -11870,6 +11882,7 @@ parsesub: { | |||
11870 | PARSEBACKQNEW(); | 11882 | PARSEBACKQNEW(); |
11871 | } | 11883 | } |
11872 | } else { | 11884 | } else { |
11885 | /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */ | ||
11873 | USTPUTC(CTLVAR, out); | 11886 | USTPUTC(CTLVAR, out); |
11874 | typeloc = out - (char *)stackblock(); | 11887 | typeloc = out - (char *)stackblock(); |
11875 | USTPUTC(VSNORMAL, out); | 11888 | USTPUTC(VSNORMAL, out); |
@@ -11879,76 +11892,85 @@ parsesub: { | |||
11879 | if (c == '#') { | 11892 | if (c == '#') { |
11880 | c = pgetc(); | 11893 | c = pgetc(); |
11881 | if (c == '}') | 11894 | if (c == '}') |
11882 | c = '#'; | 11895 | c = '#'; /* ${#} - same as $# */ |
11883 | else | 11896 | else |
11884 | subtype = VSLENGTH; | 11897 | subtype = VSLENGTH; /* ${#VAR} */ |
11885 | } else | 11898 | } else { |
11886 | subtype = 0; | 11899 | subtype = 0; |
11900 | } | ||
11887 | } | 11901 | } |
11888 | if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { | 11902 | if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { |
11903 | /* $[{[#]]NAME[}] */ | ||
11889 | do { | 11904 | do { |
11890 | STPUTC(c, out); | 11905 | STPUTC(c, out); |
11891 | c = pgetc(); | 11906 | c = pgetc(); |
11892 | } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); | 11907 | } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); |
11893 | } else if (isdigit(c)) { | 11908 | } else if (isdigit(c)) { |
11909 | /* $[{[#]]NUM[}] */ | ||
11894 | do { | 11910 | do { |
11895 | STPUTC(c, out); | 11911 | STPUTC(c, out); |
11896 | c = pgetc(); | 11912 | c = pgetc(); |
11897 | } while (isdigit(c)); | 11913 | } while (isdigit(c)); |
11898 | } else if (is_special(c)) { | 11914 | } else if (is_special(c)) { |
11915 | /* $[{[#]]<specialchar>[}] */ | ||
11899 | USTPUTC(c, out); | 11916 | USTPUTC(c, out); |
11900 | c = pgetc(); | 11917 | c = pgetc(); |
11901 | } else { | 11918 | } else { |
11902 | badsub: | 11919 | badsub: |
11903 | raise_error_syntax("bad substitution"); | 11920 | raise_error_syntax("bad substitution"); |
11904 | } | 11921 | } |
11905 | if (c != '}' && subtype == VSLENGTH) | 11922 | if (c != '}' && subtype == VSLENGTH) { |
11923 | /* ${#VAR didn't end with } */ | ||
11906 | goto badsub; | 11924 | goto badsub; |
11925 | } | ||
11907 | 11926 | ||
11908 | STPUTC('=', out); | 11927 | STPUTC('=', out); |
11909 | flags = 0; | 11928 | flags = 0; |
11910 | if (subtype == 0) { | 11929 | if (subtype == 0) { |
11930 | /* ${VAR...} but not $VAR or ${#VAR} */ | ||
11931 | /* c == first char after VAR */ | ||
11911 | switch (c) { | 11932 | switch (c) { |
11912 | case ':': | 11933 | case ':': |
11913 | c = pgetc(); | 11934 | c = pgetc(); |
11914 | #if ENABLE_ASH_BASH_COMPAT | 11935 | #if ENABLE_ASH_BASH_COMPAT |
11915 | if (c == ':' || c == '$' || isdigit(c)) { | 11936 | if (c == ':' || c == '$' || isdigit(c)) { |
11916 | pungetc(); | ||
11917 | subtype = VSSUBSTR; | 11937 | subtype = VSSUBSTR; |
11918 | break; | 11938 | pungetc(); |
11939 | break; /* "goto do_pungetc" is bigger (!) */ | ||
11919 | } | 11940 | } |
11920 | #endif | 11941 | #endif |
11921 | flags = VSNUL; | 11942 | flags = VSNUL; |
11922 | /*FALLTHROUGH*/ | 11943 | /*FALLTHROUGH*/ |
11923 | default: | 11944 | default: { |
11924 | p = strchr(types, c); | 11945 | static const char types[] ALIGN1 = "}-+?="; |
11946 | const char *p = strchr(types, c); | ||
11925 | if (p == NULL) | 11947 | if (p == NULL) |
11926 | goto badsub; | 11948 | goto badsub; |
11927 | subtype = p - types + VSNORMAL; | 11949 | subtype = p - types + VSNORMAL; |
11928 | break; | 11950 | break; |
11951 | } | ||
11929 | case '%': | 11952 | case '%': |
11930 | case '#': { | 11953 | case '#': { |
11931 | int cc = c; | 11954 | int cc = c; |
11932 | subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; | 11955 | subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); |
11933 | c = pgetc(); | 11956 | c = pgetc(); |
11934 | if (c == cc) | 11957 | if (c != cc) |
11935 | subtype++; | 11958 | goto do_pungetc; |
11936 | else | 11959 | subtype++; |
11937 | pungetc(); | ||
11938 | break; | 11960 | break; |
11939 | } | 11961 | } |
11940 | #if ENABLE_ASH_BASH_COMPAT | 11962 | #if ENABLE_ASH_BASH_COMPAT |
11941 | case '/': | 11963 | case '/': |
11942 | subtype = VSREPLACE; | 11964 | subtype = VSREPLACE; |
11943 | c = pgetc(); | 11965 | c = pgetc(); |
11944 | if (c == '/') | 11966 | if (c != '/') |
11945 | subtype++; /* VSREPLACEALL */ | 11967 | goto do_pungetc; |
11946 | else | 11968 | subtype++; /* VSREPLACEALL */ |
11947 | pungetc(); | ||
11948 | break; | 11969 | break; |
11949 | #endif | 11970 | #endif |
11950 | } | 11971 | } |
11951 | } else { | 11972 | } else { |
11973 | do_pungetc: | ||
11952 | pungetc(); | 11974 | pungetc(); |
11953 | } | 11975 | } |
11954 | if (dblquote || arinest) | 11976 | if (dblquote || arinest) |
@@ -12518,7 +12540,6 @@ evalcmd(int argc UNUSED_PARAM, char **argv) | |||
12518 | p = grabstackstr(concat); | 12540 | p = grabstackstr(concat); |
12519 | } | 12541 | } |
12520 | evalstring(p, ~SKIPEVAL); | 12542 | evalstring(p, ~SKIPEVAL); |
12521 | |||
12522 | } | 12543 | } |
12523 | return exitstatus; | 12544 | return exitstatus; |
12524 | } | 12545 | } |
diff --git a/shell/ash_test/ash-redir/redir9.tests b/shell/ash_test/ash-redir/redir9.tests index 8befa611c..8befa611c 100644..100755 --- a/shell/ash_test/ash-redir/redir9.tests +++ b/shell/ash_test/ash-redir/redir9.tests | |||
diff --git a/shell/ash_test/ash-signals/signal7.right b/shell/ash_test/ash-signals/signal7.right new file mode 100644 index 000000000..ba7453e42 --- /dev/null +++ b/shell/ash_test/ash-signals/signal7.right | |||
@@ -0,0 +1 @@ | |||
Bug detected: 0 | |||
diff --git a/shell/ash_test/ash-signals/signal7.tests b/shell/ash_test/ash-signals/signal7.tests new file mode 100755 index 000000000..c2b1381f9 --- /dev/null +++ b/shell/ash_test/ash-signals/signal7.tests | |||
@@ -0,0 +1,18 @@ | |||
1 | bug() { | ||
2 | trap : exit | ||
3 | # Bug was causing sh to be run in subshell, | ||
4 | # as if this line is replaced with (sh -c ...; exit $?) & | ||
5 | # here: | ||
6 | sh -c 'echo REAL_CHILD=$$' & | ||
7 | echo PARENTS_IDEA_OF_CHILD=$! | ||
8 | wait # make sure bkgd shell completes | ||
9 | } | ||
10 | |||
11 | bug | { | ||
12 | while read varval; do | ||
13 | eval $varval | ||
14 | done | ||
15 | test x"$REAL_CHILD" != x"" \ | ||
16 | && test x"$REAL_CHILD" = x"$PARENTS_IDEA_OF_CHILD" | ||
17 | echo "Bug detected: $?" | ||
18 | } | ||
diff --git a/shell/ash_test/ash-vars/var_bash3.right b/shell/ash_test/ash-vars/var_bash3.right index f7f14791e..a97c850ea 100644 --- a/shell/ash_test/ash-vars/var_bash3.right +++ b/shell/ash_test/ash-vars/var_bash3.right | |||
@@ -1,20 +1,20 @@ | |||
1 | a041#c | 1 | 1 a041#c |
2 | a041#c | 2 | 2 a041#c |
3 | a\041#c | 3 | 3 a\041#c |
4 | a\041#c | 4 | 4 a\041#c |
5 | a\041#c | 5 | 5 a\041#c |
6 | a\041#c | 6 | 6 a\041#c |
7 | a\041#c | 7 | 7 a\041#c |
8 | a\041#c | 8 | 8 a\041#c |
9 | a\041#c | 9 | 9 a\041#c |
10 | a\c | 10 | 10 a\c |
11 | a\c | 11 | 11 a\c |
12 | a\c | 12 | 12 a\c |
13 | a\\c | 13 | 13 a\\c |
14 | a\\c | 14 | 14 a\\c |
15 | a\\c | 15 | 15 a\\c |
16 | a\tc | 16 | 16 a\tc |
17 | a\tc | 17 | 17 a\tc |
18 | a\tc | 18 | 18 a\tc |
19 | atc | 19 | 19 atc |
20 | a\tc | 20 | 20 a\tc |
diff --git a/shell/ash_test/ash-vars/var_bash3.tests b/shell/ash_test/ash-vars/var_bash3.tests index b9050279e..eca3318e2 100755 --- a/shell/ash_test/ash-vars/var_bash3.tests +++ b/shell/ash_test/ash-vars/var_bash3.tests | |||
@@ -1,41 +1,48 @@ | |||
1 | a='abc' | 1 | a='abc' |
2 | r=${a//b/\041#} | 2 | r=${a//b/\041#} |
3 | echo $r | 3 | echo 1 $r |
4 | echo ${a//b/\041#} | 4 | echo 2 ${a//b/\041#} |
5 | echo "${a//b/\041#}" | 5 | echo 3 "${a//b/\041#}" |
6 | # --- var_bash3.xx | ||
7 | # +++ var_bash3.right | ||
8 | # -1 a\041#c | ||
9 | # +1 a041#c | ||
10 | # 2 a041#c | ||
11 | # -3 a041#c | ||
12 | # +3 a\041#c | ||
6 | 13 | ||
7 | a='abc' | 14 | a='abc' |
8 | r=${a//b/\\041#} | 15 | r=${a//b/\\041#} |
9 | echo $r | 16 | echo 4 $r |
10 | echo ${a//b/\\041#} | 17 | echo 5 ${a//b/\\041#} |
11 | echo "${a//b/\\041#}" | 18 | echo 6 "${a//b/\\041#}" |
12 | 19 | ||
13 | a='abc' | 20 | a='abc' |
14 | b='\041#' | 21 | b='\041#' |
15 | r=${a//b/$b} | 22 | r=${a//b/$b} |
16 | echo $r | 23 | echo 7 $r |
17 | echo ${a//b/$b} | 24 | echo 8 ${a//b/$b} |
18 | echo "${a//b/$b}" | 25 | echo 9 "${a//b/$b}" |
19 | 26 | ||
20 | a='abc' | 27 | a='abc' |
21 | b='\' | 28 | b='\' |
22 | r="${a//b/$b}" | 29 | r="${a//b/$b}" |
23 | echo $r | 30 | echo 10 $r |
24 | echo ${a//b/$b} | 31 | echo 11 ${a//b/$b} |
25 | echo "${a//b/$b}" | 32 | echo 12 "${a//b/$b}" |
26 | 33 | ||
27 | a='abc' | 34 | a='abc' |
28 | b='\\' | 35 | b='\\' |
29 | r="${a//b/$b}" | 36 | r="${a//b/$b}" |
30 | echo $r | 37 | echo 13 $r |
31 | echo ${a//b/$b} | 38 | echo 14 ${a//b/$b} |
32 | echo "${a//b/$b}" | 39 | echo 15 "${a//b/$b}" |
33 | 40 | ||
34 | a='abc' | 41 | a='abc' |
35 | b='\t' | 42 | b='\t' |
36 | r="${a//b/$b}" | 43 | r="${a//b/$b}" |
37 | echo $r | 44 | echo 16 $r |
38 | echo ${a//b/$b} | 45 | echo 17 ${a//b/$b} |
39 | echo "${a//b/$b}" | 46 | echo 18 "${a//b/$b}" |
40 | echo ${a//b/\t} | 47 | echo 19 ${a//b/\t} |
41 | echo "${a//b/\t}" | 48 | echo 20 "${a//b/\t}" |
diff --git a/shell/ash_test/ash-vars/var_bash4.right b/shell/ash_test/ash-vars/var_bash4.right new file mode 100644 index 000000000..fc3a9e41c --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash4.right | |||
@@ -0,0 +1,4 @@ | |||
1 | In assignment: a*b-backslashstar- | ||
2 | Unquoted: a*b-backslashstar- | ||
3 | Quoted: a*b-backslashstar- | ||
4 | Done: 0 | ||
diff --git a/shell/ash_test/ash-vars/var_bash4.tests b/shell/ash_test/ash-vars/var_bash4.tests new file mode 100755 index 000000000..3b323c576 --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash4.tests | |||
@@ -0,0 +1,6 @@ | |||
1 | FOO='a*b\*c' | ||
2 | BAR=${FOO//\\*/-backslashstar-} | ||
3 | echo In assignment: "$BAR" | ||
4 | echo Unquoted: ${FOO//\\*/-backslashstar-} | ||
5 | echo Quoted: "${FOO//\\*/-backslashstar-}" | ||
6 | echo Done: $? | ||
diff --git a/shell/cttyhack.c b/shell/cttyhack.c index 67736ad62..7a5e1ffd2 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c | |||
@@ -6,6 +6,62 @@ | |||
6 | */ | 6 | */ |
7 | #include "libbb.h" | 7 | #include "libbb.h" |
8 | 8 | ||
9 | //applet:IF_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_DROP)) | ||
10 | |||
11 | //kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o | ||
12 | |||
13 | //config:config CTTYHACK | ||
14 | //config: bool "cttyhack" | ||
15 | //config: default y | ||
16 | //config: help | ||
17 | //config: One common problem reported on the mailing list is "can't access tty; | ||
18 | //config: job control turned off" error message which typically appears when | ||
19 | //config: one tries to use shell with stdin/stdout opened to /dev/console. | ||
20 | //config: This device is special - it cannot be a controlling tty. | ||
21 | //config: | ||
22 | //config: Proper solution is to use correct device instead of /dev/console. | ||
23 | //config: | ||
24 | //config: cttyhack provides "quick and dirty" solution to this problem. | ||
25 | //config: It analyzes stdin with various ioctls, trying to determine whether | ||
26 | //config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). | ||
27 | //config: If it detects one, it closes stdin/out/err and reopens that device. | ||
28 | //config: Then it executes given program. Opening the device will make | ||
29 | //config: that device a controlling tty. This may require cttyhack | ||
30 | //config: to be a session leader. | ||
31 | //config: | ||
32 | //config: Example for /etc/inittab (for busybox init): | ||
33 | //config: | ||
34 | //config: ::respawn:/bin/cttyhack /bin/sh | ||
35 | //config: | ||
36 | //config: Starting an interactive shell from boot shell script: | ||
37 | //config: | ||
38 | //config: setsid cttyhack sh | ||
39 | //config: | ||
40 | //config: Giving controlling tty to shell running with PID 1: | ||
41 | //config: | ||
42 | //config: # exec cttyhack sh | ||
43 | //config: | ||
44 | //config: Without cttyhack, you need to know exact tty name, | ||
45 | //config: and do something like this: | ||
46 | //config: | ||
47 | //config: # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1' | ||
48 | //config: | ||
49 | |||
50 | //usage:#define cttyhack_trivial_usage | ||
51 | //usage: "PROG ARGS" | ||
52 | //usage:#define cttyhack_full_usage "\n\n" | ||
53 | //usage: "Give PROG a controlling tty if possible." | ||
54 | //usage: "\nExample for /etc/inittab (for busybox init):" | ||
55 | //usage: "\n ::respawn:/bin/cttyhack /bin/sh" | ||
56 | //usage: "\nGiving controlling tty to shell running with PID 1:" | ||
57 | //usage: "\n $ exec cttyhack sh" | ||
58 | //usage: "\nStarting interactive shell from boot shell script:" | ||
59 | //usage: "\n setsid cttyhack sh" | ||
60 | |||
61 | #if !defined(__linux__) && !defined(TIOCGSERIAL) && !ENABLE_WERROR | ||
62 | # warning cttyhack will not be able to detect a controlling tty on this system | ||
63 | #endif | ||
64 | |||
9 | /* From <linux/vt.h> */ | 65 | /* From <linux/vt.h> */ |
10 | struct vt_stat { | 66 | struct vt_stat { |
11 | unsigned short v_active; /* active vt */ | 67 | unsigned short v_active; /* active vt */ |
@@ -59,13 +115,19 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) | |||
59 | close(fd); | 115 | close(fd); |
60 | } else { | 116 | } else { |
61 | /* We don't have ctty (or don't have "/dev/tty" node...) */ | 117 | /* We don't have ctty (or don't have "/dev/tty" node...) */ |
62 | if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { | 118 | if (0) {} |
119 | #ifdef TIOCGSERIAL | ||
120 | else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { | ||
63 | /* this is a serial console */ | 121 | /* this is a serial console */ |
64 | sprintf(console + 8, "S%d", u.sr.line); | 122 | sprintf(console + 8, "S%d", u.sr.line); |
65 | } else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { | 123 | } |
124 | #endif | ||
125 | #ifdef __linux__ | ||
126 | else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { | ||
66 | /* this is linux virtual tty */ | 127 | /* this is linux virtual tty */ |
67 | sprintf(console + 8, "S%d" + 1, u.vt.v_active); | 128 | sprintf(console + 8, "S%d" + 1, u.vt.v_active); |
68 | } | 129 | } |
130 | #endif | ||
69 | if (console[8]) { | 131 | if (console[8]) { |
70 | fd = xopen(console, O_RDWR); | 132 | fd = xopen(console, O_RDWR); |
71 | //bb_error_msg("switching to '%s'", console); | 133 | //bb_error_msg("switching to '%s'", console); |
diff --git a/shell/hush.c b/shell/hush.c index 56a3f4b14..0a420f685 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -224,6 +224,20 @@ | |||
224 | //config: This instructs hush to print commands before execution. | 224 | //config: This instructs hush to print commands before execution. |
225 | //config: Adds ~300 bytes. | 225 | //config: Adds ~300 bytes. |
226 | //config: | 226 | //config: |
227 | //config:config LASH | ||
228 | //config: bool "lash (deprecated: aliased to hush)" | ||
229 | //config: default n | ||
230 | //config: select HUSH | ||
231 | //config: help | ||
232 | //config: lash is deprecated and will be removed, please migrate to hush. | ||
233 | //config: | ||
234 | //config:config MSH | ||
235 | //config: bool "msh (deprecated: aliased to hush)" | ||
236 | //config: default n | ||
237 | //config: select HUSH | ||
238 | //config: help | ||
239 | //config: msh is deprecated and will be removed, please migrate to hush. | ||
240 | //config: | ||
227 | 241 | ||
228 | //usage:#define hush_trivial_usage NOUSAGE_STR | 242 | //usage:#define hush_trivial_usage NOUSAGE_STR |
229 | //usage:#define hush_full_usage "" | 243 | //usage:#define hush_full_usage "" |
@@ -4094,8 +4108,6 @@ static void insert_bg_job(struct pipe *pi) | |||
4094 | 4108 | ||
4095 | if (G_interactive_fd) | 4109 | if (G_interactive_fd) |
4096 | printf("[%d] %d %s\n", job->jobid, job->cmds[0].pid, job->cmdtext); | 4110 | printf("[%d] %d %s\n", job->jobid, job->cmds[0].pid, job->cmdtext); |
4097 | /* Last command's pid goes to $! */ | ||
4098 | G.last_bg_pid = job->cmds[job->num_cmds - 1].pid; | ||
4099 | G.last_jobid = job->jobid; | 4111 | G.last_jobid = job->jobid; |
4100 | } | 4112 | } |
4101 | 4113 | ||
@@ -4506,7 +4518,6 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
4506 | #ifdef CMD_SINGLEWORD_NOGLOB_COND | 4518 | #ifdef CMD_SINGLEWORD_NOGLOB_COND |
4507 | else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB_COND) { | 4519 | else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB_COND) { |
4508 | argv_expanded = expand_strvec_to_strvec_singleword_noglob_cond(argv + command->assignment_cnt); | 4520 | argv_expanded = expand_strvec_to_strvec_singleword_noglob_cond(argv + command->assignment_cnt); |
4509 | |||
4510 | } | 4521 | } |
4511 | #endif | 4522 | #endif |
4512 | else { | 4523 | else { |
@@ -5062,6 +5073,8 @@ static int run_list(struct pipe *pi) | |||
5062 | if (G.run_list_level == 1) | 5073 | if (G.run_list_level == 1) |
5063 | insert_bg_job(pi); | 5074 | insert_bg_job(pi); |
5064 | #endif | 5075 | #endif |
5076 | /* Last command's pid goes to $! */ | ||
5077 | G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; | ||
5065 | G.last_exitcode = rcode = EXIT_SUCCESS; | 5078 | G.last_exitcode = rcode = EXIT_SUCCESS; |
5066 | debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); | 5079 | debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); |
5067 | } else { | 5080 | } else { |
diff --git a/shell/hush_test/hush-misc/break1.tests b/shell/hush_test/hush-misc/break1.tests index 912f149c1..3a6b060d9 100755 --- a/shell/hush_test/hush-misc/break1.tests +++ b/shell/hush_test/hush-misc/break1.tests | |||
@@ -1,3 +1,2 @@ | |||
1 | while true; do echo A; break; echo B; done | 1 | while true; do echo A; break; echo B; done |
2 | echo OK:$? | 2 | echo OK:$? |
3 | |||
diff --git a/shell/hush_test/hush-trap/signal7.right b/shell/hush_test/hush-trap/signal7.right new file mode 100644 index 000000000..ba7453e42 --- /dev/null +++ b/shell/hush_test/hush-trap/signal7.right | |||
@@ -0,0 +1 @@ | |||
Bug detected: 0 | |||
diff --git a/shell/hush_test/hush-trap/signal7.tests b/shell/hush_test/hush-trap/signal7.tests new file mode 100755 index 000000000..c2b1381f9 --- /dev/null +++ b/shell/hush_test/hush-trap/signal7.tests | |||
@@ -0,0 +1,18 @@ | |||
1 | bug() { | ||
2 | trap : exit | ||
3 | # Bug was causing sh to be run in subshell, | ||
4 | # as if this line is replaced with (sh -c ...; exit $?) & | ||
5 | # here: | ||
6 | sh -c 'echo REAL_CHILD=$$' & | ||
7 | echo PARENTS_IDEA_OF_CHILD=$! | ||
8 | wait # make sure bkgd shell completes | ||
9 | } | ||
10 | |||
11 | bug | { | ||
12 | while read varval; do | ||
13 | eval $varval | ||
14 | done | ||
15 | test x"$REAL_CHILD" != x"" \ | ||
16 | && test x"$REAL_CHILD" = x"$PARENTS_IDEA_OF_CHILD" | ||
17 | echo "Bug detected: $?" | ||
18 | } | ||
diff --git a/shell/shell_common.c b/shell/shell_common.c index 840e03bff..957d71928 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -435,9 +435,14 @@ shell_builtin_ulimit(char **argv) | |||
435 | val <<= l->factor_shift; | 435 | val <<= l->factor_shift; |
436 | } | 436 | } |
437 | //bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val); | 437 | //bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val); |
438 | /* from man bash: "If neither -H nor -S | ||
439 | * is specified, both the soft and hard | ||
440 | * limits are set. */ | ||
441 | if (!opts) | ||
442 | opts = OPT_hard + OPT_soft; | ||
438 | if (opts & OPT_hard) | 443 | if (opts & OPT_hard) |
439 | limit.rlim_max = val; | 444 | limit.rlim_max = val; |
440 | if ((opts & OPT_soft) || opts == 0) | 445 | if (opts & OPT_soft) |
441 | limit.rlim_cur = val; | 446 | limit.rlim_cur = val; |
442 | //bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max); | 447 | //bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max); |
443 | if (setrlimit(l->cmd, &limit) < 0) { | 448 | if (setrlimit(l->cmd, &limit) < 0) { |