aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c304
1 files changed, 165 insertions, 139 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 2e7f68c05..af1157709 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -30,80 +30,6 @@
30 * - fake $PPID 30 * - fake $PPID
31 */ 31 */
32 32
33/*
34 * The following should be set to reflect the type of system you have:
35 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
36 * define SYSV if you are running under System V.
37 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
38 * define DEBUG=2 to compile in and turn on debugging.
39 *
40 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
41 * debugging info will be written to ./trace and a quit signal
42 * will generate a core dump.
43 */
44#define DEBUG 0
45/* Tweak debug output verbosity here */
46#define DEBUG_TIME 0
47#define DEBUG_PID 1
48#define DEBUG_SIG 1
49#define DEBUG_INTONOFF 0
50
51#define PROFILE 0
52
53#define JOBS ENABLE_ASH_JOB_CONTROL
54
55#include <setjmp.h>
56#include <fnmatch.h>
57#include <sys/times.h>
58#include <sys/utsname.h> /* for setting $HOSTNAME */
59
60#include "busybox.h" /* for applet_names */
61
62#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
63/* Bionic at least up to version 24 has no glob() */
64# undef ENABLE_ASH_INTERNAL_GLOB
65# define ENABLE_ASH_INTERNAL_GLOB 1
66#endif
67
68#if !ENABLE_ASH_INTERNAL_GLOB
69# include <glob.h>
70#endif
71
72#include "unicode.h"
73#include "shell_common.h"
74#if ENABLE_SH_MATH_SUPPORT
75# include "math.h"
76#endif
77#if ENABLE_ASH_RANDOM_SUPPORT
78# include "random.h"
79#else
80# define CLEAR_RANDOM_T(rnd) ((void)0)
81#endif
82
83#include "NUM_APPLETS.h"
84#if NUM_APPLETS == 1
85/* STANDALONE does not make sense, and won't compile */
86# undef CONFIG_FEATURE_SH_STANDALONE
87# undef ENABLE_FEATURE_SH_STANDALONE
88# undef IF_FEATURE_SH_STANDALONE
89# undef IF_NOT_FEATURE_SH_STANDALONE
90# define ENABLE_FEATURE_SH_STANDALONE 0
91# define IF_FEATURE_SH_STANDALONE(...)
92# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
93#endif
94
95#ifndef PIPE_BUF
96# define PIPE_BUF 4096 /* amount of buffering in a pipe */
97#endif
98
99#if !ENABLE_PLATFORM_MINGW32
100# define is_absolute_path(path) ((path)[0] == '/')
101#endif
102
103#if !BB_MMU
104# error "Do not even bother, ash will not run on NOMMU machine"
105#endif
106
107//config:config ASH 33//config:config ASH
108//config: bool "ash" 34//config: bool "ash"
109//config: default y 35//config: default y
@@ -118,14 +44,14 @@
118//config:config ASH_OPTIMIZE_FOR_SIZE 44//config:config ASH_OPTIMIZE_FOR_SIZE
119//config: bool "Optimize for size instead of speed" 45//config: bool "Optimize for size instead of speed"
120//config: default y 46//config: default y
121//config: depends on ASH 47//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
122//config: help 48//config: help
123//config: Compile ash for reduced size at the price of speed. 49//config: Compile ash for reduced size at the price of speed.
124//config: 50//config:
125//config:config ASH_INTERNAL_GLOB 51//config:config ASH_INTERNAL_GLOB
126//config: bool "Use internal glob() implementation" 52//config: bool "Use internal glob() implementation"
127//config: default n 53//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
128//config: depends on ASH 54//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
129//config: help 55//config: help
130//config: Do not use glob() function from libc, use internal implementation. 56//config: Do not use glob() function from libc, use internal implementation.
131//config: Use this if you are getting "glob.h: No such file or directory" 57//config: Use this if you are getting "glob.h: No such file or directory"
@@ -134,7 +60,7 @@
134//config:config ASH_RANDOM_SUPPORT 60//config:config ASH_RANDOM_SUPPORT
135//config: bool "Pseudorandom generator and $RANDOM variable" 61//config: bool "Pseudorandom generator and $RANDOM variable"
136//config: default y 62//config: default y
137//config: depends on ASH 63//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
138//config: help 64//config: help
139//config: Enable pseudorandom generator and dynamic variable "$RANDOM". 65//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
140//config: Each read of "$RANDOM" will generate a new pseudorandom value. 66//config: Each read of "$RANDOM" will generate a new pseudorandom value.
@@ -145,7 +71,7 @@
145//config:config ASH_EXPAND_PRMT 71//config:config ASH_EXPAND_PRMT
146//config: bool "Expand prompt string" 72//config: bool "Expand prompt string"
147//config: default y 73//config: default y
148//config: depends on ASH 74//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
149//config: help 75//config: help
150//config: "PS#" may contain volatile content, such as backquote commands. 76//config: "PS#" may contain volatile content, such as backquote commands.
151//config: This option recreates the prompt string from the environment 77//config: This option recreates the prompt string from the environment
@@ -154,70 +80,70 @@
154//config:config ASH_BASH_COMPAT 80//config:config ASH_BASH_COMPAT
155//config: bool "bash-compatible extensions" 81//config: bool "bash-compatible extensions"
156//config: default y 82//config: default y
157//config: depends on ASH 83//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
158//config: help 84//config: help
159//config: Enable bash-compatible extensions. 85//config: Enable bash-compatible extensions.
160//config: 86//config:
161//config:config ASH_IDLE_TIMEOUT 87//config:config ASH_IDLE_TIMEOUT
162//config: bool "Idle timeout variable" 88//config: bool "Idle timeout variable"
163//config: default n 89//config: default n
164//config: depends on ASH 90//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
165//config: help 91//config: help
166//config: Enables bash-like auto-logout after $TMOUT seconds of idle time. 92//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
167//config: 93//config:
168//config:config ASH_JOB_CONTROL 94//config:config ASH_JOB_CONTROL
169//config: bool "Job control" 95//config: bool "Job control"
170//config: default y 96//config: default y
171//config: depends on ASH 97//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
172//config: help 98//config: help
173//config: Enable job control in the ash shell. 99//config: Enable job control in the ash shell.
174//config: 100//config:
175//config:config ASH_ALIAS 101//config:config ASH_ALIAS
176//config: bool "Alias support" 102//config: bool "Alias support"
177//config: default y 103//config: default y
178//config: depends on ASH 104//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
179//config: help 105//config: help
180//config: Enable alias support in the ash shell. 106//config: Enable alias support in the ash shell.
181//config: 107//config:
182//config:config ASH_GETOPTS 108//config:config ASH_GETOPTS
183//config: bool "Builtin getopt to parse positional parameters" 109//config: bool "Builtin getopt to parse positional parameters"
184//config: default y 110//config: default y
185//config: depends on ASH 111//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
186//config: help 112//config: help
187//config: Enable support for getopts builtin in ash. 113//config: Enable support for getopts builtin in ash.
188//config: 114//config:
189//config:config ASH_BUILTIN_ECHO 115//config:config ASH_BUILTIN_ECHO
190//config: bool "Builtin version of 'echo'" 116//config: bool "Builtin version of 'echo'"
191//config: default y 117//config: default y
192//config: depends on ASH 118//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
193//config: help 119//config: help
194//config: Enable support for echo builtin in ash. 120//config: Enable support for echo builtin in ash.
195//config: 121//config:
196//config:config ASH_BUILTIN_PRINTF 122//config:config ASH_BUILTIN_PRINTF
197//config: bool "Builtin version of 'printf'" 123//config: bool "Builtin version of 'printf'"
198//config: default y 124//config: default y
199//config: depends on ASH 125//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
200//config: help 126//config: help
201//config: Enable support for printf builtin in ash. 127//config: Enable support for printf builtin in ash.
202//config: 128//config:
203//config:config ASH_BUILTIN_TEST 129//config:config ASH_BUILTIN_TEST
204//config: bool "Builtin version of 'test'" 130//config: bool "Builtin version of 'test'"
205//config: default y 131//config: default y
206//config: depends on ASH 132//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
207//config: help 133//config: help
208//config: Enable support for test builtin in ash. 134//config: Enable support for test builtin in ash.
209//config: 135//config:
210//config:config ASH_HELP 136//config:config ASH_HELP
211//config: bool "help builtin" 137//config: bool "help builtin"
212//config: default y 138//config: default y
213//config: depends on ASH 139//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
214//config: help 140//config: help
215//config: Enable help builtin in ash. 141//config: Enable help builtin in ash.
216//config: 142//config:
217//config:config ASH_CMDCMD 143//config:config ASH_CMDCMD
218//config: bool "'command' command to override shell builtins" 144//config: bool "'command' command to override shell builtins"
219//config: default y 145//config: default y
220//config: depends on ASH 146//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
221//config: help 147//config: help
222//config: Enable support for the ash 'command' builtin, which allows 148//config: Enable support for the ash 'command' builtin, which allows
223//config: you to run the specified command with the specified arguments, 149//config: you to run the specified command with the specified arguments,
@@ -225,19 +151,105 @@
225//config: 151//config:
226//config:config ASH_MAIL 152//config:config ASH_MAIL
227//config: bool "Check for new mail on interactive shells" 153//config: bool "Check for new mail on interactive shells"
228//config: default n 154//config: default y
229//config: depends on ASH 155//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
230//config: help 156//config: help
231//config: Enable "check for new mail" function in the ash shell. 157//config: Enable "check for new mail" function in the ash shell.
232//config:
233 158
234//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 159//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
235//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) 160//applet:IF_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
236//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) 161//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
237 162
238//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 163//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
164//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
165//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
239//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 166//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
240 167
168/*
169 * The following should be set to reflect the type of system you have:
170 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
171 * define SYSV if you are running under System V.
172 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
173 * define DEBUG=2 to compile in and turn on debugging.
174 *
175 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
176 * debugging info will be written to ./trace and a quit signal
177 * will generate a core dump.
178 */
179#define DEBUG 0
180/* Tweak debug output verbosity here */
181#define DEBUG_TIME 0
182#define DEBUG_PID 1
183#define DEBUG_SIG 1
184#define DEBUG_INTONOFF 0
185
186#define PROFILE 0
187
188#define JOBS ENABLE_ASH_JOB_CONTROL
189
190#include <setjmp.h>
191#include <fnmatch.h>
192#include <sys/times.h>
193#include <sys/utsname.h> /* for setting $HOSTNAME */
194
195#include "busybox.h" /* for applet_names */
196
197#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
198/* Bionic at least up to version 24 has no glob() */
199# undef ENABLE_ASH_INTERNAL_GLOB
200# define ENABLE_ASH_INTERNAL_GLOB 1
201#endif
202
203#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
204# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
205# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
206# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
207# error glob() should unbackslash them and match. uClibc does not unbackslash,
208# error fails to match dirname, subsequently not expanding <pattern> in it.
209// Testcase:
210// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
211// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
212#endif
213
214#if !ENABLE_ASH_INTERNAL_GLOB
215# include <glob.h>
216#endif
217
218#include "unicode.h"
219#include "shell_common.h"
220#if CONFIG_FEATURE_SH_MATH
221# include "math.h"
222#endif
223#if ENABLE_ASH_RANDOM_SUPPORT
224# include "random.h"
225#else
226# define CLEAR_RANDOM_T(rnd) ((void)0)
227#endif
228
229#include "NUM_APPLETS.h"
230#if NUM_APPLETS == 1
231/* STANDALONE does not make sense, and won't compile */
232# undef CONFIG_FEATURE_SH_STANDALONE
233# undef ENABLE_FEATURE_SH_STANDALONE
234# undef IF_FEATURE_SH_STANDALONE
235# undef IF_NOT_FEATURE_SH_STANDALONE
236# define ENABLE_FEATURE_SH_STANDALONE 0
237# define IF_FEATURE_SH_STANDALONE(...)
238# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
239#endif
240
241#ifndef PIPE_BUF
242# define PIPE_BUF 4096 /* amount of buffering in a pipe */
243#endif
244
245#if !ENABLE_PLATFORM_MINGW32
246# define is_absolute_path(path) ((path)[0] == '/')
247#endif
248
249#if !BB_MMU
250# error "Do not even bother, ash will not run on NOMMU machine"
251#endif
252
241#if ENABLE_PLATFORM_MINGW32 253#if ENABLE_PLATFORM_MINGW32
242union node; 254union node;
243struct strlist; 255struct strlist;
@@ -1343,6 +1355,8 @@ ash_msg_and_raise_error(const char *msg, ...)
1343{ 1355{
1344 va_list ap; 1356 va_list ap;
1345 1357
1358 exitstatus = 2;
1359
1346 va_start(ap, msg); 1360 va_start(ap, msg);
1347 ash_vmsg_and_raise(EXERROR, msg, ap); 1361 ash_vmsg_and_raise(EXERROR, msg, ap);
1348 /* NOTREACHED */ 1362 /* NOTREACHED */
@@ -2205,6 +2219,7 @@ lookupvar(const char *name)
2205 return NULL; 2219 return NULL;
2206} 2220}
2207 2221
2222#if ENABLE_UNICODE_SUPPORT
2208static void 2223static void
2209reinit_unicode_for_ash(void) 2224reinit_unicode_for_ash(void)
2210{ 2225{
@@ -2221,6 +2236,9 @@ reinit_unicode_for_ash(void)
2221 reinit_unicode(s); 2236 reinit_unicode(s);
2222 } 2237 }
2223} 2238}
2239#else
2240# define reinit_unicode_for_ash() ((void)0)
2241#endif
2224 2242
2225/* 2243/*
2226 * Search the environment of a builtin command. 2244 * Search the environment of a builtin command.
@@ -2924,7 +2942,7 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2924 2942
2925#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE 2943#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2926 2944
2927#if ENABLE_SH_MATH_SUPPORT 2945#if ENABLE_FEATURE_SH_MATH
2928# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12)) 2946# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2929#else 2947#else
2930# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) 2948# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
@@ -3305,7 +3323,18 @@ static const uint8_t syntax_index_table[] ALIGN1 = {
3305# endif 3323# endif
3306}; 3324};
3307 3325
3326#if 1
3308# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf) 3327# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3328#else /* debug version, caught one signed char bug */
3329# define SIT(c, syntax) \
3330 ({ \
3331 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3332 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3333 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3334 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3335 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3336 })
3337#endif
3309 3338
3310#endif /* !USE_SIT_FUNCTION */ 3339#endif /* !USE_SIT_FUNCTION */
3311 3340
@@ -4765,7 +4794,7 @@ cmdputs(const char *s)
4765 case CTLBACKQ: 4794 case CTLBACKQ:
4766 str = "$(...)"; 4795 str = "$(...)";
4767 goto dostr; 4796 goto dostr;
4768#if ENABLE_SH_MATH_SUPPORT 4797#if ENABLE_FEATURE_SH_MATH
4769 case CTLARI: 4798 case CTLARI:
4770 str = "$(("; 4799 str = "$((";
4771 goto dostr; 4800 goto dostr;
@@ -5749,11 +5778,11 @@ redirect(union node *redir, int flags)
5749 /* Careful to not accidentally "save" 5778 /* Careful to not accidentally "save"
5750 * to the same fd as right side fd in N>&M */ 5779 * to the same fd as right side fd in N>&M */
5751 int minfd = right_fd < 10 ? 10 : right_fd + 1; 5780 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5781#if defined(F_DUPFD_CLOEXEC)
5782 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5783#else
5752 i = fcntl(fd, F_DUPFD, minfd); 5784 i = fcntl(fd, F_DUPFD, minfd);
5753/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds 5785#endif
5754 * are closed in popredir() in the child, preventing them from leaking
5755 * into child. (popredir() also cleans up the mess in case of failures)
5756 */
5757 if (i == -1) { 5786 if (i == -1) {
5758 i = errno; 5787 i = errno;
5759 if (i != EBADF) { 5788 if (i != EBADF) {
@@ -5768,6 +5797,9 @@ redirect(union node *redir, int flags)
5768 remember_to_close: 5797 remember_to_close:
5769 i = CLOSED; 5798 i = CLOSED;
5770 } else { /* fd is open, save its copy */ 5799 } else { /* fd is open, save its copy */
5800#if !defined(F_DUPFD_CLOEXEC)
5801 fcntl(i, F_SETFD, FD_CLOEXEC);
5802#endif
5771 /* "exec fd>&-" should not close fds 5803 /* "exec fd>&-" should not close fds
5772 * which point to script file(s). 5804 * which point to script file(s).
5773 * Force them to be restored afterwards */ 5805 * Force them to be restored afterwards */
@@ -5878,7 +5910,7 @@ redirectsafe(union node *redir, int flags)
5878 * We have to deal with backquotes, shell variables, and file metacharacters. 5910 * We have to deal with backquotes, shell variables, and file metacharacters.
5879 */ 5911 */
5880 5912
5881#if ENABLE_SH_MATH_SUPPORT 5913#if ENABLE_FEATURE_SH_MATH
5882static arith_t 5914static arith_t
5883ash_arith(const char *s) 5915ash_arith(const char *s)
5884{ 5916{
@@ -5966,7 +5998,7 @@ static struct arglist exparg;
5966/* 5998/*
5967 * Our own itoa(). 5999 * Our own itoa().
5968 */ 6000 */
5969#if !ENABLE_SH_MATH_SUPPORT 6001#if !ENABLE_FEATURE_SH_MATH
5970/* cvtnum() is used even if math support is off (to prepare $? values and such) */ 6002/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5971typedef long arith_t; 6003typedef long arith_t;
5972# define ARITH_FMT "%ld" 6004# define ARITH_FMT "%ld"
@@ -6220,14 +6252,15 @@ memtodest(const char *p, size_t len, int syntax, int quotes)
6220 do { 6252 do {
6221 unsigned char c = *p++; 6253 unsigned char c = *p++;
6222 if (c) { 6254 if (c) {
6223 int n = SIT(c, syntax); 6255 if (quotes & QUOTES_ESC) {
6224 if ((quotes & QUOTES_ESC) 6256 int n = SIT(c, syntax);
6225 && ((n == CCTL) 6257 if (n == CCTL
6226 || (((quotes & EXP_FULL) || syntax != BASESYNTAX) 6258 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6227 && n == CBACK) 6259 && n == CBACK
6228 ) 6260 )
6229 ) { 6261 ) {
6230 USTPUTC(CTLESC, q); 6262 USTPUTC(CTLESC, q);
6263 }
6231 } 6264 }
6232 } else if (!(quotes & QUOTES_KEEPNUL)) 6265 } else if (!(quotes & QUOTES_KEEPNUL))
6233 continue; 6266 continue;
@@ -6490,7 +6523,7 @@ expbackq(union node *cmd, int flag)
6490 stackblock() + startloc)); 6523 stackblock() + startloc));
6491} 6524}
6492 6525
6493#if ENABLE_SH_MATH_SUPPORT 6526#if ENABLE_FEATURE_SH_MATH
6494/* 6527/*
6495 * Expand arithmetic expression. Backup to start of expression, 6528 * Expand arithmetic expression. Backup to start of expression,
6496 * evaluate, place result in (backed up) result, adjust string position. 6529 * evaluate, place result in (backed up) result, adjust string position.
@@ -6572,7 +6605,7 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6572 CTLESC, 6605 CTLESC,
6573 CTLVAR, 6606 CTLVAR,
6574 CTLBACKQ, 6607 CTLBACKQ,
6575#if ENABLE_SH_MATH_SUPPORT 6608#if ENABLE_FEATURE_SH_MATH
6576 CTLENDARI, 6609 CTLENDARI,
6577#endif 6610#endif
6578 '\0' 6611 '\0'
@@ -6608,7 +6641,7 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6608 c = p[length]; 6641 c = p[length];
6609 if (c) { 6642 if (c) {
6610 if (!(c & 0x80) 6643 if (!(c & 0x80)
6611 IF_SH_MATH_SUPPORT(|| c == CTLENDARI) 6644 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6612 ) { 6645 ) {
6613 /* c == '=' || c == ':' || c == CTLENDARI */ 6646 /* c == '=' || c == ':' || c == CTLENDARI */
6614 length++; 6647 length++;
@@ -6688,7 +6721,7 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6688 expbackq(argbackq->n, flags | inquotes); 6721 expbackq(argbackq->n, flags | inquotes);
6689 argbackq = argbackq->next; 6722 argbackq = argbackq->next;
6690 goto start; 6723 goto start;
6691#if ENABLE_SH_MATH_SUPPORT 6724#if ENABLE_FEATURE_SH_MATH
6692 case CTLENDARI: 6725 case CTLENDARI:
6693 p--; 6726 p--;
6694 expari(flags | inquotes); 6727 expari(flags | inquotes);
@@ -9686,7 +9719,7 @@ static int helpcmd(int, char **) FAST_FUNC;
9686#if MAX_HISTORY 9719#if MAX_HISTORY
9687static int historycmd(int, char **) FAST_FUNC; 9720static int historycmd(int, char **) FAST_FUNC;
9688#endif 9721#endif
9689#if ENABLE_SH_MATH_SUPPORT 9722#if ENABLE_FEATURE_SH_MATH
9690static int letcmd(int, char **) FAST_FUNC; 9723static int letcmd(int, char **) FAST_FUNC;
9691#endif 9724#endif
9692static int readcmd(int, char **) FAST_FUNC; 9725static int readcmd(int, char **) FAST_FUNC;
@@ -9766,7 +9799,7 @@ static const struct builtincmd builtintab[] = {
9766 { BUILTIN_REGULAR "jobs" , jobscmd }, 9799 { BUILTIN_REGULAR "jobs" , jobscmd },
9767 { BUILTIN_REGULAR "kill" , killcmd }, 9800 { BUILTIN_REGULAR "kill" , killcmd },
9768#endif 9801#endif
9769#if ENABLE_SH_MATH_SUPPORT 9802#if ENABLE_FEATURE_SH_MATH
9770 { BUILTIN_NOSPEC "let" , letcmd }, 9803 { BUILTIN_NOSPEC "let" , letcmd },
9771#endif 9804#endif
9772 { BUILTIN_ASSIGN "local" , localcmd }, 9805 { BUILTIN_ASSIGN "local" , localcmd },
@@ -10004,11 +10037,13 @@ evalcommand(union node *cmd, int flags)
10004 } 10037 }
10005 10038
10006 if (status) { 10039 if (status) {
10040 bail:
10041 exitstatus = status;
10042
10007 /* We have a redirection error. */ 10043 /* We have a redirection error. */
10008 if (spclbltin > 0) 10044 if (spclbltin > 0)
10009 raise_exception(EXERROR); 10045 raise_exception(EXERROR);
10010 bail: 10046
10011 exitstatus = status;
10012 goto out; 10047 goto out;
10013 } 10048 }
10014 10049
@@ -10516,7 +10551,7 @@ pgetc(void)
10516 return g_parsefile->lastc[--g_parsefile->unget]; 10551 return g_parsefile->lastc[--g_parsefile->unget];
10517 10552
10518 if (--g_parsefile->left_in_line >= 0) 10553 if (--g_parsefile->left_in_line >= 0)
10519 c = (signed char)*g_parsefile->next_to_pgetc++; 10554 c = (unsigned char)*g_parsefile->next_to_pgetc++;
10520 else 10555 else
10521 c = preadbuffer(); 10556 c = preadbuffer();
10522 10557
@@ -11840,13 +11875,13 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11840 smallint quotef; 11875 smallint quotef;
11841 smallint dblquote; 11876 smallint dblquote;
11842 smallint oldstyle; 11877 smallint oldstyle;
11843 smallint prevsyntax; /* syntax before arithmetic */ 11878 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
11844#if ENABLE_ASH_EXPAND_PRMT 11879#if ENABLE_ASH_EXPAND_PRMT
11845 smallint pssyntax; /* we are expanding a prompt string */ 11880 smallint pssyntax; /* we are expanding a prompt string */
11846#endif 11881#endif
11847 int varnest; /* levels of variables expansion */ 11882 int varnest; /* levels of variables expansion */
11848 int arinest; /* levels of arithmetic expansion */ 11883 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11849 int parenlevel; /* levels of parens in arithmetic */ 11884 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
11850 int dqvarnest; /* levels of variables expansion within double quotes */ 11885 int dqvarnest; /* levels of variables expansion within double quotes */
11851 11886
11852 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) 11887 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
@@ -11854,7 +11889,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11854 startlinno = g_parsefile->linno; 11889 startlinno = g_parsefile->linno;
11855 bqlist = NULL; 11890 bqlist = NULL;
11856 quotef = 0; 11891 quotef = 0;
11857 prevsyntax = 0; 11892 IF_FEATURE_SH_MATH(prevsyntax = 0;)
11858#if ENABLE_ASH_EXPAND_PRMT 11893#if ENABLE_ASH_EXPAND_PRMT
11859 pssyntax = (syntax == PSSYNTAX); 11894 pssyntax = (syntax == PSSYNTAX);
11860 if (pssyntax) 11895 if (pssyntax)
@@ -11862,8 +11897,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11862#endif 11897#endif
11863 dblquote = (syntax == DQSYNTAX); 11898 dblquote = (syntax == DQSYNTAX);
11864 varnest = 0; 11899 varnest = 0;
11865 arinest = 0; 11900 IF_FEATURE_SH_MATH(arinest = 0;)
11866 parenlevel = 0; 11901 IF_FEATURE_SH_MATH(parenlevel = 0;)
11867 dqvarnest = 0; 11902 dqvarnest = 0;
11868 11903
11869 STARTSTACKSTR(out); 11904 STARTSTACKSTR(out);
@@ -11970,7 +12005,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11970 } 12005 }
11971 USTPUTC(c, out); 12006 USTPUTC(c, out);
11972 break; 12007 break;
11973#if ENABLE_SH_MATH_SUPPORT 12008#if ENABLE_FEATURE_SH_MATH
11974 case CLP: /* '(' in arithmetic */ 12009 case CLP: /* '(' in arithmetic */
11975 parenlevel++; 12010 parenlevel++;
11976 USTPUTC(c, out); 12011 USTPUTC(c, out);
@@ -12021,7 +12056,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12021 } /* for (;;) */ 12056 } /* for (;;) */
12022 endword: 12057 endword:
12023 12058
12024#if ENABLE_SH_MATH_SUPPORT 12059#if ENABLE_FEATURE_SH_MATH
12025 if (syntax == ARISYNTAX) 12060 if (syntax == ARISYNTAX)
12026 raise_error_syntax("missing '))'"); 12061 raise_error_syntax("missing '))'");
12027#endif 12062#endif
@@ -12200,7 +12235,7 @@ parsesub: {
12200 } else if (c == '(') { 12235 } else if (c == '(') {
12201 /* $(command) or $((arith)) */ 12236 /* $(command) or $((arith)) */
12202 if (pgetc_eatbnl() == '(') { 12237 if (pgetc_eatbnl() == '(') {
12203#if ENABLE_SH_MATH_SUPPORT 12238#if ENABLE_FEATURE_SH_MATH
12204 PARSEARITH(); 12239 PARSEARITH();
12205#else 12240#else
12206 raise_error_syntax("you disabled math support for $((arith)) syntax"); 12241 raise_error_syntax("you disabled math support for $((arith)) syntax");
@@ -12455,7 +12490,7 @@ parsebackq: {
12455 goto parsebackq_newreturn; 12490 goto parsebackq_newreturn;
12456} 12491}
12457 12492
12458#if ENABLE_SH_MATH_SUPPORT 12493#if ENABLE_FEATURE_SH_MATH
12459/* 12494/*
12460 * Parse an arithmetic expansion (indicate start of one and set state) 12495 * Parse an arithmetic expansion (indicate start of one and set state)
12461 */ 12496 */
@@ -13532,7 +13567,7 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13532 return 0; 13567 return 0;
13533} 13568}
13534 13569
13535#if ENABLE_SH_MATH_SUPPORT 13570#if ENABLE_FEATURE_SH_MATH
13536/* 13571/*
13537 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. 13572 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
13538 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. 13573 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
@@ -13871,15 +13906,6 @@ init(void)
13871//usage:#define ash_full_usage "\n\n" 13906//usage:#define ash_full_usage "\n\n"
13872//usage: "Unix shell interpreter" 13907//usage: "Unix shell interpreter"
13873 13908
13874//usage:#if ENABLE_FEATURE_SH_IS_ASH
13875//usage:# define sh_trivial_usage ash_trivial_usage
13876//usage:# define sh_full_usage ash_full_usage
13877//usage:#endif
13878//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13879//usage:# define bash_trivial_usage ash_trivial_usage
13880//usage:# define bash_full_usage ash_full_usage
13881//usage:#endif
13882
13883/* 13909/*
13884 * Process the shell command line arguments. 13910 * Process the shell command line arguments.
13885 */ 13911 */