summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-05-04 00:14:30 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-05-04 00:14:30 +0200
commitcb6ff25afeb2daeebcb435c9766215061d3c75cb (patch)
treee185f3ff23622f171d52fb783ad4b23626f26bfc /shell
parente19e1935a33b117e2ee6daf9b2d79c00603333c7 (diff)
downloadbusybox-w32-cb6ff25afeb2daeebcb435c9766215061d3c75cb.tar.gz
busybox-w32-cb6ff25afeb2daeebcb435c9766215061d3c75cb.tar.bz2
busybox-w32-cb6ff25afeb2daeebcb435c9766215061d3c75cb.zip
hush: fix bug where in "var=val func" var's value is not visible in func
function old new delta unset_local_var - 168 +168 set_vars_all_and_save_old - 87 +87 get_ptr_to_local_var - 77 +77 free_strings_and_unset - 53 +53 builtin_export 266 274 +8 get_local_var_value 31 33 +2 putenv_all 27 - -27 free_strings_and_unsetenv 53 - -53 get_local_var 68 - -68 run_list 2475 2350 -125 builtin_unset 380 220 -160 ------------------------------------------------------------------------------ (add/remove: 4/3 grow/shrink: 2/2 up/down: 395/-433) Total: -38 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c199
-rw-r--r--shell/hush_test/hush-misc/env_and_func.right (renamed from shell/hush_test/hush-bugs/env_and_func.right)0
-rwxr-xr-xshell/hush_test/hush-misc/env_and_func.tests (renamed from shell/hush_test/hush-bugs/env_and_func.tests)2
3 files changed, 109 insertions, 92 deletions
diff --git a/shell/hush.c b/shell/hush.c
index c6e940548..0890f0977 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -56,7 +56,7 @@
56 * 56 *
57 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 57 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
58 */ 58 */
59#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 59#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
60#include <glob.h> 60#include <glob.h>
61/* #include <dmalloc.h> */ 61/* #include <dmalloc.h> */
62#if ENABLE_HUSH_CASE 62#if ENABLE_HUSH_CASE
@@ -65,7 +65,7 @@
65#include "math.h" 65#include "math.h"
66#include "match.h" 66#include "match.h"
67#ifndef PIPE_BUF 67#ifndef PIPE_BUF
68# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 68# define PIPE_BUF 4096 /* amount of buffering in a pipe */
69#endif 69#endif
70 70
71 71
@@ -138,6 +138,8 @@
138 138
139#define SPECIAL_VAR_SYMBOL 3 139#define SPECIAL_VAR_SYMBOL 3
140 140
141struct variable;
142
141static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER; 143static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER;
142 144
143/* This supports saving pointers malloced in vfork child, 145/* This supports saving pointers malloced in vfork child,
@@ -146,7 +148,7 @@ static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER;
146#if !BB_MMU 148#if !BB_MMU
147typedef struct nommu_save_t { 149typedef struct nommu_save_t {
148 char **new_env; 150 char **new_env;
149 char **old_env; 151 struct variable *old_vars;
150 char **argv; 152 char **argv;
151 char **argv_from_re_execing; 153 char **argv_from_re_execing;
152} nommu_save_t; 154} nommu_save_t;
@@ -282,8 +284,8 @@ struct command {
282#if ENABLE_HUSH_FUNCTIONS 284#if ENABLE_HUSH_FUNCTIONS
283# define GRP_FUNCTION 2 285# define GRP_FUNCTION 2
284#endif 286#endif
285 struct pipe *group; /* if non-NULL, this "command" is { list }, 287 /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */
286 * ( list ), or a compound statement */ 288 struct pipe *group;
287#if !BB_MMU 289#if !BB_MMU
288 char *group_as_string; 290 char *group_as_string;
289#endif 291#endif
@@ -883,6 +885,7 @@ static char **xx_add_strings_to_strings(int lineno, char **strings, char **add,
883 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup) 885 xx_add_strings_to_strings(__LINE__, strings, add, need_to_dup)
884#endif 886#endif
885 887
888/* Note: takes ownership of "add" ptr (it is not strdup'ed) */
886static char **add_string_to_strings(char **strings, char *add) 889static char **add_string_to_strings(char **strings, char *add)
887{ 890{
888 char *v[2]; 891 char *v[2];
@@ -901,44 +904,9 @@ static char **xx_add_string_to_strings(int lineno, char **strings, char *add)
901 xx_add_string_to_strings(__LINE__, strings, add) 904 xx_add_string_to_strings(__LINE__, strings, add)
902#endif 905#endif
903 906
904static void putenv_all(char **strings) 907static int unset_local_var(const char *name);
905{
906 if (!strings)
907 return;
908 while (*strings) {
909 debug_printf_env("putenv '%s'\n", *strings);
910 putenv(*strings++);
911 }
912}
913
914static char **putenv_all_and_save_old(char **strings)
915{
916 char **old = NULL;
917 char **s = strings;
918
919 if (!strings)
920 return old;
921 while (*strings) {
922 char *v, *eq;
923
924 eq = strchr(*strings, '=');
925 if (eq) {
926 *eq = '\0';
927 v = getenv(*strings);
928 *eq = '=';
929 if (v) {
930 /* v points to VAL in VAR=VAL, go back to VAR */
931 v -= (eq - *strings) + 1;
932 old = add_string_to_strings(old, v);
933 }
934 }
935 strings++;
936 }
937 putenv_all(s);
938 return old;
939}
940 908
941static void free_strings_and_unsetenv(char **strings, int unset) 909static void free_strings_and_unset(char **strings, int unset)
942{ 910{
943 char **v; 911 char **v;
944 912
@@ -948,8 +916,7 @@ static void free_strings_and_unsetenv(char **strings, int unset)
948 v = strings; 916 v = strings;
949 while (*v) { 917 while (*v) {
950 if (unset) { 918 if (unset) {
951 debug_printf_env("unsetenv '%s'\n", *v); 919 unset_local_var(*v);
952 bb_unsetenv(*v);
953 } 920 }
954 free(*v++); 921 free(*v++);
955 } 922 }
@@ -958,7 +925,7 @@ static void free_strings_and_unsetenv(char **strings, int unset)
958 925
959static void free_strings(char **strings) 926static void free_strings(char **strings)
960{ 927{
961 free_strings_and_unsetenv(strings, 0); 928 free_strings_and_unset(strings, 0);
962} 929}
963 930
964 931
@@ -1242,27 +1209,38 @@ static const char *set_cwd(void)
1242} 1209}
1243 1210
1244 1211
1245/* Get/check local shell variables */ 1212/*
1246static struct variable *get_local_var(const char *name) 1213 * Shell and environment variable support
1214 */
1215static struct variable **get_ptr_to_local_var(const char *name)
1247{ 1216{
1217 struct variable **pp;
1248 struct variable *cur; 1218 struct variable *cur;
1249 int len; 1219 int len;
1250 1220
1251 if (!name)
1252 return NULL;
1253 len = strlen(name); 1221 len = strlen(name);
1254 for (cur = G.top_var; cur; cur = cur->next) { 1222 pp = &G.top_var;
1223 while ((cur = *pp) != NULL) {
1255 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=') 1224 if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
1256 return cur; 1225 return pp;
1226 pp = &cur->next;
1257 } 1227 }
1258 return NULL; 1228 return NULL;
1259} 1229}
1260 1230
1261static const char *get_local_var_value(const char *src) 1231static struct variable *get_local_var(const char *name)
1262{ 1232{
1263 struct variable *var = get_local_var(src); 1233 struct variable **pp = get_ptr_to_local_var(name);
1264 if (var) 1234 if (pp)
1265 return strchr(var->varstr, '=') + 1; 1235 return *pp;
1236 return NULL;
1237}
1238
1239static const char *get_local_var_value(const char *name)
1240{
1241 struct variable **pp = get_ptr_to_local_var(name);
1242 if (pp)
1243 return strchr((*pp)->varstr, '=') + 1;
1266 return NULL; 1244 return NULL;
1267} 1245}
1268 1246
@@ -1423,6 +1401,57 @@ static void arith_set_local_var(const char *name, const char *val, int flags)
1423 1401
1424 1402
1425/* 1403/*
1404 * Helpers for "var1=val1 var2=val2 cmd" feature
1405 */
1406static void add_vars(struct variable *var)
1407{
1408 struct variable *next;
1409
1410 while (var) {
1411 next = var->next;
1412 var->next = G.top_var;
1413 G.top_var = var;
1414 if (var->flg_export)
1415 putenv(var->varstr);
1416 var = next;
1417 }
1418}
1419
1420static struct variable *set_vars_all_and_save_old(char **strings)
1421{
1422 char **s;
1423 struct variable *old = NULL;
1424
1425 if (!strings)
1426 return old;
1427 s = strings;
1428 while (*s) {
1429 struct variable *var_p;
1430 struct variable **var_pp;
1431 char *eq;
1432
1433 eq = strchr(*s, '=');
1434 if (eq) {
1435 *eq = '\0';
1436 var_pp = get_ptr_to_local_var(*s);
1437 *eq = '=';
1438 if (var_pp) {
1439 /* Remove variable from global linked list */
1440 var_p = *var_pp;
1441 *var_pp = var_p->next;
1442 /* Add it to returned list */
1443 var_p->next = old;
1444 old = var_p;
1445 }
1446 set_local_var(*s, 1, 0);
1447 }
1448 s++;
1449 }
1450 return old;
1451}
1452
1453
1454/*
1426 * in_str support 1455 * in_str support
1427 */ 1456 */
1428static int static_get(struct in_str *i) 1457static int static_get(struct in_str *i)
@@ -2855,17 +2884,17 @@ static struct function *new_function(char *name)
2855 * body_as_string was not malloced! */ 2884 * body_as_string was not malloced! */
2856 if (funcp->body) { 2885 if (funcp->body) {
2857 free_pipe_list(funcp->body); 2886 free_pipe_list(funcp->body);
2858#if !BB_MMU 2887# if !BB_MMU
2859 free(funcp->body_as_string); 2888 free(funcp->body_as_string);
2860#endif 2889# endif
2861 } 2890 }
2862 } else { 2891 } else {
2863 debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name); 2892 debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name);
2864 cmd->argv[0] = funcp->name; 2893 cmd->argv[0] = funcp->name;
2865 cmd->group = funcp->body; 2894 cmd->group = funcp->body;
2866#if !BB_MMU 2895# if !BB_MMU
2867 cmd->group_as_string = funcp->body_as_string; 2896 cmd->group_as_string = funcp->body_as_string;
2868#endif 2897# endif
2869 } 2898 }
2870 goto skip; 2899 goto skip;
2871 } 2900 }
@@ -2892,9 +2921,9 @@ static void unset_func(const char *name)
2892 * body_as_string was not malloced! */ 2921 * body_as_string was not malloced! */
2893 if (funcp->body) { 2922 if (funcp->body) {
2894 free_pipe_list(funcp->body); 2923 free_pipe_list(funcp->body);
2895#if !BB_MMU 2924# if !BB_MMU
2896 free(funcp->body_as_string); 2925 free(funcp->body_as_string);
2897#endif 2926# endif
2898 } 2927 }
2899 free(funcp); 2928 free(funcp);
2900 break; 2929 break;
@@ -2903,10 +2932,10 @@ static void unset_func(const char *name)
2903 } 2932 }
2904} 2933}
2905 2934
2906#if BB_MMU 2935# if BB_MMU
2907#define exec_function(nommu_save, funcp, argv) \ 2936#define exec_function(nommu_save, funcp, argv) \
2908 exec_function(funcp, argv) 2937 exec_function(funcp, argv)
2909#endif 2938# endif
2910static void exec_function(nommu_save_t *nommu_save, 2939static void exec_function(nommu_save_t *nommu_save,
2911 const struct function *funcp, 2940 const struct function *funcp,
2912 char **argv) NORETURN; 2941 char **argv) NORETURN;
@@ -2938,37 +2967,31 @@ static int run_function(const struct function *funcp, char **argv)
2938{ 2967{
2939 int rc; 2968 int rc;
2940 save_arg_t sv; 2969 save_arg_t sv;
2941#if ENABLE_HUSH_FUNCTIONS
2942 smallint sv_flg; 2970 smallint sv_flg;
2943#endif
2944 2971
2945 save_and_replace_G_args(&sv, argv); 2972 save_and_replace_G_args(&sv, argv);
2946#if ENABLE_HUSH_FUNCTIONS
2947 /* "we are in function, ok to use return" */ 2973 /* "we are in function, ok to use return" */
2948 sv_flg = G.flag_return_in_progress; 2974 sv_flg = G.flag_return_in_progress;
2949 G.flag_return_in_progress = -1; 2975 G.flag_return_in_progress = -1;
2950#endif
2951 2976
2952 /* On MMU, funcp->body is always non-NULL */ 2977 /* On MMU, funcp->body is always non-NULL */
2953#if !BB_MMU 2978# if !BB_MMU
2954 if (!funcp->body) { 2979 if (!funcp->body) {
2955 /* Function defined by -F */ 2980 /* Function defined by -F */
2956 parse_and_run_string(funcp->body_as_string); 2981 parse_and_run_string(funcp->body_as_string);
2957 rc = G.last_exitcode; 2982 rc = G.last_exitcode;
2958 } else 2983 } else
2959#endif 2984# endif
2960 { 2985 {
2961 rc = run_list(funcp->body); 2986 rc = run_list(funcp->body);
2962 } 2987 }
2963 2988
2964#if ENABLE_HUSH_FUNCTIONS
2965 G.flag_return_in_progress = sv_flg; 2989 G.flag_return_in_progress = sv_flg;
2966#endif
2967 restore_G_args(&sv, argv); 2990 restore_G_args(&sv, argv);
2968 2991
2969 return rc; 2992 return rc;
2970} 2993}
2971#endif 2994#endif /* ENABLE_HUSH_FUNCTIONS */
2972 2995
2973 2996
2974#if BB_MMU 2997#if BB_MMU
@@ -2998,11 +3021,13 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
2998 3021
2999 new_env = expand_assignments(argv, assignment_cnt); 3022 new_env = expand_assignments(argv, assignment_cnt);
3000#if BB_MMU 3023#if BB_MMU
3001 putenv_all(new_env); 3024 set_vars_all_and_save_old(new_env);
3002 free(new_env); /* optional */ 3025 free(new_env); /* optional */
3026 /* we can also destroy set_vars_all_and_save_old's return value,
3027 * to save memory */
3003#else 3028#else
3004 nommu_save->new_env = new_env; 3029 nommu_save->new_env = new_env;
3005 nommu_save->old_env = putenv_all_and_save_old(new_env); 3030 nommu_save->old_vars = set_vars_all_and_save_old(new_env);
3006#endif 3031#endif
3007 if (argv_expanded) { 3032 if (argv_expanded) {
3008 argv = argv_expanded; 3033 argv = argv_expanded;
@@ -3443,10 +3468,10 @@ static int run_pipe(struct pipe *pi)
3443 funcp = new_function(command->argv[0]); 3468 funcp = new_function(command->argv[0]);
3444 /* funcp->name is already set to argv[0] */ 3469 /* funcp->name is already set to argv[0] */
3445 funcp->body = command->group; 3470 funcp->body = command->group;
3446#if !BB_MMU 3471# if !BB_MMU
3447 funcp->body_as_string = command->group_as_string; 3472 funcp->body_as_string = command->group_as_string;
3448 command->group_as_string = NULL; 3473 command->group_as_string = NULL;
3449#endif 3474# endif
3450 command->group = NULL; 3475 command->group = NULL;
3451 command->argv[0] = NULL; 3476 command->argv[0] = NULL;
3452 debug_printf_exec("cmd %p has child func at %p\n", command, funcp); 3477 debug_printf_exec("cmd %p has child func at %p\n", command, funcp);
@@ -3481,7 +3506,7 @@ static int run_pipe(struct pipe *pi)
3481 enum { funcp = 0 }; 3506 enum { funcp = 0 };
3482#endif 3507#endif
3483 char **new_env = NULL; 3508 char **new_env = NULL;
3484 char **old_env = NULL; 3509 struct variable *old_vars = NULL;
3485 3510
3486 if (argv[command->assignment_cnt] == NULL) { 3511 if (argv[command->assignment_cnt] == NULL) {
3487 /* Assignments, but no command */ 3512 /* Assignments, but no command */
@@ -3529,7 +3554,7 @@ static int run_pipe(struct pipe *pi)
3529 rcode = setup_redirects(command, squirrel); 3554 rcode = setup_redirects(command, squirrel);
3530 if (rcode == 0) { 3555 if (rcode == 0) {
3531 new_env = expand_assignments(argv, command->assignment_cnt); 3556 new_env = expand_assignments(argv, command->assignment_cnt);
3532 old_env = putenv_all_and_save_old(new_env); 3557 old_vars = set_vars_all_and_save_old(new_env);
3533 if (!funcp) { 3558 if (!funcp) {
3534 debug_printf_exec(": builtin '%s' '%s'...\n", 3559 debug_printf_exec(": builtin '%s' '%s'...\n",
3535 x->cmd, argv_expanded[1]); 3560 x->cmd, argv_expanded[1]);
@@ -3548,11 +3573,8 @@ static int run_pipe(struct pipe *pi)
3548 clean_up_and_ret: 3573 clean_up_and_ret:
3549#endif 3574#endif
3550 restore_redirects(squirrel); 3575 restore_redirects(squirrel);
3551 free_strings_and_unsetenv(new_env, 1); 3576 free_strings_and_unset(new_env, 1);
3552 putenv_all(old_env); 3577 add_vars(old_vars);
3553 /* Free the pointers, but the strings themselves
3554 * are in environ now, don't use free_strings! */
3555 free(old_env);
3556 clean_up_and_ret1: 3578 clean_up_and_ret1:
3557 free(argv_expanded); 3579 free(argv_expanded);
3558 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 3580 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
@@ -3567,7 +3589,7 @@ static int run_pipe(struct pipe *pi)
3567 rcode = setup_redirects(command, squirrel); 3589 rcode = setup_redirects(command, squirrel);
3568 if (rcode == 0) { 3590 if (rcode == 0) {
3569 new_env = expand_assignments(argv, command->assignment_cnt); 3591 new_env = expand_assignments(argv, command->assignment_cnt);
3570 old_env = putenv_all_and_save_old(new_env); 3592 old_vars = set_vars_all_and_save_old(new_env);
3571 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", 3593 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
3572 argv_expanded[0], argv_expanded[1]); 3594 argv_expanded[0], argv_expanded[1]);
3573 rcode = run_nofork_applet(i, argv_expanded); 3595 rcode = run_nofork_applet(i, argv_expanded);
@@ -3592,7 +3614,7 @@ static int run_pipe(struct pipe *pi)
3592#if !BB_MMU 3614#if !BB_MMU
3593 volatile nommu_save_t nommu_save; 3615 volatile nommu_save_t nommu_save;
3594 nommu_save.new_env = NULL; 3616 nommu_save.new_env = NULL;
3595 nommu_save.old_env = NULL; 3617 nommu_save.old_vars = NULL;
3596 nommu_save.argv = NULL; 3618 nommu_save.argv = NULL;
3597 nommu_save.argv_from_re_execing = NULL; 3619 nommu_save.argv_from_re_execing = NULL;
3598#endif 3620#endif
@@ -3665,11 +3687,8 @@ static int run_pipe(struct pipe *pi)
3665 /* Clean up after vforked child */ 3687 /* Clean up after vforked child */
3666 free(nommu_save.argv); 3688 free(nommu_save.argv);
3667 free(nommu_save.argv_from_re_execing); 3689 free(nommu_save.argv_from_re_execing);
3668 free_strings_and_unsetenv(nommu_save.new_env, 1); 3690 free_strings_and_unset(nommu_save.new_env, 1);
3669 putenv_all(nommu_save.old_env); 3691 add_vars(nommu_save.old_vars);
3670 /* Free the pointers, but the strings themselves
3671 * are in environ now, don't use free_strings! */
3672 free(nommu_save.old_env);
3673#endif 3692#endif
3674 free(argv_expanded); 3693 free(argv_expanded);
3675 argv_expanded = NULL; 3694 argv_expanded = NULL;
diff --git a/shell/hush_test/hush-bugs/env_and_func.right b/shell/hush_test/hush-misc/env_and_func.right
index 4a1545058..4a1545058 100644
--- a/shell/hush_test/hush-bugs/env_and_func.right
+++ b/shell/hush_test/hush-misc/env_and_func.right
diff --git a/shell/hush_test/hush-bugs/env_and_func.tests b/shell/hush_test/hush-misc/env_and_func.tests
index d62c1af40..1d4eaf3a7 100755
--- a/shell/hush_test/hush-bugs/env_and_func.tests
+++ b/shell/hush_test/hush-misc/env_and_func.tests
@@ -1,5 +1,3 @@
1# UNFIXED BUG
2
3var=old 1var=old
4f() { echo "var=$var"; } 2f() { echo "var=$var"; }
5var=val f 3var=val f