diff options
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 117 |
1 files changed, 83 insertions, 34 deletions
diff --git a/shell/hush.c b/shell/hush.c index 1082738a2..e4138adf7 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2281,7 +2281,7 @@ static void o_addqblock(o_string *o, const char *str, int len) | |||
2281 | ordinary_cnt = len; | 2281 | ordinary_cnt = len; |
2282 | o_addblock(o, str, ordinary_cnt); | 2282 | o_addblock(o, str, ordinary_cnt); |
2283 | if (ordinary_cnt == len) | 2283 | if (ordinary_cnt == len) |
2284 | return; | 2284 | return; /* NUL is already added by o_addblock */ |
2285 | str += ordinary_cnt; | 2285 | str += ordinary_cnt; |
2286 | len -= ordinary_cnt + 1; /* we are processing + 1 char below */ | 2286 | len -= ordinary_cnt + 1; /* we are processing + 1 char below */ |
2287 | 2287 | ||
@@ -2295,8 +2295,8 @@ static void o_addqblock(o_string *o, const char *str, int len) | |||
2295 | o_grow_by(o, sz); | 2295 | o_grow_by(o, sz); |
2296 | o->data[o->length] = ch; | 2296 | o->data[o->length] = ch; |
2297 | o->length++; | 2297 | o->length++; |
2298 | o->data[o->length] = '\0'; | ||
2299 | } | 2298 | } |
2299 | o->data[o->length] = '\0'; | ||
2300 | } | 2300 | } |
2301 | 2301 | ||
2302 | static void o_addQblock(o_string *o, const char *str, int len) | 2302 | static void o_addQblock(o_string *o, const char *str, int len) |
@@ -2385,6 +2385,7 @@ static int o_save_ptr_helper(o_string *o, int n) | |||
2385 | n, string_len, string_start); | 2385 | n, string_len, string_start); |
2386 | o->has_empty_slot = 0; | 2386 | o->has_empty_slot = 0; |
2387 | } | 2387 | } |
2388 | o->has_quoted_part = 0; | ||
2388 | list[n] = (char*)(uintptr_t)string_len; | 2389 | list[n] = (char*)(uintptr_t)string_len; |
2389 | return n + 1; | 2390 | return n + 1; |
2390 | } | 2391 | } |
@@ -3264,14 +3265,6 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3264 | ) { | 3265 | ) { |
3265 | p += 3; | 3266 | p += 3; |
3266 | } | 3267 | } |
3267 | if (p == word->data || p[0] != '\0') { | ||
3268 | /* saw no "$@", or not only "$@" but some | ||
3269 | * real text is there too */ | ||
3270 | /* insert "empty variable" reference, this makes | ||
3271 | * e.g. "", $empty"" etc to not disappear */ | ||
3272 | o_addchr(word, SPECIAL_VAR_SYMBOL); | ||
3273 | o_addchr(word, SPECIAL_VAR_SYMBOL); | ||
3274 | } | ||
3275 | } | 3268 | } |
3276 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); | 3269 | command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); |
3277 | debug_print_strings("word appended to argv", command->argv); | 3270 | debug_print_strings("word appended to argv", command->argv); |
@@ -4515,20 +4508,30 @@ static struct pipe *parse_stream(char **pstring, | |||
4515 | break; | 4508 | break; |
4516 | case '\'': | 4509 | case '\'': |
4517 | dest.has_quoted_part = 1; | 4510 | dest.has_quoted_part = 1; |
4518 | while (1) { | 4511 | if (next == '\'' && !ctx.pending_redirect) { |
4519 | ch = i_getch(input); | 4512 | insert_empty_quoted_str_marker: |
4520 | if (ch == EOF) { | 4513 | nommu_addchr(&ctx.as_string, next); |
4521 | syntax_error_unterm_ch('\''); | 4514 | i_getch(input); /* eat second ' */ |
4522 | goto parse_error; | 4515 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); |
4516 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | ||
4517 | } else { | ||
4518 | while (1) { | ||
4519 | ch = i_getch(input); | ||
4520 | if (ch == EOF) { | ||
4521 | syntax_error_unterm_ch('\''); | ||
4522 | goto parse_error; | ||
4523 | } | ||
4524 | nommu_addchr(&ctx.as_string, ch); | ||
4525 | if (ch == '\'') | ||
4526 | break; | ||
4527 | o_addqchr(&dest, ch); | ||
4523 | } | 4528 | } |
4524 | nommu_addchr(&ctx.as_string, ch); | ||
4525 | if (ch == '\'') | ||
4526 | break; | ||
4527 | o_addqchr(&dest, ch); | ||
4528 | } | 4529 | } |
4529 | break; | 4530 | break; |
4530 | case '"': | 4531 | case '"': |
4531 | dest.has_quoted_part = 1; | 4532 | dest.has_quoted_part = 1; |
4533 | if (next == '"' && !ctx.pending_redirect) | ||
4534 | goto insert_empty_quoted_str_marker; | ||
4532 | if (dest.o_assignment == NOT_ASSIGNMENT) | 4535 | if (dest.o_assignment == NOT_ASSIGNMENT) |
4533 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; | 4536 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; |
4534 | if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) | 4537 | if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) |
@@ -4750,12 +4753,22 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len | |||
4750 | 4753 | ||
4751 | /* Store given string, finalizing the word and starting new one whenever | 4754 | /* Store given string, finalizing the word and starting new one whenever |
4752 | * we encounter IFS char(s). This is used for expanding variable values. | 4755 | * we encounter IFS char(s). This is used for expanding variable values. |
4753 | * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ | 4756 | * End-of-string does NOT finalize word: think about 'echo -$VAR-'. |
4754 | static int expand_on_ifs(o_string *output, int n, const char *str) | 4757 | * Return in *ended_with_ifs: |
4758 | * 1 - ended with IFS char, else 0 (this includes case of empty str). | ||
4759 | */ | ||
4760 | static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) | ||
4755 | { | 4761 | { |
4762 | int last_is_ifs = 0; | ||
4763 | |||
4756 | while (1) { | 4764 | while (1) { |
4757 | int word_len = strcspn(str, G.ifs); | 4765 | int word_len; |
4766 | |||
4767 | if (!*str) /* EOL - do not finalize word */ | ||
4768 | break; | ||
4769 | word_len = strcspn(str, G.ifs); | ||
4758 | if (word_len) { | 4770 | if (word_len) { |
4771 | /* We have WORD_LEN leading non-IFS chars */ | ||
4759 | if (!(output->o_expflags & EXP_FLAG_GLOB)) { | 4772 | if (!(output->o_expflags & EXP_FLAG_GLOB)) { |
4760 | o_addblock(output, str, word_len); | 4773 | o_addblock(output, str, word_len); |
4761 | } else { | 4774 | } else { |
@@ -4768,15 +4781,36 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
4768 | /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ | 4781 | /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ |
4769 | /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ | 4782 | /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ |
4770 | } | 4783 | } |
4784 | last_is_ifs = 0; | ||
4771 | str += word_len; | 4785 | str += word_len; |
4786 | if (!*str) /* EOL - do not finalize word */ | ||
4787 | break; | ||
4772 | } | 4788 | } |
4789 | |||
4790 | /* We know str here points to at least one IFS char */ | ||
4791 | last_is_ifs = 1; | ||
4792 | str += strspn(str, G.ifs); /* skip IFS chars */ | ||
4773 | if (!*str) /* EOL - do not finalize word */ | 4793 | if (!*str) /* EOL - do not finalize word */ |
4774 | break; | 4794 | break; |
4775 | o_addchr(output, '\0'); | 4795 | |
4776 | debug_print_list("expand_on_ifs", output, n); | 4796 | /* Start new word... but not always! */ |
4777 | n = o_save_ptr(output, n); | 4797 | /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */ |
4778 | str += strspn(str, G.ifs); /* skip ifs chars */ | 4798 | if (output->has_quoted_part |
4799 | /* Case "v=' a'; echo $v": | ||
4800 | * here nothing precedes the space in $v expansion, | ||
4801 | * therefore we should not finish the word | ||
4802 | * (IOW: if there *is* word to finalize, only then do it): | ||
4803 | */ | ||
4804 | || (n > 0 && output->data[output->length - 1]) | ||
4805 | ) { | ||
4806 | o_addchr(output, '\0'); | ||
4807 | debug_print_list("expand_on_ifs", output, n); | ||
4808 | n = o_save_ptr(output, n); | ||
4809 | } | ||
4779 | } | 4810 | } |
4811 | |||
4812 | if (ended_with_ifs) | ||
4813 | *ended_with_ifs = last_is_ifs; | ||
4780 | debug_print_list("expand_on_ifs[1]", output, n); | 4814 | debug_print_list("expand_on_ifs[1]", output, n); |
4781 | return n; | 4815 | return n; |
4782 | } | 4816 | } |
@@ -5191,6 +5225,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5191 | * expansion of right-hand side of assignment == 1-element expand. | 5225 | * expansion of right-hand side of assignment == 1-element expand. |
5192 | */ | 5226 | */ |
5193 | char cant_be_null = 0; /* only bit 0x80 matters */ | 5227 | char cant_be_null = 0; /* only bit 0x80 matters */ |
5228 | int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */ | ||
5194 | char *p; | 5229 | char *p; |
5195 | 5230 | ||
5196 | debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, | 5231 | debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, |
@@ -5209,6 +5244,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5209 | #if ENABLE_SH_MATH_SUPPORT | 5244 | #if ENABLE_SH_MATH_SUPPORT |
5210 | char arith_buf[sizeof(arith_t)*3 + 2]; | 5245 | char arith_buf[sizeof(arith_t)*3 + 2]; |
5211 | #endif | 5246 | #endif |
5247 | |||
5248 | if (ended_in_ifs) { | ||
5249 | o_addchr(output, '\0'); | ||
5250 | n = o_save_ptr(output, n); | ||
5251 | ended_in_ifs = 0; | ||
5252 | } | ||
5253 | |||
5212 | o_addblock(output, arg, p - arg); | 5254 | o_addblock(output, arg, p - arg); |
5213 | debug_print_list("expand_vars_to_list[1]", output, n); | 5255 | debug_print_list("expand_vars_to_list[1]", output, n); |
5214 | arg = ++p; | 5256 | arg = ++p; |
@@ -5237,7 +5279,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5237 | cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ | 5279 | cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ |
5238 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ | 5280 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ |
5239 | while (G.global_argv[i]) { | 5281 | while (G.global_argv[i]) { |
5240 | n = expand_on_ifs(output, n, G.global_argv[i]); | 5282 | n = expand_on_ifs(NULL, output, n, G.global_argv[i]); |
5241 | debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); | 5283 | debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); |
5242 | if (G.global_argv[i++][0] && G.global_argv[i]) { | 5284 | if (G.global_argv[i++][0] && G.global_argv[i]) { |
5243 | /* this argv[] is not empty and not last: | 5285 | /* this argv[] is not empty and not last: |
@@ -5270,11 +5312,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5270 | if (G.ifs[0]) | 5312 | if (G.ifs[0]) |
5271 | o_addchr(output, G.ifs[0]); | 5313 | o_addchr(output, G.ifs[0]); |
5272 | } | 5314 | } |
5315 | output->has_quoted_part = 1; | ||
5273 | } | 5316 | } |
5274 | break; | 5317 | break; |
5275 | } | 5318 | } |
5276 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ | 5319 | case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ |
5277 | /* "Empty variable", used to make "" etc to not disappear */ | 5320 | /* "Empty variable", used to make "" etc to not disappear */ |
5321 | output->has_quoted_part = 1; | ||
5278 | arg++; | 5322 | arg++; |
5279 | cant_be_null = 0x80; | 5323 | cant_be_null = 0x80; |
5280 | break; | 5324 | break; |
@@ -5312,10 +5356,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5312 | debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, | 5356 | debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, |
5313 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); | 5357 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); |
5314 | if (val && val[0]) { | 5358 | if (val && val[0]) { |
5315 | n = expand_on_ifs(output, n, val); | 5359 | n = expand_on_ifs(&ended_in_ifs, output, n, val); |
5316 | val = NULL; | 5360 | val = NULL; |
5317 | } | 5361 | } |
5318 | } else { /* quoted $VAR, val will be appended below */ | 5362 | } else { /* quoted $VAR, val will be appended below */ |
5363 | output->has_quoted_part = 1; | ||
5319 | debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, | 5364 | debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, |
5320 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); | 5365 | !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); |
5321 | } | 5366 | } |
@@ -5340,6 +5385,10 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) | |||
5340 | } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ | 5385 | } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ |
5341 | 5386 | ||
5342 | if (arg[0]) { | 5387 | if (arg[0]) { |
5388 | if (ended_in_ifs) { | ||
5389 | o_addchr(output, '\0'); | ||
5390 | n = o_save_ptr(output, n); | ||
5391 | } | ||
5343 | debug_print_list("expand_vars_to_list[a]", output, n); | 5392 | debug_print_list("expand_vars_to_list[a]", output, n); |
5344 | /* this part is literal, and it was already pre-quoted | 5393 | /* this part is literal, and it was already pre-quoted |
5345 | * if needed (much earlier), do not use o_addQstr here! */ | 5394 | * if needed (much earlier), do not use o_addQstr here! */ |
@@ -5470,12 +5519,6 @@ static char **expand_assignments(char **argv, int count) | |||
5470 | } | 5519 | } |
5471 | 5520 | ||
5472 | 5521 | ||
5473 | #if BB_MMU | ||
5474 | /* never called */ | ||
5475 | void re_execute_shell(char ***to_free, const char *s, | ||
5476 | char *g_argv0, char **g_argv, | ||
5477 | char **builtin_argv) NORETURN; | ||
5478 | |||
5479 | static void switch_off_special_sigs(unsigned mask) | 5522 | static void switch_off_special_sigs(unsigned mask) |
5480 | { | 5523 | { |
5481 | unsigned sig = 0; | 5524 | unsigned sig = 0; |
@@ -5495,6 +5538,12 @@ static void switch_off_special_sigs(unsigned mask) | |||
5495 | } | 5538 | } |
5496 | } | 5539 | } |
5497 | 5540 | ||
5541 | #if BB_MMU | ||
5542 | /* never called */ | ||
5543 | void re_execute_shell(char ***to_free, const char *s, | ||
5544 | char *g_argv0, char **g_argv, | ||
5545 | char **builtin_argv) NORETURN; | ||
5546 | |||
5498 | static void reset_traps_to_defaults(void) | 5547 | static void reset_traps_to_defaults(void) |
5499 | { | 5548 | { |
5500 | /* This function is always called in a child shell | 5549 | /* This function is always called in a child shell |