aboutsummaryrefslogtreecommitdiff
path: root/shell
AgeCommit message (Collapse)Author
2016-11-25ash,hush: make ^C in interactive mode visually much closer to bash behaviorDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-24ash,hush: ^C from command line should set $? to 128+SIGINTDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-23test: make [ and [[ forms individually selectableDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-08hush: make getch/peek functions directly calledDenys Vlasenko
Indirect calls are more difficult to predict. Unfortunately, on x64 direct call is 5 bytes while indirect "call (reg+ofs)" is 3 bytes: function old new delta i_getch - 82 +82 i_peek - 63 +63 parse_stream 2531 2579 +48 parse_dollar 771 797 +26 parse_redirect 296 321 +25 add_till_closing_bracket 408 420 +12 encode_string 256 265 +9 i_peek_and_eat_bkslash_nl 93 99 +6 add_till_backquote 110 114 +4 parse_and_run_stream 139 141 +2 expand_vars_to_list 1143 1144 +1 static_peek 6 - -6 setup_string_in_str 39 18 -21 setup_file_in_str 40 19 -21 static_get 27 - -27 file_peek 52 - -52 file_get 65 - -65 ------------------------------------------------------------------------------ (add/remove: 2/4 grow/shrink: 9/2 up/down: 278/-192) Total: 86 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-08hush: renumber PIPE_foo, make PIPE_SEQ = 0Denys Vlasenko
PIPE_SEQ is used most often, having it zero makes code smaller: function old new delta done_word 719 707 -12 parse_stream 2546 2531 -15 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-08hush: small optimization in run_listDenys Vlasenko
I thought gcc can detect this itself. It doesn't. function old new delta run_list 1030 1021 -9 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-08hush: deindent large block of code, no code changesDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-08hush: simplify insert_bg_jobsDenys Vlasenko
function old new delta insert_bg_job 366 281 -85 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-08hush: make "wait %1" less likely to play with signal maskDenys Vlasenko
Was playing with "sleep 3 | exit 3 & wait %1" and noticed that often SIGCHLD arrives even before I get to signal masking. Can avoid it in this case. function old new delta wait_for_child_or_signal 228 265 +37 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-08hush: rework "wait %jobspec" to work in non-interactive shells tooDenys Vlasenko
Also add tests. wait5.tests so far fails (but works for ash and dash). function old new delta builtin_wait 305 283 -22 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-07hush: "wait $!; echo $?" should return 127 if $! already exitedDenys Vlasenko
It would be nice to provide bash-like "remember las exitcode" thingy, but it's a bit complex. For now, match ash and dash. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-07hush: implement "wait %jobspec"Denys Vlasenko
function old new delta parse_jobspec - 83 +83 job_exited_or_stopped - 79 +79 builtin_wait 236 302 +66 wait_for_child_or_signal 199 228 +29 checkjobs 142 158 +16 builtin_jobs 59 68 +9 process_wait_result 453 408 -45 builtin_fg_bg 272 203 -69 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 4/2 up/down: 282/-114) Total: 168 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-07hush: factor out %jobspec parsingDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-07hush: comment fixDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-07hush: do not allow sh -c '{ echo boo }'Denys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-04hush: case logic for setting $? was still wrongDenys Vlasenko
Resetting to 0 should happen in "esac". Matched branch must still see previous $?. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-04hush: non-matching "case" statement sets $? to 0Denys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-04hush: allow { cmd } to not be terminated by semicolon in some casesDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-04ash: fix "duplicate local" code (forgot to re-enable interrupts)Denys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-11-03ash: while (!got_sig) pause() is not reliable, use sigsuspend()Denys Vlasenko
dash was doing it for a reason. Unfortunately, it had no comment why... now I know. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-30ash: if using libc glob(), skip it if no metachars are in wordDenys Vlasenko
This saves making tons of pointless stat() calls function old new delta expandarg 888 921 +33 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-30ash: fix bit-rotten debug infrastructureDenys Vlasenko
DEBUG = 2 output was a bit messed up Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-30ash: make popfile() anfter popallfiles() safeDenys Vlasenko
In this example: ash -c 'readonly x; echo $(command eval x=2)' evalstring() is called after forkchild(), which calls popallfiles(). On exception, evalstring() will popfile(). Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-28hush: fix "(sleep 1; exit 3) & sleep 2; echo $?; wait $!; echo $?"Denys Vlasenko
"wait $!" may be just a bit too late: backgrounded $! is gone. Do not bomb out in this case. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-28hush: fix "wait PID"Denys Vlasenko
It was not properly interruptible, and did not update job status (the exited processes were still thought of as running). function old new delta process_wait_result - 453 +453 wait_for_child_or_signal - 199 +199 run_list 996 1002 +6 checkjobs_and_fg_shell 41 43 +2 builtin_wait 328 215 -113 checkjobs 516 142 -374 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 2/2 up/down: 660/-487) Total: 173 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-28ash: use pause(), not sigsuspend(), in wait builtinDenys Vlasenko
Same effect, smaller code function old new delta dowait 463 374 -89 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-28ash: fix interactive "command eval STRING" exiting on errors.Denys Vlasenko
This bug is also present in current dash Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: [JOBS] Fix dowait signal raceDenys Vlasenko
Upstream commit: Date: Sun, 22 Feb 2009 18:10:01 +0800 [JOBS] Fix dowait signal race This test program by Alexey Gladkov can cause dash to enter an infinite loop in waitcmd. #!/bin/dash trap "echo TRAP" USR1 stub() { echo ">>> STUB $1" >&2 sleep $1 echo "<<< STUB $1" >&2 kill -USR1 $$ } stub 3 & stub 2 & until { echo "###"; wait; } do echo "*** $?" done The problem is that if we get a signal after the wait3 system call has returned but before we get to INTON in dowait, then we can jump back up to the top and lose the exit status. So if we then wait for the job that has just exited, then it'll stay there forever. I made the original change that caused this bug to fix pretty much the same bug but in the opposite direction. That is, if we get a signal after we enter wait3 but before we hit the kernel then it too can cause the wait to go on forever (assuming the child doesn't exit). In fact this is pretty much exactly the scenario that you'll find in glibc's documentation on pause(). The solution is given there too, in the form of sigsuspend, which is the only way to do the check and wait atomically. So this patch fixes Alexey's race without reintroducing the old bug by converting the blocking wait3 to a sigsuspend. In order to do this we need to set a signal handler for SIGCHLD, so the code has been modified to always do that. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> I failed to reproduce the bug (it requires precise timing), but it seems real. function old new delta dowait 284 463 +179 setsignal 301 326 +25 signal_handler 59 76 +17 ash_main 1481 1487 +6 localcmd 350 348 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 227/-2) Total: 225 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: [SIGNAL] Remove EXSIGDenys Vlasenko
Upstream commit 1: Date: Sun, 22 Feb 2009 18:16:13 +0800 [SIGNAL] Remove EXSIG Now that waitcmd no longer uses EXSIG we can remove it. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Upstream commit 2: Date: Thu, 2 Oct 2014 21:07:55 +0800 [ERROR] Set exitstatus in onint Currently the exit status when we receive SIGINT is set in evalcommand which means that it doesn't always get set. For example, if you press CTRL-C at the prompt of an interactive dash, the exit status is not set to 130 as it is in many other Bourne shells. This patch fixes this by moving the setting of the exit status into onint which also simplifies evalcommand. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Upstream commit 3: Date: Fri, 3 Oct 2014 14:07:07 +0800 [EVAL] Do not clobber exitstatus in evalcommand All originators of EXERROR have been setting the exitstatus for a while now. So it is no longer appropriate to set it explicitly in evalcommand. In fact doing so may cause the original exitstatus to be lost. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Last three coomits: function old new delta waitcmd 186 224 +38 dowait 276 284 +8 waitforjob 104 107 +3 localcmd 348 350 +2 showjobs 64 61 -3 forkshell 263 260 -3 raise_interrupt 93 67 -26 blocking_wait_with_raise_on_sig 40 - -40 evalcommand 1264 1208 -56 evaltree 809 498 -311 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: open-code blocking_dowait_with_raise_on_sig()Denys Vlasenko
There is in fact only one callsite. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: return to DOWAIT_* constants similar to dash, no logic changesDenys Vlasenko
This loses an insignificant optimization, but may allow backporting of some recent-ish dash fixes. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: delete leftovers from "simplify EOF/newline handling in list parser" commitDenys Vlasenko
This commit should have deleted these two statements: commit c0e007663d30f83b0e5e074db34dcffaa8915e99 Author: Ron Yorston <rmy@pobox.com> Date: Thu Oct 29 11:30:55 2015 +0000 ash: simplify EOF/newline handling in list parser Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: [EXPAND] Fix ifsfirst/ifslastp leakDenys Vlasenko
Upstream commit: Date: Wed, 8 Sep 2010 20:07:26 +0800 [EXPAND] Fix ifsfirst/ifslastp leak As it stands expandarg may return with a non-NULL ifslastp which then confuses any subsequent ifsbreakup user that doesn't clear it directly. What's worse, if we get interrupted before we hit ifsfree in expandarg we will leak memory. This patch fixes this by always calling ifsfree in expandarg thus ensuring that ifslastp is always NULL on the normal path. It also adds an ifsfree call to the RESET path to ensure that memory isn't leaked. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Fallout 1: Date: Mon, 18 Oct 2010 10:55:42 +0800 [EXPAND] Fix ifsfirst/ifslastp leak in casematch The commit f42e443bb511ed3224f09b4fcf0772438ebdbbfa [EXPAND] Fix ifsfirst/ifslastp leak revealed yet another ifsfirst/ifslastp leak in casematch. Previously it was hidden because ifsfirst/ifslastp was cleared unconditionally on entry (which caused the leakage of those entries). Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Fallout 2: Date: Sun, 28 Nov 2010 21:09:51 +0800 [EXPAND] Free IFS state in evalbackcmd On Sun, Nov 07, 2010 at 04:04:20PM -0600, Jonathan Nieder wrote: > Herbert Xu wrote: > > commit f42e443bb511ed3224f09b4fcf0772438ebdbbfa > > Author: Herbert Xu <herbert@gondor.apana.org.au> > > Date: Wed Sep 8 20:07:26 2010 +0800 > > > > [EXPAND] Fix ifsfirst/ifslastp leak > > Another puzzle bisecting to f42e443bb. This one comes from the > grub-mkconfig script: > > $ sh -c 'datadir=/usr/share; pkgdatadir=${datadir}/`cat`' 2>&1 | cat -A > cat: M-^\^M^F^HM-4^M^F^HM-(^M^F^H: No such file or directory$ > cat: M-(^M^F^H: No such file or directory$ > > Still reproducible with 016b529. I'll try to find time to look into > it, but thought you might like to know nevertheless. This is the symptom of another leak. In this case evalbackcmd occurs in the middle of an expansion (as it should) but the forked child never clears the previous IFS state. This patch adds the missing ifsfree call. This wasn't as much of a problem as the previously discovered leaks since all it means is that the child gets to carry around the parent's expansion state and the child is usually short-lived. Reported-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Fallout 3: Date: Tue, 15 Mar 2011 16:01:34 +0800 [EXPAND] Free IFS state after here document expansion Here's another bug bisecting to f42e443bb ([EXPAND] Fix ifsfirst/ifslastp leak, 2010-09-08). It was found with the following test case, based on the configure script for Tracker: dash -x -c ' <<-_ACEOF $@ _ACEOF exec ' - abcdefgh + + exec ?a exec: 1: : Permission denied The missing ifsfree call is in expandarg when it returns to openhere during here document expansion. Reported-by: Aurelien Jarno <aurel32@debian.org> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> function old new delta ifsfree - 66 +66 ash_main 1490 1495 +5 argstr 1154 1159 +5 evalcase 275 270 -5 expandarg 972 888 -84 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/2 up/down: 76/-89) Total: -13 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: move ifsbreakup() and ifsfree() upDenys Vlasenko
Preparatory patch. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: partially sync with dash on "fork if traps are set" logicDenys Vlasenko
Upstream commit "[EVAL] Force fork if any trap is set, not just on EXIT" had a similar code as our fix to that bug. Eliminate some superficial differences. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: [SHELL] Expand ENV before using itDenys Vlasenko
Upstream commit: Date: Sun, 13 Jul 2008 21:51:52 +0800 [SHELL] Expand ENV before using it Per POSIX ENV needs to undergo parameter expansion. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-27ash: comment tweaks, no code changesDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: optimize tryexec(): avoid one allocationDenys Vlasenko
There was a bug in tryexec which bbox had fixed in 2003. dash had a smaller fix in 2007. Copy it. It is smaller, although it is also more quirky (requires argv[-1] to exist). Upstream commit 1: Date: Mon, 15 Oct 2007 20:24:28 +0800 [EXEC] Fixed execing of scripts with no hash-bang The function tryexec used the original name instead of the path found through PATH search. This patch fixes that. Test case: trap 'rm -f $TMP' EXIT TMP=$(tempfile -s nosuchthing) cat <<- EOF > $TMP echo OK EOF chmod u+x $TMP cd / PATH=${TMP%/*} ${TMP##*/} Old result: /bin/sh: Can't open filelgY4Fanosuchthing New result: OK Upstream commit 2: Date: Sun, 23 Dec 2007 11:02:26 +0800 [EVAL] Fix bad pointer arithmetic in evalcommand dash dies on sparc with a SIGBUS due to an arithmetic error introduced with commit 03b4958, this patch fixes it. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> function old new delta evalcommand 1261 1264 +3 dotcmd 321 319 -2 tryexec 115 64 -51 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/2 up/down: 3/-53) Total: -50 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [CD] Lookup PWD after going through CDPATHDenys Vlasenko
Upstream commit: Date: Mon, 31 Aug 2009 22:06:41 +1000 [CD] Lookup PWD after going through CDPATH On Tue, Jul 14, 2009 at 09:39:03PM +0000, Eric Blake wrote: > For the cd command, POSIX 2008 requires that after all pathnames in CDPATH > have been tested and failed in step 5, then step 6 interprets the directory > argument relative to PWD. In other words, this demonstrates a bug: > > $ dash -c 'cd /tmp; mkdir -p foo; CDPATH=oops; cd foo; echo $?; pwd' > cd: 1: can't cd to foo > 2 > /tmp > > while bash gets it correct: > > $ bash -c 'cd /tmp; mkdir -p foo; CDPATH=oops; cd foo; echo $?; pwd' > 0 > /tmp/foo This patch fixes the problem. Reported-by: Eric Blake <ebb9@byu.net> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> function old new delta cdcmd 667 680 +13 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [MEMALLOC] Made grabstackblock an inline wrapper for stallocDenys Vlasenko
Upstream patch: Date: Fri, 5 Oct 2007 23:26:45 +0800 [MEMALLOC] Made grabstackblock an inline wrapper for stalloc The function grabstackblock is identical in semantics to stalloc within its input constraints. function old new delta dotcmd 319 321 +2 grabstackblock 19 5 -14 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [VAR] Remove setvarsafeDenys Vlasenko
Upstream commit: Date: Sat, 6 Oct 2007 21:18:58 +0800 [VAR] Remove setvarsafe The only user of setvarsafe is getopts. However, we can achieve the same result by pre-setting the value of shellparam.optind. function old new delta getoptscmd 614 515 -99 setvarsafe 147 - -147 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 0/1 up/down: 0/-246) Total: -246 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: use shellparam.optind/optoff in getopts() directly, not through pointersDenys Vlasenko
This is a preparatory patch for next change Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [PARSER] Size optimisations in parameter expansion parserDenys Vlasenko
Upstream commit: Date: Thu, 4 Oct 2007 22:20:38 +0800 [PARSER] Size optimisations in parameter expansion parser Merge flags into subtype. Do not write subtype out twice. Add likely flag on ${ vs. $NAME. Kill unnecessary (and bogus) PEOA check. function old new delta readtoken1 2891 2860 -31 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [PARSER] Recognise here-doc delimiters terminated by EOFDenys Vlasenko
Upstream commit 1: Date: Wed, 26 Sep 2007 17:14:16 +0800 [PARSER] Recognise here-doc delimiters terminated by EOF Previously dash required a <newline> character to be present in order for a here-document delimiter to be detected. Allowing EOF in the absence of a <newline> to play the same purpose allows some intuitive scripts to succeed. POSIX seems to be silence on this so this should be OK. Test case: eval 'cat <<- NOT test NOT' echo OK Old result: test NOTOK New result: test OK Upstream commit 2: Date: Sat, 20 Oct 2007 18:49:31 +0800 [PARSER] Fix here-doc corruption The change [PARSER] Recognise here-doc delimiters terminated by EOF introduced a regerssion whereby lines starting with eofmark but are not equal to eofmark would be corrupted. This patch fixes it. Test case: cat << _ACEOF _ASBOX _ACEOF Old result: SASBOX New result: _ASBOX Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [PARSER] Fix parsing of ${##1}Denys Vlasenko
Upstream commit: Date: Thu, 4 Oct 2007 22:15:10 +0800 [PARSER] Fix parsing of ${##1} Previously dash treated ${##1} as a length operation. This patch fixes that. Test case: set -- a echo ${##1}OK Old result: 1OK New result: OK This was a real bug in ash (but not in hush). Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [REDIR] Remove redundant CLOEXEC callsDenys Vlasenko
Upstream commit: Date: Sun, 6 May 2007 19:28:56 +1000 [REDIR] Remove redundant CLOEXEC calls Now that we're marking file descriptors as CLOEXEC in savefd, we no longer need to close them on exec or in setinputfd. function old new delta ash_main 1478 1492 +14 setinputfile 224 226 +2 readtoken1 2752 2750 -2 shellexec 208 198 -10 clearredir 30 - -30 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/2 up/down: 16/-42) Total: -26 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [REDIR] Replace copyfd by savefd and use dup2 elsewhereDenys Vlasenko
Upstream commit: Date: Sat, 12 May 2007 18:00:57 +1000 [REDIR] Replace copyfd by savefd and use dup2 elsewhere There are two kinds of users to copyfd, those that want to copy an fd to an exact value and those that want to move an fd to a value >= 10. The former can simply use dup2 directly while the latter share a lot of common code that now constitutes savefd. This does not change much, just reducing our divergence from dash code. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26typo fixesDenys Vlasenko
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [BUILTIN] Treat OPTIND=0 in the same way as OPTIND=1Denys Vlasenko
Upstream commit: Date: Sat, 6 Oct 2007 18:59:31 +0800 [BUILTIN] Treat OPTIND=0 in the same way as OPTIND=1 Previously setting OPTIND to 0 would cause subsequent getopts calls to fail. This patch makes dash reset the getopts parameters the same way as OPTIND=1. Both behaviours are allowed by POSIX but other common shells do tolerate this case. function old new delta getoptsreset 24 30 +6 getoptscmd 632 614 -18 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2016-10-26ash: [PARSER] Report substition errors at expansion timeDenys Vlasenko
Upstreams commit: Date: Mon, 8 Oct 2007 21:32:25 +0800 [PARSER] Report substition errors at expansion time On Wed, Apr 11, 2007 at 01:24:21PM -0700, Micah Cowan wrote: > This operation fails on Ubuntu: > > $ /bin/sh -c 'if false; then d="${foo/bar}"; fi' > /bin/sh: Syntax error: Bad substitution > > When used with other POSIX shells it succeeds. While semantically the > variable reference ${foo/bar} is not valid, this is not a syntax error > according to POSIX, and since the variable assignment expression is > never invoked (because it's within an "if false") it should not be seen > as an error. > > I ran into this because after restarting my system I could no longer log > in. It turns out that the problem was (a) I had edited .gnomerc to > source my .bashrc file so that my environment would be set properly, and > (b) I had added some new code to my .bashrc WITHIN A CHECK FOR BASH! > that used bash's ${var/match/sub} feature. Even though this code was > within a "case $BASH_VERSION; in *[0-9]*) ... esac (so dash would never > execute it since that variable is not set), it still caused dash to > throw up. > > FYI, some relevant details from POSIX: > > Section 2.3, Token Recognition: > > 5. If the current character is an unquoted '$' or '`', the shell shall > identify the start of any candidates for parameter expansion ( Parameter > Expansion), command substitution ( Command Substitution), or arithmetic > expansion ( Arithmetic Expansion) from their introductory unquoted > character sequences: '$' or "${", "$(" or '`', and "$((", respectively. > The shell shall read sufficient input to determine the end of the unit > to be expanded (as explained in the cited sections). > > Section 2.6.2, Parameter Expansion: > > The format for parameter expansion is as follows: > > ${expression} > > where expression consists of all characters until the matching '}'. Any > '}' escaped by a backslash or within a quoted string, and characters in > embedded arithmetic expansions, command substitutions, and variable > expansions, shall not be examined in determining the matching '}'. > [...] > > The parameter name or symbol can be enclosed in braces, which are > optional except for positional parameters with more than one digit or > when parameter is followed by a character that could be interpreted as > part of the name. The matching closing brace shall be determined by > counting brace levels, skipping over enclosed quoted strings, and > command substitutions. > --- > In addition to bash I've checked Solaris /bin/sh and ksh and they don't > report an error. > > ----- > Micah Cowan: > > The applicable portion of POSIX is in XCU 2.10.1: > > "The WORD tokens shall have the word expansion rules applied to them > immediately before the associated command is executed, not at the time > the command is parsed." > > This seems fairly clear to me. This patch moves the error detection to expansion time. Test case: if false; then echo ${a!7} fi echo OK Old result: dash: Syntax error: Bad substitution New result: OK function old new delta evalvar 574 585 +11 readtoken1 2763 2750 -13 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>