aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c117
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
2302static void o_addQblock(o_string *o, const char *str, int len) 2302static 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-'.
4754static 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 */
4760static 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 */
5475void re_execute_shell(char ***to_free, const char *s,
5476 char *g_argv0, char **g_argv,
5477 char **builtin_argv) NORETURN;
5478
5479static void switch_off_special_sigs(unsigned mask) 5522static 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 */
5543void re_execute_shell(char ***to_free, const char *s,
5544 char *g_argv0, char **g_argv,
5545 char **builtin_argv) NORETURN;
5546
5498static void reset_traps_to_defaults(void) 5547static 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