aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-13 12:36:05 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-13 12:36:05 +0000
commitf886fd2bc7b313d5616e88822387cc6fd6898f34 (patch)
tree6be3ac7ffd4337b7c2296337353778bff7483c99
parentd29084dd7d23cb0efe0732b22aa669adcc5eaa0e (diff)
downloadbusybox-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_nommu20
-rw-r--r--shell/hush.c158
-rw-r--r--shell/hush_test/hush-vars/var_preserved.right6
-rwxr-xr-xshell/hush_test/hush-vars/var_preserved.tests8
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#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7 7
@@ -13,8 +13,8 @@ CONFIG_HAVE_DOT_CONFIG=y
13# General Configuration 13# General Configuration
14# 14#
15CONFIG_DESKTOP=y 15CONFIG_DESKTOP=y
16# CONFIG_EXTRA_COMPAT is not set 16CONFIG_EXTRA_COMPAT=y
17CONFIG_FEATURE_ASSUME_UNICODE=y 17# CONFIG_FEATURE_ASSUME_UNICODE is not set
18CONFIG_FEATURE_BUFFERS_USE_MALLOC=y 18CONFIG_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
153CONFIG_FEATURE_DD_SIGNAL_HANDLING=y 153CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
154CONFIG_FEATURE_DD_IBS_OBS=y 154CONFIG_FEATURE_DD_IBS_OBS=y
155CONFIG_DF=y 155CONFIG_DF=y
156CONFIG_FEATURE_DF_INODE=y 156CONFIG_FEATURE_DF_FANCY=y
157CONFIG_DIRNAME=y 157CONFIG_DIRNAME=y
158CONFIG_DOS2UNIX=y 158CONFIG_DOS2UNIX=y
159CONFIG_UNIX2DOS=y 159CONFIG_UNIX2DOS=y
@@ -283,6 +283,8 @@ CONFIG_FEATURE_RESIZE_PRINT=y
283CONFIG_SETCONSOLE=y 283CONFIG_SETCONSOLE=y
284CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y 284CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y
285CONFIG_SETFONT=y 285CONFIG_SETFONT=y
286CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y
287CONFIG_DEFAULT_SETFONT_DIR=""
286CONFIG_SETKEYCODES=y 288CONFIG_SETKEYCODES=y
287CONFIG_SETLOGCONS=y 289CONFIG_SETLOGCONS=y
288CONFIG_SHOWKEY=y 290CONFIG_SHOWKEY=y
@@ -690,6 +692,10 @@ CONFIG_FEATURE_FANCY_PING=y
690CONFIG_PSCAN=y 692CONFIG_PSCAN=y
691CONFIG_ROUTE=y 693CONFIG_ROUTE=y
692CONFIG_SENDMAIL=y 694CONFIG_SENDMAIL=y
695CONFIG_FEATURE_SENDMAIL_MAILX=y
696CONFIG_FEATURE_SENDMAIL_MAILXX=y
697CONFIG_FEATURE_SENDMAIL_SSL=y
698CONFIG_FEATURE_SENDMAIL_CHARSET="utf-8"
693CONFIG_FETCHMAIL=y 699CONFIG_FETCHMAIL=y
694CONFIG_SLATTACH=y 700CONFIG_SLATTACH=y
695CONFIG_TELNET=y 701CONFIG_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 769CONFIG_FEATURE_SH_IS_HUSH=y
764# CONFIG_FEATURE_SH_IS_MSH is not set 770# CONFIG_FEATURE_SH_IS_MSH is not set
765CONFIG_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);
522static int free_pipe_list(struct pipe *head, int indent); 527static int free_pipe_list(struct pipe *head, int indent);
523static int free_pipe(struct pipe *pi, int indent); 528static int free_pipe(struct pipe *pi, int indent);
524/* really run the final data structures: */ 529/* really run the final data structures: */
525static int setup_redirects(struct command *prog, int squirrel[]); 530typedef struct nommu_save_t {
526static 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
533static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; 541static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN;
534static void pseudo_exec(char ***ptr_ptrs2free, struct command *command, char **argv_expanded) NORETURN; 542static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) NORETURN;
543static int setup_redirects(struct command *prog, int squirrel[]);
544static int run_list(struct pipe *pi);
535static int run_pipe(struct pipe *pi); 545static int run_pipe(struct pipe *pi);
536/* data structure manipulation: */ 546/* data structure manipulation: */
537static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); 547static 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
662static char **putenv_all_and_save_old(char **strings) 674static 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
1448static 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) */
1440static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) 1464static 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 */
1515static void pseudo_exec(char ***ptr_ptrs2free, struct command *command, char **argv_expanded) 1535static 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 */
1789static 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}
1799static int run_pipe(struct pipe *pi) 1808static 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
1970for 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 @@
1a=a 1a=b
2a=a 2a=b
3a=a 3a=b
4OK 4OK
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 @@
1export a=a 1export a=b
2 2
3# external program 3# external program
4a=b /bin/true 4a=c /bin/true
5env | grep ^a= 5env | grep ^a=
6 6
7# builtin 7# builtin
8a=b true 8a=d true
9env | grep ^a= 9env | grep ^a=
10 10
11# exec with redirection only 11# exec with redirection only
12# in bash, this leaks! 12# in bash, this leaks!
13a=b exec 1>&1 13a=e exec 1>&1
14env | grep ^a= 14env | grep ^a=
15 15
16echo OK 16echo OK