aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c55
-rw-r--r--shell/shell_common.c15
-rw-r--r--shell/shell_common.h2
3 files changed, 40 insertions, 32 deletions
diff --git a/shell/hush.c b/shell/hush.c
index b3ae73b9b..b612c80da 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2248,9 +2248,12 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
2248 return NULL; 2248 return NULL;
2249} 2249}
2250 2250
2251#if (ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT) \
2252 || (ENABLE_HUSH_LINENO_VAR || ENABLE_HUSH_GETOPTS)
2251static void handle_changed_special_names(const char *name, unsigned name_len) 2253static void handle_changed_special_names(const char *name, unsigned name_len)
2252{ 2254{
2253 if (ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT 2255 if (ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2256 && G_interactive_fd
2254 && name_len == 3 && name[0] == 'P' && name[1] == 'S' 2257 && name_len == 3 && name[0] == 'P' && name[1] == 'S'
2255 ) { 2258 ) {
2256 cmdedit_update_prompt(); 2259 cmdedit_update_prompt();
@@ -2274,6 +2277,10 @@ static void handle_changed_special_names(const char *name, unsigned name_len)
2274#endif 2277#endif
2275 } 2278 }
2276} 2279}
2280#else
2281/* Do not even bother evaluating arguments */
2282# define handle_changed_special_names(...) ((void)0)
2283#endif
2277 2284
2278/* str holds "NAME=VAL" and is expected to be malloced. 2285/* str holds "NAME=VAL" and is expected to be malloced.
2279 * We take ownership of it. 2286 * We take ownership of it.
@@ -2289,6 +2296,7 @@ static int set_local_var(char *str, unsigned flags)
2289 char *free_me = NULL; 2296 char *free_me = NULL;
2290 char *eq_sign; 2297 char *eq_sign;
2291 int name_len; 2298 int name_len;
2299 int retval;
2292 unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT); 2300 unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT);
2293 2301
2294 eq_sign = strchr(str, '='); 2302 eq_sign = strchr(str, '=');
@@ -2402,24 +2410,24 @@ static int set_local_var(char *str, unsigned flags)
2402#endif 2410#endif
2403 if (flags & SETFLAG_EXPORT) 2411 if (flags & SETFLAG_EXPORT)
2404 cur->flg_export = 1; 2412 cur->flg_export = 1;
2413 retval = 0;
2405 if (cur->flg_export) { 2414 if (cur->flg_export) {
2406 if (flags & SETFLAG_UNEXPORT) { 2415 if (flags & SETFLAG_UNEXPORT) {
2407 cur->flg_export = 0; 2416 cur->flg_export = 0;
2408 /* unsetenv was already done */ 2417 /* unsetenv was already done */
2409 } else { 2418 } else {
2410 int i;
2411 debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level); 2419 debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level);
2412 i = putenv(cur->varstr); 2420 retval = putenv(cur->varstr);
2413 /* only now we can free old exported malloced string */ 2421 /* fall through to "free(free_me)" -
2414 free(free_me); 2422 * only now we can free old exported malloced string
2415 return i; 2423 */
2416 } 2424 }
2417 } 2425 }
2418 free(free_me); 2426 free(free_me);
2419 2427
2420 handle_changed_special_names(cur->varstr, name_len - 1); 2428 handle_changed_special_names(cur->varstr, name_len - 1);
2421 2429
2422 return 0; 2430 return retval;
2423} 2431}
2424 2432
2425static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) 2433static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
@@ -2492,6 +2500,11 @@ static void add_vars(struct variable *var)
2492 } else { 2500 } else {
2493 debug_printf_env("%s: restoring variable '%s'/%u\n", __func__, var->varstr, var->var_nest_level); 2501 debug_printf_env("%s: restoring variable '%s'/%u\n", __func__, var->varstr, var->var_nest_level);
2494 } 2502 }
2503 /* Testcase (interactive):
2504 * f() { local PS1='\w \$ '; }; f
2505 * the below call is needed to notice restored PS1 when f returns.
2506 */
2507 handle_changed_special_names(var->varstr, endofname(var->varstr) - var->varstr);
2495 var = next; 2508 var = next;
2496 } 2509 }
2497} 2510}
@@ -4198,7 +4211,7 @@ static int done_word(struct parse_context *ctx)
4198#if ENABLE_HUSH_LOOPS 4211#if ENABLE_HUSH_LOOPS
4199 if (ctx->ctx_res_w == RES_FOR) { 4212 if (ctx->ctx_res_w == RES_FOR) {
4200 if (ctx->word.has_quoted_part 4213 if (ctx->word.has_quoted_part
4201 || !is_well_formed_var_name(command->argv[0], '\0') 4214 || endofname(command->argv[0])[0] != '\0'
4202 ) { 4215 ) {
4203 /* bash says just "not a valid identifier" */ 4216 /* bash says just "not a valid identifier" */
4204 syntax_error("not a valid identifier in for"); 4217 syntax_error("not a valid identifier in for");
@@ -5372,7 +5385,7 @@ static struct pipe *parse_stream(char **pstring,
5372 if ((ctx.is_assignment == MAYBE_ASSIGNMENT 5385 if ((ctx.is_assignment == MAYBE_ASSIGNMENT
5373 || ctx.is_assignment == WORD_IS_KEYWORD) 5386 || ctx.is_assignment == WORD_IS_KEYWORD)
5374 && ch == '=' 5387 && ch == '='
5375 && is_well_formed_var_name(ctx.word.data, '=') 5388 && endofname(ctx.word.data)[0] == '='
5376 ) { 5389 ) {
5377 ctx.is_assignment = DEFINITELY_ASSIGNMENT; 5390 ctx.is_assignment = DEFINITELY_ASSIGNMENT;
5378 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); 5391 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
@@ -7598,10 +7611,10 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7598 avoid_fd = 9; 7611 avoid_fd = 9;
7599 7612
7600#if ENABLE_HUSH_INTERACTIVE 7613#if ENABLE_HUSH_INTERACTIVE
7601 if (fd == G.interactive_fd) { 7614 if (fd == G_interactive_fd) {
7602 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ 7615 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */
7603 G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd); 7616 G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd);
7604 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); 7617 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd);
7605 return 1; /* "we closed fd" */ 7618 return 1; /* "we closed fd" */
7606 } 7619 }
7607#endif 7620#endif
@@ -7677,7 +7690,7 @@ static void restore_redirects(struct squirrel *sq)
7677 free(sq); 7690 free(sq);
7678 } 7691 }
7679 7692
7680 /* If moved, G.interactive_fd stays on new fd, not restoring it */ 7693 /* If moved, G_interactive_fd stays on new fd, not restoring it */
7681} 7694}
7682 7695
7683#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU 7696#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
@@ -7694,7 +7707,7 @@ static int internally_opened_fd(int fd, struct squirrel *sq)
7694 int i; 7707 int i;
7695 7708
7696#if ENABLE_HUSH_INTERACTIVE 7709#if ENABLE_HUSH_INTERACTIVE
7697 if (fd == G.interactive_fd) 7710 if (fd == G_interactive_fd)
7698 return 1; 7711 return 1;
7699#endif 7712#endif
7700 /* If this one of script's fds? */ 7713 /* If this one of script's fds? */
@@ -7885,6 +7898,11 @@ static void remove_nested_vars(void)
7885 *cur_pp = cur->next; 7898 *cur_pp = cur->next;
7886 /* Free */ 7899 /* Free */
7887 if (!cur->max_len) { 7900 if (!cur->max_len) {
7901 /* Testcase (interactive):
7902 * f() { local PS1='\w \$ '; }; f
7903 * we should forget local PS1:
7904 */
7905 handle_changed_special_names(cur->varstr, endofname(cur->varstr) - cur->varstr);
7888 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level); 7906 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7889 free(cur->varstr); 7907 free(cur->varstr);
7890 } 7908 }
@@ -10687,9 +10705,7 @@ static int helper_export_local(char **argv, unsigned flags)
10687{ 10705{
10688 do { 10706 do {
10689 char *name = *argv; 10707 char *name = *argv;
10690 char *name_end = strchrnul(name, '='); 10708 const char *name_end = endofname(name);
10691
10692 /* So far we do not check that name is valid (TODO?) */
10693 10709
10694 if (*name_end == '\0') { 10710 if (*name_end == '\0') {
10695 struct variable *var, **vpp; 10711 struct variable *var, **vpp;
@@ -10747,8 +10763,15 @@ static int helper_export_local(char **argv, unsigned flags)
10747 */ 10763 */
10748 name = xasprintf("%s=", name); 10764 name = xasprintf("%s=", name);
10749 } else { 10765 } else {
10766 if (*name_end != '=') {
10767 bb_error_msg("'%s': bad variable name", name);
10768 /* do not parse following argv[]s: */
10769 return 1;
10770 }
10750 /* (Un)exporting/making local NAME=VALUE */ 10771 /* (Un)exporting/making local NAME=VALUE */
10751 name = xstrdup(name); 10772 name = xstrdup(name);
10773 /* Testcase: export PS1='\w \$ ' */
10774 unbackslash(name);
10752 } 10775 }
10753 debug_printf_env("%s: set_local_var('%s')\n", __func__, name); 10776 debug_printf_env("%s: set_local_var('%s')\n", __func__, name);
10754 if (set_local_var(name, flags)) 10777 if (set_local_var(name, flags))
diff --git a/shell/shell_common.c b/shell/shell_common.c
index da3165329..e0582adfb 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -22,19 +22,6 @@
22const char defifsvar[] ALIGN1 = "IFS= \t\n"; 22const char defifsvar[] ALIGN1 = "IFS= \t\n";
23const char defoptindvar[] ALIGN1 = "OPTIND=1"; 23const char defoptindvar[] ALIGN1 = "OPTIND=1";
24 24
25
26int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
27{
28 if (!s || !(isalpha(*s) || *s == '_'))
29 return 0;
30
31 do
32 s++;
33 while (isalnum(*s) || *s == '_');
34
35 return *s == terminator;
36}
37
38/* read builtin */ 25/* read builtin */
39 26
40/* Needs to be interruptible: shell must handle traps and shell-special signals 27/* Needs to be interruptible: shell must handle traps and shell-special signals
@@ -70,7 +57,7 @@ shell_builtin_read(struct builtin_read_params *params)
70 argv = params->argv; 57 argv = params->argv;
71 pp = argv; 58 pp = argv;
72 while (*pp) { 59 while (*pp) {
73 if (!is_well_formed_var_name(*pp, '\0')) { 60 if (endofname(*pp)[0] != '\0') {
74 /* Mimic bash message */ 61 /* Mimic bash message */
75 bb_error_msg("read: '%s': not a valid identifier", *pp); 62 bb_error_msg("read: '%s': not a valid identifier", *pp);
76 return (const char *)(uintptr_t)1; 63 return (const char *)(uintptr_t)1;
diff --git a/shell/shell_common.h b/shell/shell_common.h
index a1323021d..7b478f1df 100644
--- a/shell/shell_common.h
+++ b/shell/shell_common.h
@@ -26,8 +26,6 @@ extern const char defifsvar[] ALIGN1; /* "IFS= \t\n" */
26 26
27extern const char defoptindvar[] ALIGN1; /* "OPTIND=1" */ 27extern const char defoptindvar[] ALIGN1; /* "OPTIND=1" */
28 28
29int FAST_FUNC is_well_formed_var_name(const char *s, char terminator);
30
31/* Builtins */ 29/* Builtins */
32 30
33struct builtin_read_params { 31struct builtin_read_params {