diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-13 12:36:05 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-13 12:36:05 +0000 |
commit | f886fd2bc7b313d5616e88822387cc6fd6898f34 (patch) | |
tree | 6be3ac7ffd4337b7c2296337353778bff7483c99 | |
parent | d29084dd7d23cb0efe0732b22aa669adcc5eaa0e (diff) | |
download | busybox-w32-f886fd2bc7b313d5616e88822387cc6fd6898f34.tar.gz busybox-w32-f886fd2bc7b313d5616e88822387cc6fd6898f34.tar.bz2 busybox-w32-f886fd2bc7b313d5616e88822387cc6fd6898f34.zip |
hush: fix NOMMU bug (analogous to preceding commit for MMU)
-rw-r--r-- | TODO_config_nommu | 20 | ||||
-rw-r--r-- | shell/hush.c | 158 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_preserved.right | 6 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_preserved.tests | 8 |
4 files changed, 108 insertions, 84 deletions
diff --git a/TODO_config_nommu b/TODO_config_nommu index 8e13e1fe5..bdef3e91e 100644 --- a/TODO_config_nommu +++ b/TODO_config_nommu | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.12.0.svn | 3 | # Busybox version: 1.13.0.svn |
4 | # Wed Aug 20 00:24:07 2008 | 4 | # Mon Oct 13 14:30:37 2008 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | 7 | ||
@@ -13,8 +13,8 @@ CONFIG_HAVE_DOT_CONFIG=y | |||
13 | # General Configuration | 13 | # General Configuration |
14 | # | 14 | # |
15 | CONFIG_DESKTOP=y | 15 | CONFIG_DESKTOP=y |
16 | # CONFIG_EXTRA_COMPAT is not set | 16 | CONFIG_EXTRA_COMPAT=y |
17 | CONFIG_FEATURE_ASSUME_UNICODE=y | 17 | # CONFIG_FEATURE_ASSUME_UNICODE is not set |
18 | CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | 18 | CONFIG_FEATURE_BUFFERS_USE_MALLOC=y |
19 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 19 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
20 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 20 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
@@ -153,7 +153,7 @@ CONFIG_DD=y | |||
153 | CONFIG_FEATURE_DD_SIGNAL_HANDLING=y | 153 | CONFIG_FEATURE_DD_SIGNAL_HANDLING=y |
154 | CONFIG_FEATURE_DD_IBS_OBS=y | 154 | CONFIG_FEATURE_DD_IBS_OBS=y |
155 | CONFIG_DF=y | 155 | CONFIG_DF=y |
156 | CONFIG_FEATURE_DF_INODE=y | 156 | CONFIG_FEATURE_DF_FANCY=y |
157 | CONFIG_DIRNAME=y | 157 | CONFIG_DIRNAME=y |
158 | CONFIG_DOS2UNIX=y | 158 | CONFIG_DOS2UNIX=y |
159 | CONFIG_UNIX2DOS=y | 159 | CONFIG_UNIX2DOS=y |
@@ -283,6 +283,8 @@ CONFIG_FEATURE_RESIZE_PRINT=y | |||
283 | CONFIG_SETCONSOLE=y | 283 | CONFIG_SETCONSOLE=y |
284 | CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y | 284 | CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y |
285 | CONFIG_SETFONT=y | 285 | CONFIG_SETFONT=y |
286 | CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y | ||
287 | CONFIG_DEFAULT_SETFONT_DIR="" | ||
286 | CONFIG_SETKEYCODES=y | 288 | CONFIG_SETKEYCODES=y |
287 | CONFIG_SETLOGCONS=y | 289 | CONFIG_SETLOGCONS=y |
288 | CONFIG_SHOWKEY=y | 290 | CONFIG_SHOWKEY=y |
@@ -690,6 +692,10 @@ CONFIG_FEATURE_FANCY_PING=y | |||
690 | CONFIG_PSCAN=y | 692 | CONFIG_PSCAN=y |
691 | CONFIG_ROUTE=y | 693 | CONFIG_ROUTE=y |
692 | CONFIG_SENDMAIL=y | 694 | CONFIG_SENDMAIL=y |
695 | CONFIG_FEATURE_SENDMAIL_MAILX=y | ||
696 | CONFIG_FEATURE_SENDMAIL_MAILXX=y | ||
697 | CONFIG_FEATURE_SENDMAIL_SSL=y | ||
698 | CONFIG_FEATURE_SENDMAIL_CHARSET="utf-8" | ||
693 | CONFIG_FETCHMAIL=y | 699 | CONFIG_FETCHMAIL=y |
694 | CONFIG_SLATTACH=y | 700 | CONFIG_SLATTACH=y |
695 | CONFIG_TELNET=y | 701 | CONFIG_TELNET=y |
@@ -760,9 +766,9 @@ CONFIG_WATCH=y | |||
760 | # Shells | 766 | # Shells |
761 | # | 767 | # |
762 | # CONFIG_FEATURE_SH_IS_ASH is not set | 768 | # CONFIG_FEATURE_SH_IS_ASH is not set |
763 | # CONFIG_FEATURE_SH_IS_HUSH is not set | 769 | CONFIG_FEATURE_SH_IS_HUSH=y |
764 | # CONFIG_FEATURE_SH_IS_MSH is not set | 770 | # CONFIG_FEATURE_SH_IS_MSH is not set |
765 | CONFIG_FEATURE_SH_IS_NONE=y | 771 | # CONFIG_FEATURE_SH_IS_NONE is not set |
766 | # CONFIG_ASH is not set | 772 | # CONFIG_ASH is not set |
767 | # CONFIG_ASH_BASH_COMPAT is not set | 773 | # CONFIG_ASH_BASH_COMPAT is not set |
768 | # CONFIG_ASH_JOB_CONTROL is not set | 774 | # CONFIG_ASH_JOB_CONTROL is not set |
diff --git a/shell/hush.c b/shell/hush.c index b62350404..377f13aa4 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -103,6 +103,7 @@ | |||
103 | #define debug_printf_parse(...) do {} while (0) | 103 | #define debug_printf_parse(...) do {} while (0) |
104 | #define debug_print_tree(a, b) do {} while (0) | 104 | #define debug_print_tree(a, b) do {} while (0) |
105 | #define debug_printf_exec(...) do {} while (0) | 105 | #define debug_printf_exec(...) do {} while (0) |
106 | #define debug_printf_env(...) do {} while (0) | ||
106 | #define debug_printf_jobs(...) do {} while (0) | 107 | #define debug_printf_jobs(...) do {} while (0) |
107 | #define debug_printf_expand(...) do {} while (0) | 108 | #define debug_printf_expand(...) do {} while (0) |
108 | #define debug_printf_glob(...) do {} while (0) | 109 | #define debug_printf_glob(...) do {} while (0) |
@@ -122,6 +123,10 @@ | |||
122 | #define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__) | 123 | #define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__) |
123 | #endif | 124 | #endif |
124 | 125 | ||
126 | #ifndef debug_printf_env | ||
127 | #define debug_printf_env(...) fprintf(stderr, __VA_ARGS__) | ||
128 | #endif | ||
129 | |||
125 | #ifndef debug_printf_jobs | 130 | #ifndef debug_printf_jobs |
126 | #define debug_printf_jobs(...) fprintf(stderr, __VA_ARGS__) | 131 | #define debug_printf_jobs(...) fprintf(stderr, __VA_ARGS__) |
127 | #define DEBUG_JOBS 1 | 132 | #define DEBUG_JOBS 1 |
@@ -522,16 +527,21 @@ static void setup_string_in_str(struct in_str *i, const char *s); | |||
522 | static int free_pipe_list(struct pipe *head, int indent); | 527 | static int free_pipe_list(struct pipe *head, int indent); |
523 | static int free_pipe(struct pipe *pi, int indent); | 528 | static int free_pipe(struct pipe *pi, int indent); |
524 | /* really run the final data structures: */ | 529 | /* really run the final data structures: */ |
525 | static int setup_redirects(struct command *prog, int squirrel[]); | 530 | typedef struct nommu_save_t { |
526 | static int run_list(struct pipe *pi); | 531 | char **new_env; |
532 | char **old_env; | ||
533 | char **argv; | ||
534 | } nommu_save_t; | ||
527 | #if BB_MMU | 535 | #if BB_MMU |
528 | #define pseudo_exec_argv(ptr_ptrs2free, argv, assignment_cnt, argv_expanded) \ | 536 | #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ |
529 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) | 537 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) |
530 | #define pseudo_exec(ptr_ptrs2free, command, argv_expanded) \ | 538 | #define pseudo_exec(nommu_save, command, argv_expanded) \ |
531 | pseudo_exec(command, argv_expanded) | 539 | pseudo_exec(command, argv_expanded) |
532 | #endif | 540 | #endif |
533 | static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; | 541 | static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; |
534 | static void pseudo_exec(char ***ptr_ptrs2free, struct command *command, char **argv_expanded) NORETURN; | 542 | static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) NORETURN; |
543 | static int setup_redirects(struct command *prog, int squirrel[]); | ||
544 | static int run_list(struct pipe *pi); | ||
535 | static int run_pipe(struct pipe *pi); | 545 | static int run_pipe(struct pipe *pi); |
536 | /* data structure manipulation: */ | 546 | /* data structure manipulation: */ |
537 | static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); | 547 | static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); |
@@ -655,8 +665,10 @@ static void putenv_all(char **strings) | |||
655 | { | 665 | { |
656 | if (!strings) | 666 | if (!strings) |
657 | return; | 667 | return; |
658 | while (*strings) | 668 | while (*strings) { |
669 | debug_printf_env("putenv '%s'\n", *strings); | ||
659 | putenv(*strings++); | 670 | putenv(*strings++); |
671 | } | ||
660 | } | 672 | } |
661 | 673 | ||
662 | static char **putenv_all_and_save_old(char **strings) | 674 | static char **putenv_all_and_save_old(char **strings) |
@@ -667,10 +679,20 @@ static char **putenv_all_and_save_old(char **strings) | |||
667 | if (!strings) | 679 | if (!strings) |
668 | return old; | 680 | return old; |
669 | while (*strings) { | 681 | while (*strings) { |
670 | char *v = getenv(*strings++); | 682 | char *v, *eq; |
671 | if (!v) | 683 | |
672 | continue; | 684 | eq = strchr(*strings, '='); |
673 | old = add_string_to_strings(old, v); | 685 | if (eq) { |
686 | *eq = '\0'; | ||
687 | v = getenv(*strings); | ||
688 | *eq = '='; | ||
689 | if (v) { | ||
690 | /* v points to VAL in VAR=VAL, go back to VAR */ | ||
691 | v -= (eq - *strings) + 1; | ||
692 | old = add_string_to_strings(old, v); | ||
693 | } | ||
694 | } | ||
695 | strings++; | ||
674 | } | 696 | } |
675 | putenv_all(s); | 697 | putenv_all(s); |
676 | return old; | 698 | return old; |
@@ -687,21 +709,13 @@ static void free_strings_and_unsetenv(char **strings, int unset) | |||
687 | while (*v) { | 709 | while (*v) { |
688 | if (unset) { | 710 | if (unset) { |
689 | char *copy; | 711 | char *copy; |
690 | #if !BB_MMU | ||
691 | /* If this is a magic guard pointer, do not free it, | ||
692 | * and stop unsetting */ | ||
693 | if (*v == hush_version_str) { | ||
694 | unset = 0; | ||
695 | v++; | ||
696 | continue; | ||
697 | } | ||
698 | #endif | ||
699 | /* *strchrnul(*v, '=') = '\0'; -- BAD | 712 | /* *strchrnul(*v, '=') = '\0'; -- BAD |
700 | * In case *v was putenv'ed, we can't | 713 | * In case *v was putenv'ed, we can't |
701 | * unsetenv(*v) after taking out '=': | 714 | * unsetenv(*v) after taking out '=': |
702 | * it won't work, env is modified by taking out! | 715 | * it won't work, env is modified by taking out! |
703 | * horror :( */ | 716 | * horror :( */ |
704 | copy = xstrndup(*v, strchrnul(*v, '=') - *v); | 717 | copy = xstrndup(*v, strchrnul(*v, '=') - *v); |
718 | debug_printf_env("unsetenv '%s'\n", copy); | ||
705 | unsetenv(copy); | 719 | unsetenv(copy); |
706 | free(copy); | 720 | free(copy); |
707 | } | 721 | } |
@@ -1431,16 +1445,26 @@ static void restore_redirects(int squirrel[]) | |||
1431 | } | 1445 | } |
1432 | } | 1446 | } |
1433 | 1447 | ||
1448 | static char **expand_assignments(char **argv, int count) | ||
1449 | { | ||
1450 | int i; | ||
1451 | char **p = NULL; | ||
1452 | /* Expand assignments into one string each */ | ||
1453 | for (i = 0; i < count; i++) { | ||
1454 | p = add_string_to_strings(p, expand_string_to_string(argv[i])); | ||
1455 | } | ||
1456 | return p; | ||
1457 | } | ||
1434 | 1458 | ||
1435 | /* Called after [v]fork() in run_pipe(), or from builtin_exec(). | 1459 | /* Called after [v]fork() in run_pipe(), or from builtin_exec(). |
1436 | * Never returns. | 1460 | * Never returns. |
1437 | * XXX no exit() here. If you don't exec, use _exit instead. | 1461 | * XXX no exit() here. If you don't exec, use _exit instead. |
1438 | * The at_exit handlers apparently confuse the calling process, | 1462 | * The at_exit handlers apparently confuse the calling process, |
1439 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ | 1463 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ |
1440 | static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) | 1464 | static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) |
1441 | { | 1465 | { |
1442 | int i, rcode; | 1466 | int rcode; |
1443 | char *p; | 1467 | char **new_env; |
1444 | const struct built_in_command *x; | 1468 | const struct built_in_command *x; |
1445 | 1469 | ||
1446 | /* If a variable is assigned in a forest, and nobody listens, | 1470 | /* If a variable is assigned in a forest, and nobody listens, |
@@ -1449,24 +1473,20 @@ static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_ | |||
1449 | if (!argv[assignment_cnt]) | 1473 | if (!argv[assignment_cnt]) |
1450 | _exit(EXIT_SUCCESS); | 1474 | _exit(EXIT_SUCCESS); |
1451 | 1475 | ||
1452 | for (i = 0; i < assignment_cnt; i++) { | 1476 | new_env = expand_assignments(argv, assignment_cnt); |
1453 | debug_printf_exec("pid %d environment modification: %s\n", | 1477 | #if BB_MMU |
1454 | getpid(), *argv); | 1478 | putenv_all(new_env); |
1455 | p = expand_string_to_string(*argv); | 1479 | free(new_env); /* optional */ |
1456 | putenv(p); | 1480 | #else |
1457 | #if !BB_MMU | 1481 | nommu_save->new_env = new_env; |
1458 | *ptr_ptrs2free = add_string_to_strings(*ptr_ptrs2free, p); | 1482 | nommu_save->old_env = putenv_all_and_save_old(new_env); |
1459 | #endif | 1483 | #endif |
1460 | argv++; | ||
1461 | } | ||
1462 | if (argv_expanded) { | 1484 | if (argv_expanded) { |
1463 | argv = argv_expanded; | 1485 | argv = argv_expanded; |
1464 | } else { | 1486 | } else { |
1465 | argv = expand_strvec_to_strvec(argv); | 1487 | argv = expand_strvec_to_strvec(argv); |
1466 | #if !BB_MMU | 1488 | #if !BB_MMU |
1467 | /* Inserting magic guard pointer to not unsetenv junk later */ | 1489 | nommu_save->argv = argv; |
1468 | *ptr_ptrs2free = add_string_to_strings(*ptr_ptrs2free, (char*)hush_version_str); | ||
1469 | *ptr_ptrs2free = add_string_to_strings(*ptr_ptrs2free, (char*)argv); | ||
1470 | #endif | 1490 | #endif |
1471 | } | 1491 | } |
1472 | 1492 | ||
@@ -1512,10 +1532,10 @@ static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_ | |||
1512 | 1532 | ||
1513 | /* Called after [v]fork() in run_pipe() | 1533 | /* Called after [v]fork() in run_pipe() |
1514 | */ | 1534 | */ |
1515 | static void pseudo_exec(char ***ptr_ptrs2free, struct command *command, char **argv_expanded) | 1535 | static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) |
1516 | { | 1536 | { |
1517 | if (command->argv) | 1537 | if (command->argv) |
1518 | pseudo_exec_argv(ptr_ptrs2free, command->argv, command->assignment_cnt, argv_expanded); | 1538 | pseudo_exec_argv(nommu_save, command->argv, command->assignment_cnt, argv_expanded); |
1519 | 1539 | ||
1520 | if (command->group) { | 1540 | if (command->group) { |
1521 | #if !BB_MMU | 1541 | #if !BB_MMU |
@@ -1785,17 +1805,6 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) | |||
1785 | * Returns -1 only if started some children. IOW: we have to | 1805 | * Returns -1 only if started some children. IOW: we have to |
1786 | * mask out retvals of builtins etc with 0xff! | 1806 | * mask out retvals of builtins etc with 0xff! |
1787 | */ | 1807 | */ |
1788 | /* A little helper first */ | ||
1789 | static char **expand_assignments(char **argv, int count) | ||
1790 | { | ||
1791 | int i; | ||
1792 | char **p = NULL; | ||
1793 | /* Expand assignments into one string each */ | ||
1794 | for (i = 0; i < count; i++) { | ||
1795 | p = add_string_to_strings(p, expand_string_to_string(argv[i])); | ||
1796 | } | ||
1797 | return p; | ||
1798 | } | ||
1799 | static int run_pipe(struct pipe *pi) | 1808 | static int run_pipe(struct pipe *pi) |
1800 | { | 1809 | { |
1801 | int i; | 1810 | int i; |
@@ -1876,11 +1885,13 @@ static int run_pipe(struct pipe *pi) | |||
1876 | old_env = putenv_all_and_save_old(new_env); | 1885 | old_env = putenv_all_and_save_old(new_env); |
1877 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); | 1886 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); |
1878 | rcode = x->function(argv_expanded) & 0xff; | 1887 | rcode = x->function(argv_expanded) & 0xff; |
1879 | USE_FEATURE_SH_STANDALONE(clean_up_and_ret:) | 1888 | #if ENABLE_FEATURE_SH_STANDALONE |
1889 | clean_up_and_ret: | ||
1890 | #endif | ||
1880 | restore_redirects(squirrel); | 1891 | restore_redirects(squirrel); |
1881 | free_strings_and_unsetenv(new_env, 1); | 1892 | free_strings_and_unsetenv(new_env, 1); |
1882 | putenv_all(old_env); | 1893 | putenv_all(old_env); |
1883 | free_strings(old_env); | 1894 | free(old_env); /* not free_strings()! */ |
1884 | clean_up_and_ret1: | 1895 | clean_up_and_ret1: |
1885 | free(argv_expanded); | 1896 | free(argv_expanded); |
1886 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 1897 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
@@ -1915,12 +1926,11 @@ static int run_pipe(struct pipe *pi) | |||
1915 | 1926 | ||
1916 | for (i = 0; i < pi->num_cmds; i++) { | 1927 | for (i = 0; i < pi->num_cmds; i++) { |
1917 | #if !BB_MMU | 1928 | #if !BB_MMU |
1918 | /* Avoid confusion WHAT is volatile. Pointer is volatile, | 1929 | volatile nommu_save_t nommu_save; |
1919 | * not the stuff it points to. */ | 1930 | nommu_save.new_env = NULL; |
1920 | typedef char **ppchar_t; | 1931 | nommu_save.old_env = NULL; |
1921 | volatile ppchar_t shared_across_vfork = NULL; | 1932 | nommu_save.argv = NULL; |
1922 | #endif | 1933 | #endif |
1923 | |||
1924 | command = &(pi->cmds[i]); | 1934 | command = &(pi->cmds[i]); |
1925 | if (command->argv) { | 1935 | if (command->argv) { |
1926 | debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); | 1936 | debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); |
@@ -1966,15 +1976,18 @@ static int run_pipe(struct pipe *pi) | |||
1966 | set_jobctrl_sighandler(SIG_DFL); | 1976 | set_jobctrl_sighandler(SIG_DFL); |
1967 | set_misc_sighandler(SIG_DFL); | 1977 | set_misc_sighandler(SIG_DFL); |
1968 | signal(SIGCHLD, SIG_DFL); | 1978 | signal(SIGCHLD, SIG_DFL); |
1969 | /* comment how it sets env???? | 1979 | /* Stores to nommu_save list of env vars putenv'ed |
1970 | for single_and_fg, it's already set yes? */ | 1980 | * (NOMMU, on MMU we don't need that) */ |
1971 | pseudo_exec((char ***) &shared_across_vfork, command, argv_expanded); | 1981 | /* cast away volatility... */ |
1982 | pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded); | ||
1972 | /* pseudo_exec() does not return */ | 1983 | /* pseudo_exec() does not return */ |
1973 | } | 1984 | } |
1974 | /* parent */ | 1985 | /* parent */ |
1975 | #if !BB_MMU | 1986 | #if !BB_MMU |
1976 | //BUG: does not restore OLD env var contents | 1987 | /* Clean up after vforked child */ |
1977 | free_strings_and_unsetenv((char **)shared_across_vfork, 1); | 1988 | free(nommu_save.argv); |
1989 | free_strings_and_unsetenv(nommu_save.new_env, 1); | ||
1990 | putenv_all(nommu_save.old_env); | ||
1978 | #endif | 1991 | #endif |
1979 | free(argv_expanded); | 1992 | free(argv_expanded); |
1980 | argv_expanded = NULL; | 1993 | argv_expanded = NULL; |
@@ -2829,6 +2842,7 @@ static int set_local_var(char *str, int flg_export) | |||
2829 | free(str); | 2842 | free(str); |
2830 | return -1; | 2843 | return -1; |
2831 | } | 2844 | } |
2845 | debug_printf_env("%s: unsetenv '%s'\n", __func__, str); | ||
2832 | unsetenv(str); /* just in case */ | 2846 | unsetenv(str); /* just in case */ |
2833 | *value = '='; | 2847 | *value = '='; |
2834 | if (strcmp(cur->varstr, str) == 0) { | 2848 | if (strcmp(cur->varstr, str) == 0) { |
@@ -2858,8 +2872,10 @@ static int set_local_var(char *str, int flg_export) | |||
2858 | exp: | 2872 | exp: |
2859 | if (flg_export) | 2873 | if (flg_export) |
2860 | cur->flg_export = 1; | 2874 | cur->flg_export = 1; |
2861 | if (cur->flg_export) | 2875 | if (cur->flg_export) { |
2876 | debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); | ||
2862 | return putenv(cur->varstr); | 2877 | return putenv(cur->varstr); |
2878 | } | ||
2863 | return 0; | 2879 | return 0; |
2864 | } | 2880 | } |
2865 | 2881 | ||
@@ -2879,9 +2895,10 @@ static void unset_local_var(const char *name) | |||
2879 | bb_error_msg("%s: readonly variable", name); | 2895 | bb_error_msg("%s: readonly variable", name); |
2880 | return; | 2896 | return; |
2881 | } | 2897 | } |
2882 | /* prev is ok to use here because 1st variable, HUSH_VERSION, | 2898 | /* prev is ok to use here because 1st variable, HUSH_VERSION, |
2883 | * is ro, and we cannot reach this code on the 1st pass */ | 2899 | * is ro, and we cannot reach this code on the 1st pass */ |
2884 | prev->next = cur->next; | 2900 | prev->next = cur->next; |
2901 | debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr); | ||
2885 | unsetenv(cur->varstr); | 2902 | unsetenv(cur->varstr); |
2886 | if (!cur->max_len) | 2903 | if (!cur->max_len) |
2887 | free(cur->varstr); | 2904 | free(cur->varstr); |
@@ -3467,11 +3484,9 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3467 | endch = ")"; | 3484 | endch = ")"; |
3468 | command->subshell = 1; | 3485 | command->subshell = 1; |
3469 | } | 3486 | } |
3470 | #if 0 /* TODO function support */ | 3487 | //TODO if (ch == 'F') { /* function definition */ |
3471 | if (ch == 'F') { /* function definition */ | 3488 | // command->subshell = 2; |
3472 | command->subshell = 2; | 3489 | // } |
3473 | } | ||
3474 | #endif | ||
3475 | rcode = parse_stream(dest, &sub, input, endch); | 3490 | rcode = parse_stream(dest, &sub, input, endch); |
3476 | if (rcode == 0) { | 3491 | if (rcode == 0) { |
3477 | done_word(dest, &sub); /* finish off the final word in the subcontext */ | 3492 | done_word(dest, &sub); /* finish off the final word in the subcontext */ |
@@ -4175,6 +4190,7 @@ int hush_main(int argc, char **argv) | |||
4175 | /* Deal with HUSH_VERSION */ | 4190 | /* Deal with HUSH_VERSION */ |
4176 | G.shell_ver = const_shell_ver; /* copying struct here */ | 4191 | G.shell_ver = const_shell_ver; /* copying struct here */ |
4177 | G.top_var = &G.shell_ver; | 4192 | G.top_var = &G.shell_ver; |
4193 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | ||
4178 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ | 4194 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ |
4179 | /* Initialize our shell local variables with the values | 4195 | /* Initialize our shell local variables with the values |
4180 | * currently living in the environment */ | 4196 | * currently living in the environment */ |
@@ -4191,6 +4207,7 @@ int hush_main(int argc, char **argv) | |||
4191 | } | 4207 | } |
4192 | e++; | 4208 | e++; |
4193 | } | 4209 | } |
4210 | debug_printf_env("putenv '%s'\n", hush_version_str); | ||
4194 | putenv((char *)hush_version_str); /* reinstate HUSH_VERSION */ | 4211 | putenv((char *)hush_version_str); /* reinstate HUSH_VERSION */ |
4195 | 4212 | ||
4196 | #if ENABLE_FEATURE_EDITING | 4213 | #if ENABLE_FEATURE_EDITING |
@@ -4415,10 +4432,10 @@ static int builtin_exec(char **argv) | |||
4415 | return EXIT_SUCCESS; /* bash does this */ | 4432 | return EXIT_SUCCESS; /* bash does this */ |
4416 | { | 4433 | { |
4417 | #if !BB_MMU | 4434 | #if !BB_MMU |
4418 | char **ptrs2free = NULL; | 4435 | nommu_save_t dummy; |
4419 | #endif | 4436 | #endif |
4420 | // FIXME: if exec fails, bash does NOT exit! We do... | 4437 | // FIXME: if exec fails, bash does NOT exit! We do... |
4421 | pseudo_exec_argv(&ptrs2free, argv + 1, 0, NULL); | 4438 | pseudo_exec_argv(&dummy, argv + 1, 0, NULL); |
4422 | /* never returns */ | 4439 | /* never returns */ |
4423 | } | 4440 | } |
4424 | } | 4441 | } |
@@ -4462,6 +4479,7 @@ static int builtin_export(char **argv) | |||
4462 | var = get_local_var(name); | 4479 | var = get_local_var(name); |
4463 | if (var) { | 4480 | if (var) { |
4464 | var->flg_export = 1; | 4481 | var->flg_export = 1; |
4482 | debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr); | ||
4465 | putenv(var->varstr); | 4483 | putenv(var->varstr); |
4466 | } | 4484 | } |
4467 | /* bash does not return an error when trying to export | 4485 | /* bash does not return an error when trying to export |
diff --git a/shell/hush_test/hush-vars/var_preserved.right b/shell/hush_test/hush-vars/var_preserved.right index b0def4bb6..2a9917c99 100644 --- a/shell/hush_test/hush-vars/var_preserved.right +++ b/shell/hush_test/hush-vars/var_preserved.right | |||
@@ -1,4 +1,4 @@ | |||
1 | a=a | 1 | a=b |
2 | a=a | 2 | a=b |
3 | a=a | 3 | a=b |
4 | OK | 4 | OK |
diff --git a/shell/hush_test/hush-vars/var_preserved.tests b/shell/hush_test/hush-vars/var_preserved.tests index 132d387b4..1bddd870f 100755 --- a/shell/hush_test/hush-vars/var_preserved.tests +++ b/shell/hush_test/hush-vars/var_preserved.tests | |||
@@ -1,16 +1,16 @@ | |||
1 | export a=a | 1 | export a=b |
2 | 2 | ||
3 | # external program | 3 | # external program |
4 | a=b /bin/true | 4 | a=c /bin/true |
5 | env | grep ^a= | 5 | env | grep ^a= |
6 | 6 | ||
7 | # builtin | 7 | # builtin |
8 | a=b true | 8 | a=d true |
9 | env | grep ^a= | 9 | env | grep ^a= |
10 | 10 | ||
11 | # exec with redirection only | 11 | # exec with redirection only |
12 | # in bash, this leaks! | 12 | # in bash, this leaks! |
13 | a=b exec 1>&1 | 13 | a=e exec 1>&1 |
14 | env | grep ^a= | 14 | env | grep ^a= |
15 | 15 | ||
16 | echo OK | 16 | echo OK |