aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:19:57 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 13:19:57 +1000
commitec71cb6575290eb6ad716e4f620db445d8e1bcd3 (patch)
tree219a5dba000e0ad98ff563bc6f7d45d274d3a178 /shell
parentb5139d7cd8982d9b683cb1babf0bd759076aaab0 (diff)
parent6814cbc9288601840aedb372e2bd84dab76ffa43 (diff)
downloadbusybox-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.src59
-rw-r--r--shell/Kbuild.src1
-rw-r--r--shell/ash.c87
-rwxr-xr-x[-rw-r--r--]shell/ash_test/ash-redir/redir9.tests0
-rw-r--r--shell/ash_test/ash-signals/signal7.right1
-rwxr-xr-xshell/ash_test/ash-signals/signal7.tests18
-rw-r--r--shell/ash_test/ash-vars/var_bash3.right40
-rwxr-xr-xshell/ash_test/ash-vars/var_bash3.tests47
-rw-r--r--shell/ash_test/ash-vars/var_bash4.right4
-rwxr-xr-xshell/ash_test/ash-vars/var_bash4.tests6
-rw-r--r--shell/cttyhack.c66
-rw-r--r--shell/hush.c19
-rwxr-xr-xshell/hush_test/hush-misc/break1.tests1
-rw-r--r--shell/hush_test/hush-trap/signal7.right1
-rwxr-xr-xshell/hush_test/hush-trap/signal7.tests18
-rw-r--r--shell/shell_common.c7
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
62endchoice 62endchoice
63 63
64 64
65config 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
72config 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
88config SH_MATH_SUPPORT 65config 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
161config 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
197endmenu 138endmenu
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
9INSERT 9INSERT
10 10
11lib-$(CONFIG_CTTYHACK) += cttyhack.o
12lib-$(CONFIG_SH_MATH_SUPPORT) += math.o 11lib-$(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
6617static const char * 6619static const char *
6618subevalvar(char *p, char *str, int strloc, int subtype, 6620subevalvar(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 @@
1bug() {
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
11bug | {
12while read varval; do
13 eval $varval
14done
15test x"$REAL_CHILD" != x"" \
16&& test x"$REAL_CHILD" = x"$PARENTS_IDEA_OF_CHILD"
17echo "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 @@
1a041#c 11 a041#c
2a041#c 22 a041#c
3a\041#c 33 a\041#c
4a\041#c 44 a\041#c
5a\041#c 55 a\041#c
6a\041#c 66 a\041#c
7a\041#c 77 a\041#c
8a\041#c 88 a\041#c
9a\041#c 99 a\041#c
10a\c 1010 a\c
11a\c 1111 a\c
12a\c 1212 a\c
13a\\c 1313 a\\c
14a\\c 1414 a\\c
15a\\c 1515 a\\c
16a\tc 1616 a\tc
17a\tc 1717 a\tc
18a\tc 1818 a\tc
19atc 1919 atc
20a\tc 2020 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 @@
1a='abc' 1a='abc'
2r=${a//b/\041#} 2r=${a//b/\041#}
3echo $r 3echo 1 $r
4echo ${a//b/\041#} 4echo 2 ${a//b/\041#}
5echo "${a//b/\041#}" 5echo 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
7a='abc' 14a='abc'
8r=${a//b/\\041#} 15r=${a//b/\\041#}
9echo $r 16echo 4 $r
10echo ${a//b/\\041#} 17echo 5 ${a//b/\\041#}
11echo "${a//b/\\041#}" 18echo 6 "${a//b/\\041#}"
12 19
13a='abc' 20a='abc'
14b='\041#' 21b='\041#'
15r=${a//b/$b} 22r=${a//b/$b}
16echo $r 23echo 7 $r
17echo ${a//b/$b} 24echo 8 ${a//b/$b}
18echo "${a//b/$b}" 25echo 9 "${a//b/$b}"
19 26
20a='abc' 27a='abc'
21b='\' 28b='\'
22r="${a//b/$b}" 29r="${a//b/$b}"
23echo $r 30echo 10 $r
24echo ${a//b/$b} 31echo 11 ${a//b/$b}
25echo "${a//b/$b}" 32echo 12 "${a//b/$b}"
26 33
27a='abc' 34a='abc'
28b='\\' 35b='\\'
29r="${a//b/$b}" 36r="${a//b/$b}"
30echo $r 37echo 13 $r
31echo ${a//b/$b} 38echo 14 ${a//b/$b}
32echo "${a//b/$b}" 39echo 15 "${a//b/$b}"
33 40
34a='abc' 41a='abc'
35b='\t' 42b='\t'
36r="${a//b/$b}" 43r="${a//b/$b}"
37echo $r 44echo 16 $r
38echo ${a//b/$b} 45echo 17 ${a//b/$b}
39echo "${a//b/$b}" 46echo 18 "${a//b/$b}"
40echo ${a//b/\t} 47echo 19 ${a//b/\t}
41echo "${a//b/\t}" 48echo 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 @@
1In assignment: a*b-backslashstar-
2Unquoted: a*b-backslashstar-
3Quoted: a*b-backslashstar-
4Done: 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 @@
1FOO='a*b\*c'
2BAR=${FOO//\\*/-backslashstar-}
3echo In assignment: "$BAR"
4echo Unquoted: ${FOO//\\*/-backslashstar-}
5echo Quoted: "${FOO//\\*/-backslashstar-}"
6echo 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> */
10struct vt_stat { 66struct 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 @@
1while true; do echo A; break; echo B; done 1while true; do echo A; break; echo B; done
2echo OK:$? 2echo 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 @@
1bug() {
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
11bug | {
12while read varval; do
13 eval $varval
14done
15test x"$REAL_CHILD" != x"" \
16&& test x"$REAL_CHILD" = x"$PARENTS_IDEA_OF_CHILD"
17echo "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) {