summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-14 16:23:23 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-14 16:23:23 +0000
commit764d59d48848121d89b31ddecf0130ce24a4d91b (patch)
tree5ab700c4cbc8e39405bb97e7ad1c73a083161cfe /shell/hush.c
parent03eb8bf6ce2cef8f30402b7c2b18e8479f9da1ea (diff)
downloadbusybox-w32-764d59d48848121d89b31ddecf0130ce24a4d91b.tar.gz
busybox-w32-764d59d48848121d89b31ddecf0130ce24a4d91b.tar.bz2
busybox-w32-764d59d48848121d89b31ddecf0130ce24a4d91b.zip
hush: more fixes to variable expansion, more testcases
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c69
1 files changed, 40 insertions, 29 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 803970b57..87e003db4 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1308,6 +1308,8 @@ static void pseudo_exec_argv(char **argv)
1308 _exit(EXIT_SUCCESS); 1308 _exit(EXIT_SUCCESS);
1309 } 1309 }
1310 1310
1311 argv = do_variable_expansion(argv);
1312
1311 /* 1313 /*
1312 * Check if the command matches any of the builtins. 1314 * Check if the command matches any of the builtins.
1313 * Depending on context, this might be redundant. But it's 1315 * Depending on context, this might be redundant. But it's
@@ -1316,7 +1318,7 @@ static void pseudo_exec_argv(char **argv)
1316 */ 1318 */
1317 for (x = bltins; x->cmd; x++) { 1319 for (x = bltins; x->cmd; x++) {
1318 if (strcmp(argv[0], x->cmd) == 0) { 1320 if (strcmp(argv[0], x->cmd) == 0) {
1319 debug_printf("builtin exec %s\n", argv[0]); 1321 debug_printf_exec("running builtin '%s'\n", argv[0]);
1320 rcode = x->function(argv); 1322 rcode = x->function(argv);
1321 fflush(stdout); 1323 fflush(stdout);
1322 _exit(rcode); 1324 _exit(rcode);
@@ -1334,6 +1336,7 @@ static void pseudo_exec_argv(char **argv)
1334 * to find ourself... */ 1336 * to find ourself... */
1335#if ENABLE_FEATURE_SH_STANDALONE 1337#if ENABLE_FEATURE_SH_STANDALONE
1336 debug_printf("running applet %s\n", argv[0]); 1338 debug_printf("running applet %s\n", argv[0]);
1339// FIXME: check NOEXEC bit, and EXEC if not set!
1337 run_applet_and_exit(argv[0], argv); 1340 run_applet_and_exit(argv[0], argv);
1338// is it ok that run_applet_and_exit() does exit(), not _exit()? 1341// is it ok that run_applet_and_exit() does exit(), not _exit()?
1339// NB: IIRC on NOMMU we are after _vfork_, not fork! 1342// NB: IIRC on NOMMU we are after _vfork_, not fork!
@@ -1674,6 +1677,7 @@ static int run_pipe_real(struct pipe *pi)
1674 } 1677 }
1675 1678
1676 if (single_fg && child->argv != NULL) { 1679 if (single_fg && child->argv != NULL) {
1680 char **argv_expanded, **free_me;
1677 char **argv = child->argv; 1681 char **argv = child->argv;
1678 1682
1679 for (i = 0; is_assignment(argv[i]); i++) 1683 for (i = 0; is_assignment(argv[i]); i++)
@@ -1714,16 +1718,7 @@ static int run_pipe_real(struct pipe *pi)
1714 putenv(xstrdup(p)); 1718 putenv(xstrdup(p));
1715 } 1719 }
1716 } 1720 }
1717 if (child->sp) { 1721 free_me = NULL;
1718 char *str;
1719
1720 str = make_string(argv + i);
1721 debug_printf_exec(": parse_string_outer '%s'\n", str);
1722 parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
1723 free(str);
1724 debug_printf_exec("run_pipe_real return %d\n", last_return_code);
1725 return last_return_code;
1726 }
1727 for (x = bltins; x->cmd; x++) { 1722 for (x = bltins; x->cmd; x++) {
1728 if (strcmp(argv[i], x->cmd) == 0) { 1723 if (strcmp(argv[i], x->cmd) == 0) {
1729 if (x->function == builtin_exec && argv[i+1] == NULL) { 1724 if (x->function == builtin_exec && argv[i+1] == NULL) {
@@ -1739,7 +1734,11 @@ static int run_pipe_real(struct pipe *pi)
1739// TODO: fflush(NULL)? 1734// TODO: fflush(NULL)?
1740 setup_redirects(child, squirrel); 1735 setup_redirects(child, squirrel);
1741 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); 1736 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
1742 rcode = x->function(argv + i); 1737 argv_expanded = argv + i;
1738 if (child->sp) /* btw we can do it unconditionally... */
1739 free_me = argv_expanded = do_variable_expansion(argv + i);
1740 rcode = x->function(argv_expanded);
1741 free(free_me);
1743 restore_redirects(squirrel); 1742 restore_redirects(squirrel);
1744 debug_printf_exec("run_pipe_real return %d\n", rcode); 1743 debug_printf_exec("run_pipe_real return %d\n", rcode);
1745 return rcode; 1744 return rcode;
@@ -1750,9 +1749,13 @@ static int run_pipe_real(struct pipe *pi)
1750 const struct bb_applet *a = find_applet_by_name(argv[i]); 1749 const struct bb_applet *a = find_applet_by_name(argv[i]);
1751 if (a && a->nofork) { 1750 if (a && a->nofork) {
1752 setup_redirects(child, squirrel); 1751 setup_redirects(child, squirrel);
1753 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv[i], argv[i+1]);
1754 save_nofork_data(&nofork_save); 1752 save_nofork_data(&nofork_save);
1755 rcode = run_nofork_applet_prime(&nofork_save, a, argv + i); 1753 argv_expanded = argv + i;
1754 if (child->sp)
1755 free_me = argv_expanded = do_variable_expansion(argv + i);
1756 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
1757 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
1758 free(free_me);
1756 restore_redirects(squirrel); 1759 restore_redirects(squirrel);
1757 debug_printf_exec("run_pipe_real return %d\n", rcode); 1760 debug_printf_exec("run_pipe_real return %d\n", rcode);
1758 return rcode; 1761 return rcode;
@@ -2049,7 +2052,7 @@ static int run_list_real(struct pipe *pi)
2049 continue; 2052 continue;
2050 } 2053 }
2051 /* insert next value from for_lcur */ 2054 /* insert next value from for_lcur */
2052 //vda: does it need escaping? 2055 /* vda: does it need escaping? */
2053 pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); 2056 pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
2054 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; 2057 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
2055 } 2058 }
@@ -2359,7 +2362,13 @@ static void count_var_expansion_space(int *countp, int *lenp, char *arg)
2359 default: 2362 default:
2360 *p = '\0'; 2363 *p = '\0';
2361 arg[0] = first_ch & 0x7f; 2364 arg[0] = first_ch & 0x7f;
2362 val = lookup_param(arg); 2365 if (isdigit(arg[0])) {
2366 i = xatoi_u(arg);
2367 val = NULL;
2368 if (i < global_argc)
2369 val = global_argv[i];
2370 } else
2371 val = lookup_param(arg);
2363 arg[0] = first_ch; 2372 arg[0] = first_ch;
2364 *p = SPECIAL_VAR_SYMBOL; 2373 *p = SPECIAL_VAR_SYMBOL;
2365 2374
@@ -2380,7 +2389,7 @@ static void count_var_expansion_space(int *countp, int *lenp, char *arg)
2380 2389
2381/* Store given string, finalizing the word and starting new one whenever 2390/* Store given string, finalizing the word and starting new one whenever
2382 * we encounter ifs char(s). This is used for expanding variable values. 2391 * we encounter ifs char(s). This is used for expanding variable values.
2383 * End-of-string does NOT finalize word, because cases like echo -$VAR- */ 2392 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
2384static int expand_on_ifs(char **list, int n, char **posp, const char *str) 2393static int expand_on_ifs(char **list, int n, char **posp, const char *str)
2385{ 2394{
2386 char *pos = *posp; 2395 char *pos = *posp;
@@ -2390,15 +2399,14 @@ static int expand_on_ifs(char **list, int n, char **posp, const char *str)
2390 memcpy(pos, str, word_len); /* store non-ifs chars */ 2399 memcpy(pos, str, word_len); /* store non-ifs chars */
2391 pos += word_len; 2400 pos += word_len;
2392 str += word_len; 2401 str += word_len;
2393 if (!*str) /* EOL - do not finalize word */
2394 break;
2395 *pos++ = '\0';
2396 if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' "
2397 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2398 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2399 list[n++] = pos;
2400 } 2402 }
2401 if (!*str) break; /* EOL, not ifs char */ 2403 if (!*str) /* EOL - do not finalize word */
2404 break;
2405 *pos++ = '\0';
2406 if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' "
2407 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2408 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2409 list[n++] = pos;
2402 str += strspn(str, ifs); /* skip ifs chars */ 2410 str += strspn(str, ifs); /* skip ifs chars */
2403 } 2411 }
2404 *posp = pos; 2412 *posp = pos;
@@ -2478,7 +2486,13 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
2478 default: 2486 default:
2479 *p = '\0'; 2487 *p = '\0';
2480 arg[0] = first_ch & 0x7f; 2488 arg[0] = first_ch & 0x7f;
2481 val = lookup_param(arg); 2489 if (isdigit(arg[0])) {
2490 int i = xatoi_u(arg);
2491 val = NULL;
2492 if (i < global_argc)
2493 val = global_argv[i];
2494 } else
2495 val = lookup_param(arg);
2482 arg[0] = first_ch; 2496 arg[0] = first_ch;
2483 *p = SPECIAL_VAR_SYMBOL; 2497 *p = SPECIAL_VAR_SYMBOL;
2484 if (!(first_ch & 0x80)) { /* unquoted var */ 2498 if (!(first_ch & 0x80)) { /* unquoted var */
@@ -3541,9 +3555,6 @@ static void update_ifs_map(void)
3541 * from builtin_source() */ 3555 * from builtin_source() */
3542static int parse_stream_outer(struct in_str *inp, int parse_flag) 3556static int parse_stream_outer(struct in_str *inp, int parse_flag)
3543{ 3557{
3544// FIXME: '{ true | exit 3; echo $? }' is parsed as a whole,
3545// as a result $? is replaced by 0, not 3!
3546
3547 struct p_context ctx; 3558 struct p_context ctx;
3548 o_string temp = NULL_O_STRING; 3559 o_string temp = NULL_O_STRING;
3549 int rcode; 3560 int rcode;