aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c105
1 files changed, 84 insertions, 21 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 }