aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c67
1 files changed, 53 insertions, 14 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 309ed2139..d0225edb9 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -4466,6 +4466,8 @@ static int parse_dollar(o_string *as_string,
4466 case '@': /* args */ 4466 case '@': /* args */
4467 goto make_one_char_var; 4467 goto make_one_char_var;
4468 case '{': { 4468 case '{': {
4469 char len_single_ch;
4470
4469 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4471 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4470 4472
4471 ch = i_getch(input); /* eat '{' */ 4473 ch = i_getch(input); /* eat '{' */
@@ -4485,6 +4487,7 @@ static int parse_dollar(o_string *as_string,
4485 return 0; 4487 return 0;
4486 } 4488 }
4487 nommu_addchr(as_string, ch); 4489 nommu_addchr(as_string, ch);
4490 len_single_ch = ch;
4488 ch |= quote_mask; 4491 ch |= quote_mask;
4489 4492
4490 /* It's possible to just call add_till_closing_bracket() at this point. 4493 /* It's possible to just call add_till_closing_bracket() at this point.
@@ -4509,9 +4512,18 @@ static int parse_dollar(o_string *as_string,
4509 /* handle parameter expansions 4512 /* handle parameter expansions
4510 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 4513 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
4511 */ 4514 */
4512 if (!strchr(VAR_SUBST_OPS, ch)) /* ${var<bad_char>... */ 4515 if (!strchr(VAR_SUBST_OPS, ch)) { /* ${var<bad_char>... */
4513 goto bad_dollar_syntax; 4516 if (len_single_ch != '#'
4514 4517 /*|| !strchr(SPECIAL_VARS_STR, ch) - disallow errors like ${#+} ? */
4518 || i_peek(input) != '}'
4519 ) {
4520 goto bad_dollar_syntax;
4521 }
4522 /* else: it's "length of C" ${#C} op,
4523 * where C is a single char
4524 * special var name, e.g. ${#!}.
4525 */
4526 }
4515 /* Eat everything until closing '}' (or ':') */ 4527 /* Eat everything until closing '}' (or ':') */
4516 end_ch = '}'; 4528 end_ch = '}';
4517 if (BASH_SUBSTR 4529 if (BASH_SUBSTR
@@ -4568,6 +4580,7 @@ static int parse_dollar(o_string *as_string,
4568 } 4580 }
4569 break; 4581 break;
4570 } 4582 }
4583 len_single_ch = 0; /* it can't be ${#C} op */
4571 } 4584 }
4572 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4585 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4573 break; 4586 break;
@@ -5559,8 +5572,10 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5559 first_char = arg[0] = arg0 & 0x7f; 5572 first_char = arg[0] = arg0 & 0x7f;
5560 exp_op = 0; 5573 exp_op = 0;
5561 5574
5562 if (first_char == '#' /* ${#... */ 5575 if (first_char == '#' && arg[1] /* ${#...} but not ${#} */
5563 && arg[1] && !exp_saveptr /* not ${#} and not ${#<op_char>...} */ 5576 && (!exp_saveptr /* and ( not(${#<op_char>...}) */
5577 || (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1])) /* or ${#C} "len of $C" ) */
5578 ) /* NB: skipping ^^^specvar check mishandles ${#::2} */
5564 ) { 5579 ) {
5565 /* It must be length operator: ${#var} */ 5580 /* It must be length operator: ${#var} */
5566 var++; 5581 var++;
@@ -5797,7 +5812,11 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5797 /* mimic bash message */ 5812 /* mimic bash message */
5798 die_if_script("%s: %s", 5813 die_if_script("%s: %s",
5799 var, 5814 var,
5800 exp_word[0] ? exp_word : "parameter null or not set" 5815 exp_word[0]
5816 ? exp_word
5817 : "parameter null or not set"
5818 /* ash has more specific messages, a-la: */
5819 /*: (exp_save == ':' ? "parameter null or not set" : "parameter not set")*/
5801 ); 5820 );
5802//TODO: how interactive bash aborts expansion mid-command? 5821//TODO: how interactive bash aborts expansion mid-command?
5803 } else { 5822 } else {
@@ -6643,8 +6662,18 @@ struct squirrel {
6643 /* moved_to = -1: fd was opened by redirect; close orig_fd after redir */ 6662 /* moved_to = -1: fd was opened by redirect; close orig_fd after redir */
6644}; 6663};
6645 6664
6665static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, int moved)
6666{
6667 sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
6668 sq[i].orig_fd = orig;
6669 sq[i].moved_to = moved;
6670 sq[i+1].orig_fd = -1; /* end marker */
6671 return sq;
6672}
6673
6646static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) 6674static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6647{ 6675{
6676 int moved_to;
6648 int i = 0; 6677 int i = 0;
6649 6678
6650 if (sq) while (sq[i].orig_fd >= 0) { 6679 if (sq) while (sq[i].orig_fd >= 0) {
@@ -6664,15 +6693,12 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6664 i++; 6693 i++;
6665 } 6694 }
6666 6695
6667 sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
6668 sq[i].orig_fd = fd;
6669 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ 6696 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
6670 sq[i].moved_to = fcntl_F_DUPFD(fd, avoid_fd); 6697 moved_to = fcntl_F_DUPFD(fd, avoid_fd);
6671 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, sq[i].moved_to); 6698 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
6672 if (sq[i].moved_to < 0 && errno != EBADF) 6699 if (moved_to < 0 && errno != EBADF)
6673 xfunc_die(); 6700 xfunc_die();
6674 sq[i+1].orig_fd = -1; /* end marker */ 6701 return append_squirrel(sq, i, fd, moved_to);
6675 return sq;
6676} 6702}
6677 6703
6678/* fd: redirect wants this fd to be used (e.g. 3>file). 6704/* fd: redirect wants this fd to be used (e.g. 3>file).
@@ -6778,6 +6804,19 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6778 */ 6804 */
6779 return 1; 6805 return 1;
6780 } 6806 }
6807 if (openfd == redir->rd_fd && sqp) {
6808 /* open() gave us precisely the fd we wanted.
6809 * This means that this fd was not busy
6810 * (not opened to anywhere).
6811 * Remember to close it on restore:
6812 */
6813 struct squirrel *sq = *sqp;
6814 int i = 0;
6815 if (sq) while (sq[i].orig_fd >= 0)
6816 i++;
6817 *sqp = append_squirrel(sq, i, openfd, -1); /* -1 = "it was closed" */
6818 debug_printf_redir("redir to previously closed fd %d\n", openfd);
6819 }
6781 } else { 6820 } else {
6782 /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */ 6821 /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */
6783 openfd = redir->rd_dup; 6822 openfd = redir->rd_dup;
@@ -9719,7 +9758,7 @@ static int FAST_FUNC builtin_trap(char **argv)
9719 sighandler_t handler; 9758 sighandler_t handler;
9720 9759
9721 sig = get_signum(*argv++); 9760 sig = get_signum(*argv++);
9722 if (sig < 0 || sig >= NSIG) { 9761 if (sig < 0) {
9723 ret = EXIT_FAILURE; 9762 ret = EXIT_FAILURE;
9724 /* Mimic bash message exactly */ 9763 /* Mimic bash message exactly */
9725 bb_error_msg("trap: %s: invalid signal specification", argv[-1]); 9764 bb_error_msg("trap: %s: invalid signal specification", argv[-1]);