aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2017-11-03 14:16:08 +0000
committerRon Yorston <rmy@pobox.com>2017-11-03 14:16:08 +0000
commitd6ce08aeb85b3698ddaa281016b70e16aeb9fb35 (patch)
tree02ad9bc0684859515fe891f3d6b0a1086e0db156 /shell
parentab450021a99ba66126cc6d668fb06ec3829a572b (diff)
parenta5060b8364faa7c677c8950f1315c451403b0660 (diff)
downloadbusybox-w32-d6ce08aeb85b3698ddaa281016b70e16aeb9fb35.tar.gz
busybox-w32-d6ce08aeb85b3698ddaa281016b70e16aeb9fb35.tar.bz2
busybox-w32-d6ce08aeb85b3698ddaa281016b70e16aeb9fb35.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c105
-rw-r--r--shell/ash_test/ash-parsing/comment2.right4
-rwxr-xr-xshell/ash_test/ash-parsing/comment2.tests13
-rw-r--r--shell/ash_test/ash-standalone/nofork_env.right9
-rwxr-xr-xshell/ash_test/ash-standalone/nofork_env.tests15
-rw-r--r--shell/hush.c17
-rw-r--r--shell/hush_test/hush-parsing/comment2.right4
-rwxr-xr-xshell/hush_test/hush-parsing/comment2.tests13
-rw-r--r--shell/hush_test/hush-standalone/nofork_env.right9
-rwxr-xr-xshell/hush_test/hush-standalone/nofork_env.tests15
10 files changed, 179 insertions, 25 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 0d65a225b..81845dc60 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -1399,16 +1399,9 @@ ash_msg_and_raise_error(const char *msg, ...)
1399} 1399}
1400 1400
1401/* 1401/*
1402 * Use '%m' to append error string on platforms that support it, '%s' and
1403 * strerror() on those that don't.
1404 *
1405 * 'fmt' must be a string literal. 1402 * 'fmt' must be a string literal.
1406 */ 1403 */
1407#ifdef HAVE_PRINTF_PERCENTM 1404#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1408#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %m", ##__VA_ARGS__)
1409#else
1410#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %s", ##__VA_ARGS__, strerror(errno))
1411#endif
1412 1405
1413static void raise_error_syntax(const char *) NORETURN; 1406static void raise_error_syntax(const char *) NORETURN;
1414static void 1407static void
@@ -2474,8 +2467,11 @@ listsetvar(struct strlist *list_set_var, int flags)
2474/* 2467/*
2475 * Generate a list of variables satisfying the given conditions. 2468 * Generate a list of variables satisfying the given conditions.
2476 */ 2469 */
2470#if !ENABLE_FEATURE_SH_NOFORK
2471# define listvars(on, off, lp, end) listvars(on, off, end)
2472#endif
2477static char ** 2473static char **
2478listvars(int on, int off, char ***end) 2474listvars(int on, int off, struct strlist *lp, char ***end)
2479{ 2475{
2480 struct var **vpp; 2476 struct var **vpp;
2481 struct var *vp; 2477 struct var *vp;
@@ -2488,12 +2484,40 @@ listvars(int on, int off, char ***end)
2488 do { 2484 do {
2489 for (vp = *vpp; vp; vp = vp->next) { 2485 for (vp = *vpp; vp; vp = vp->next) {
2490 if ((vp->flags & mask) == on) { 2486 if ((vp->flags & mask) == on) {
2487#if ENABLE_FEATURE_SH_NOFORK
2488 /* If variable with the same name is both
2489 * exported and temporarily set for a command:
2490 * export ZVAR=5
2491 * ZVAR=6 printenv
2492 * then "ZVAR=6" will be both in vartab and
2493 * lp lists. Do not pass it twice to printenv.
2494 */
2495 struct strlist *lp1 = lp;
2496 while (lp1) {
2497 if (strcmp(lp1->text, vp->var_text) == 0)
2498 goto skip;
2499 lp1 = lp1->next;
2500 }
2501#endif
2491 if (ep == stackstrend()) 2502 if (ep == stackstrend())
2492 ep = growstackstr(); 2503 ep = growstackstr();
2493 *ep++ = (char*)vp->var_text; 2504 *ep++ = (char*)vp->var_text;
2505#if ENABLE_FEATURE_SH_NOFORK
2506 skip: ;
2507#endif
2494 } 2508 }
2495 } 2509 }
2496 } while (++vpp < vartab + VTABSIZE); 2510 } while (++vpp < vartab + VTABSIZE);
2511
2512#if ENABLE_FEATURE_SH_NOFORK
2513 while (lp) {
2514 if (ep == stackstrend())
2515 ep = growstackstr();
2516 *ep++ = lp->text;
2517 lp = lp->next;
2518 }
2519#endif
2520
2497 if (ep == stackstrend()) 2521 if (ep == stackstrend())
2498 ep = growstackstr(); 2522 ep = growstackstr();
2499 if (end) 2523 if (end)
@@ -8250,7 +8274,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
8250 int exerrno; 8274 int exerrno;
8251 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 8275 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8252 8276
8253 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 8277 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8254 if ((strchr(prog, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(prog, '\\'))) 8278 if ((strchr(prog, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(prog, '\\')))
8255#if ENABLE_FEATURE_SH_STANDALONE 8279#if ENABLE_FEATURE_SH_STANDALONE
8256 || (applet_no = find_applet_by_name(prog)) >= 0 8280 || (applet_no = find_applet_by_name(prog)) >= 0
@@ -10395,7 +10419,11 @@ evalcommand(union node *cmd, int flags)
10395 /* find_command() encodes applet_no as (-2 - applet_no) */ 10419 /* find_command() encodes applet_no as (-2 - applet_no) */
10396 int applet_no = (- cmdentry.u.index - 2); 10420 int applet_no = (- cmdentry.u.index - 2);
10397 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { 10421 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10398 listsetvar(varlist.list, VEXPORT|VSTACK); 10422 char **sv_environ;
10423
10424 INT_OFF;
10425 sv_environ = environ;
10426 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10399 /* 10427 /*
10400 * Run <applet>_main(). 10428 * Run <applet>_main().
10401 * Signals (^C) can't interrupt here. 10429 * Signals (^C) can't interrupt here.
@@ -10404,8 +10432,8 @@ evalcommand(union node *cmd, int flags)
10404 * and/or wait for user input ineligible for NOFORK: 10432 * and/or wait for user input ineligible for NOFORK:
10405 * for example, "yes" or "rm" (rm -i waits for input). 10433 * for example, "yes" or "rm" (rm -i waits for input).
10406 */ 10434 */
10407 INT_OFF;
10408 status = run_nofork_applet(applet_no, argv); 10435 status = run_nofork_applet(applet_no, argv);
10436 environ = sv_environ;
10409 /* 10437 /*
10410 * Try enabling NOFORK for "yes" applet. 10438 * Try enabling NOFORK for "yes" applet.
10411 * ^C _will_ stop it (write returns EINTR), 10439 * ^C _will_ stop it (write returns EINTR),
@@ -11344,7 +11372,7 @@ showvars(const char *sep_prefix, int on, int off)
11344 const char *sep; 11372 const char *sep;
11345 char **ep, **epend; 11373 char **ep, **epend;
11346 11374
11347 ep = listvars(on, off, &epend); 11375 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11348 qsort(ep, epend - ep, sizeof(char *), vpcmp); 11376 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11349 11377
11350 sep = *sep_prefix ? " " : sep_prefix; 11378 sep = *sep_prefix ? " " : sep_prefix;
@@ -11353,9 +11381,17 @@ showvars(const char *sep_prefix, int on, int off)
11353 const char *p; 11381 const char *p;
11354 const char *q; 11382 const char *q;
11355 11383
11356 p = strchrnul(*ep, '='); 11384 p = endofname(*ep);
11385/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11386 * makes "export -p" to have output not suitable for "eval":
11387 * import os
11388 * os.environ["test-test"]="test"
11389 * if os.fork() == 0:
11390 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11391 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11392 */
11357 q = nullstr; 11393 q = nullstr;
11358 if (*p) 11394 if (*p == '=')
11359 q = single_quote(++p); 11395 q = single_quote(++p);
11360 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); 11396 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11361 } 11397 }
@@ -13146,7 +13182,24 @@ expandstr(const char *ps, int syntax_type)
13146 13182
13147 saveprompt = doprompt; 13183 saveprompt = doprompt;
13148 doprompt = 0; 13184 doprompt = 0;
13149 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); 13185
13186 /* readtoken1() might die horribly.
13187 * Try a prompt with syntactically wrong command:
13188 * PS1='$(date "+%H:%M:%S) > '
13189 */
13190 {
13191 volatile int saveint;
13192 struct jmploc *volatile savehandler = exception_handler;
13193 struct jmploc jmploc;
13194 SAVE_INT(saveint);
13195 if (setjmp(jmploc.loc) == 0) {
13196 exception_handler = &jmploc;
13197 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
13198 }
13199 exception_handler = savehandler;
13200 RESTORE_INT(saveint);
13201 }
13202
13150 doprompt = saveprompt; 13203 doprompt = saveprompt;
13151 13204
13152 popfile(); 13205 popfile();
@@ -13215,7 +13268,7 @@ evalstring(char *s, int flags)
13215 13268
13216 exception_handler = savehandler; 13269 exception_handler = savehandler;
13217 if (ex) 13270 if (ex)
13218 longjmp(exception_handler->loc, ex); 13271 longjmp(exception_handler->loc, ex);
13219 13272
13220 return status; 13273 return status;
13221} 13274}
@@ -14069,8 +14122,8 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14069 } 14122 }
14070 } else { 14123 } else {
14071 char *modestr = *argptr; 14124 char *modestr = *argptr;
14072 /* numeric umasks are taken as-is */ 14125 /* numeric umasks are taken as-is */
14073 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ 14126 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
14074 if (!isdigit(modestr[0])) 14127 if (!isdigit(modestr[0]))
14075 mask ^= 0777; 14128 mask ^= 0777;
14076 mask = bb_parse_mode(modestr, mask); 14129 mask = bb_parse_mode(modestr, mask);
@@ -14236,8 +14289,18 @@ init(void)
14236 } 14289 }
14237#endif 14290#endif
14238 for (envp = environ; envp && *envp; envp++) { 14291 for (envp = environ; envp && *envp; envp++) {
14239 p = endofname(*envp); 14292/* Used to have
14240 if (p != *envp && *p == '=') { 14293 * p = endofname(*envp);
14294 * if (p != *envp && *p == '=') {
14295 * here to weed out badly-named variables, but this breaks
14296 * scenarios where people do want them passed to children:
14297 * import os
14298 * os.environ["test-test"]="test"
14299 * if os.fork() == 0:
14300 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
14301 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
14302 */
14303 if (strchr(*envp, '=')) {
14241 setvareq(*envp, VEXPORT|VTEXTFIXED); 14304 setvareq(*envp, VEXPORT|VTEXTFIXED);
14242 } 14305 }
14243 } 14306 }
diff --git a/shell/ash_test/ash-parsing/comment2.right b/shell/ash_test/ash-parsing/comment2.right
new file mode 100644
index 000000000..ee6e49a5a
--- /dev/null
+++ b/shell/ash_test/ash-parsing/comment2.right
@@ -0,0 +1,4 @@
1Ok1
2Ok2
3Ok5
4Ok6
diff --git a/shell/ash_test/ash-parsing/comment2.tests b/shell/ash_test/ash-parsing/comment2.tests
new file mode 100755
index 000000000..b7adad96a
--- /dev/null
+++ b/shell/ash_test/ash-parsing/comment2.tests
@@ -0,0 +1,13 @@
1echo "`echo Ok1 #comment is ignored`"
2echo `echo Ok2 #comment is ignored`
3#
4# Surprisingly, bash does not handle comments in $()
5# the same way as in ``. "#" causes the rest of the line, _including_ )",
6# to be ignored. These lines would cause an error:
7#echo "$(echo Ok3 #comment is ignored)"
8#echo $(echo Ok4 #comment is ignored)
9#
10echo "$(echo Ok5 #comment is ignored
11)"
12echo $(echo Ok6 #comment is ignored
13)
diff --git a/shell/ash_test/ash-standalone/nofork_env.right b/shell/ash_test/ash-standalone/nofork_env.right
new file mode 100644
index 000000000..3f16ff458
--- /dev/null
+++ b/shell/ash_test/ash-standalone/nofork_env.right
@@ -0,0 +1,9 @@
1ZVAR=1
2ZVAR=2
3ZVAR=3
4ZVAR=4
5ZVAR=5
6ZVAR=6
7ZVAR=7
8ZVAR=8
9Ok:0
diff --git a/shell/ash_test/ash-standalone/nofork_env.tests b/shell/ash_test/ash-standalone/nofork_env.tests
new file mode 100755
index 000000000..111e564d2
--- /dev/null
+++ b/shell/ash_test/ash-standalone/nofork_env.tests
@@ -0,0 +1,15 @@
1# ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables
2
3(export ZVAR=1; printenv) | grep ^ZVAR=
4(ZVAR=2 printenv) | grep ^ZVAR=
5
6(export ZVAR=3; env) | grep ^ZVAR=
7(ZVAR=4 env) | grep ^ZVAR=
8
9export ZVAR=5; printenv | grep ^ZVAR=
10ZVAR=6 printenv | grep ^ZVAR=
11
12export ZVAR=7; env | grep ^ZVAR=
13ZVAR=8 env | grep ^ZVAR=
14
15echo Ok:$?
diff --git a/shell/hush.c b/shell/hush.c
index d27550ba0..708555ac4 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -5140,14 +5140,23 @@ static struct pipe *parse_stream(char **pstring,
5140 case '#': 5140 case '#':
5141 if (dest.length == 0 && !dest.has_quoted_part) { 5141 if (dest.length == 0 && !dest.has_quoted_part) {
5142 /* skip "#comment" */ 5142 /* skip "#comment" */
5143 /* note: we do not add it to &ctx.as_string */
5144/* TODO: in bash:
5145 * comment inside $() goes to the next \n, even inside quoted string (!):
5146 * cmd "$(cmd2 #comment)" - syntax error
5147 * cmd "`cmd2 #comment`" - ok
5148 * We accept both (comment ends where command subst ends, in both cases).
5149 */
5143 while (1) { 5150 while (1) {
5144 ch = i_peek(input); 5151 ch = i_peek(input);
5145 if (ch == EOF || ch == '\n') 5152 if (ch == '\n') {
5153 nommu_addchr(&ctx.as_string, '\n');
5154 break;
5155 }
5156 ch = i_getch(input);
5157 if (ch == EOF)
5146 break; 5158 break;
5147 i_getch(input);
5148 /* note: we do not add it to &ctx.as_string */
5149 } 5159 }
5150 nommu_addchr(&ctx.as_string, '\n');
5151 continue; /* back to top of while (1) */ 5160 continue; /* back to top of while (1) */
5152 } 5161 }
5153 break; 5162 break;
diff --git a/shell/hush_test/hush-parsing/comment2.right b/shell/hush_test/hush-parsing/comment2.right
new file mode 100644
index 000000000..ee6e49a5a
--- /dev/null
+++ b/shell/hush_test/hush-parsing/comment2.right
@@ -0,0 +1,4 @@
1Ok1
2Ok2
3Ok5
4Ok6
diff --git a/shell/hush_test/hush-parsing/comment2.tests b/shell/hush_test/hush-parsing/comment2.tests
new file mode 100755
index 000000000..b7adad96a
--- /dev/null
+++ b/shell/hush_test/hush-parsing/comment2.tests
@@ -0,0 +1,13 @@
1echo "`echo Ok1 #comment is ignored`"
2echo `echo Ok2 #comment is ignored`
3#
4# Surprisingly, bash does not handle comments in $()
5# the same way as in ``. "#" causes the rest of the line, _including_ )",
6# to be ignored. These lines would cause an error:
7#echo "$(echo Ok3 #comment is ignored)"
8#echo $(echo Ok4 #comment is ignored)
9#
10echo "$(echo Ok5 #comment is ignored
11)"
12echo $(echo Ok6 #comment is ignored
13)
diff --git a/shell/hush_test/hush-standalone/nofork_env.right b/shell/hush_test/hush-standalone/nofork_env.right
new file mode 100644
index 000000000..3f16ff458
--- /dev/null
+++ b/shell/hush_test/hush-standalone/nofork_env.right
@@ -0,0 +1,9 @@
1ZVAR=1
2ZVAR=2
3ZVAR=3
4ZVAR=4
5ZVAR=5
6ZVAR=6
7ZVAR=7
8ZVAR=8
9Ok:0
diff --git a/shell/hush_test/hush-standalone/nofork_env.tests b/shell/hush_test/hush-standalone/nofork_env.tests
new file mode 100755
index 000000000..111e564d2
--- /dev/null
+++ b/shell/hush_test/hush-standalone/nofork_env.tests
@@ -0,0 +1,15 @@
1# ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables
2
3(export ZVAR=1; printenv) | grep ^ZVAR=
4(ZVAR=2 printenv) | grep ^ZVAR=
5
6(export ZVAR=3; env) | grep ^ZVAR=
7(ZVAR=4 env) | grep ^ZVAR=
8
9export ZVAR=5; printenv | grep ^ZVAR=
10ZVAR=6 printenv | grep ^ZVAR=
11
12export ZVAR=7; env | grep ^ZVAR=
13ZVAR=8 env | grep ^ZVAR=
14
15echo Ok:$?