aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c149
1 files changed, 96 insertions, 53 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 6e64efb70..06fe0e405 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1501,12 +1501,15 @@ static void free_strings(char **strings)
1501 free(strings); 1501 free(strings);
1502} 1502}
1503 1503
1504static int fcntl_F_DUPFD(int fd, int avoid_fd) 1504static int dup_CLOEXEC(int fd, int avoid_fd)
1505{ 1505{
1506 int newfd; 1506 int newfd;
1507 repeat: 1507 repeat:
1508 newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); 1508 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1509 if (newfd < 0) { 1509 if (newfd >= 0) {
1510 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1511 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1512 } else { /* newfd < 0 */
1510 if (errno == EBUSY) 1513 if (errno == EBUSY)
1511 goto repeat; 1514 goto repeat;
1512 if (errno == EINTR) 1515 if (errno == EINTR)
@@ -2691,6 +2694,42 @@ static int i_peek2(struct in_str *i)
2691 return ch; 2694 return ch;
2692} 2695}
2693 2696
2697static int i_getch_and_eat_bkslash_nl(struct in_str *input)
2698{
2699 for (;;) {
2700 int ch, ch2;
2701
2702 ch = i_getch(input);
2703 if (ch != '\\')
2704 return ch;
2705 ch2 = i_peek(input);
2706 if (ch2 != '\n')
2707 return ch;
2708 /* backslash+newline, skip it */
2709 i_getch(input);
2710 }
2711}
2712
2713/* Note: this function _eats_ \<newline> pairs, safe to use plain
2714 * i_getch() after it instead of i_getch_and_eat_bkslash_nl().
2715 */
2716static int i_peek_and_eat_bkslash_nl(struct in_str *input)
2717{
2718 for (;;) {
2719 int ch, ch2;
2720
2721 ch = i_peek(input);
2722 if (ch != '\\')
2723 return ch;
2724 ch2 = i_peek2(input);
2725 if (ch2 != '\n')
2726 return ch;
2727 /* backslash+newline, skip it */
2728 i_getch(input);
2729 i_getch(input);
2730 }
2731}
2732
2694static void setup_file_in_str(struct in_str *i, FILE *f) 2733static void setup_file_in_str(struct in_str *i, FILE *f)
2695{ 2734{
2696 memset(i, 0, sizeof(*i)); 2735 memset(i, 0, sizeof(*i));
@@ -3119,7 +3158,7 @@ static int glob_brace(char *pattern, o_string *o, int n)
3119 return o_save_ptr_helper(o, n); 3158 return o_save_ptr_helper(o, n);
3120 } 3159 }
3121 if (gr == GLOB_NOSPACE) 3160 if (gr == GLOB_NOSPACE)
3122 bb_error_msg_and_die(bb_msg_memory_exhausted); 3161 bb_die_memory_exhausted();
3123 /* GLOB_ABORTED? Only happens with GLOB_ERR flag, 3162 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
3124 * but we didn't specify it. Paranoia again. */ 3163 * but we didn't specify it. Paranoia again. */
3125 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); 3164 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
@@ -3221,7 +3260,7 @@ static int perform_glob(o_string *o, int n)
3221 goto literal; 3260 goto literal;
3222 } 3261 }
3223 if (gr == GLOB_NOSPACE) 3262 if (gr == GLOB_NOSPACE)
3224 bb_error_msg_and_die(bb_msg_memory_exhausted); 3263 bb_die_memory_exhausted();
3225 /* GLOB_ABORTED? Only happens with GLOB_ERR flag, 3264 /* GLOB_ABORTED? Only happens with GLOB_ERR flag,
3226 * but we didn't specify it. Paranoia again. */ 3265 * but we didn't specify it. Paranoia again. */
3227 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); 3266 bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
@@ -3812,16 +3851,28 @@ static int done_word(o_string *word, struct parse_context *ctx)
3812 if (ctx->pending_redirect) { 3851 if (ctx->pending_redirect) {
3813 /* We do not glob in e.g. >*.tmp case. bash seems to glob here 3852 /* We do not glob in e.g. >*.tmp case. bash seems to glob here
3814 * only if run as "bash", not "sh" */ 3853 * only if run as "bash", not "sh" */
3815 /* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html 3854 /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
3816 * "2.7 Redirection 3855 * "2.7 Redirection
3817 * ...the word that follows the redirection operator 3856 * If the redirection operator is "<<" or "<<-", the word
3818 * shall be subjected to tilde expansion, parameter expansion, 3857 * that follows the redirection operator shall be
3819 * command substitution, arithmetic expansion, and quote 3858 * subjected to quote removal; it is unspecified whether
3820 * removal. Pathname expansion shall not be performed 3859 * any of the other expansions occur. For the other
3860 * redirection operators, the word that follows the
3861 * redirection operator shall be subjected to tilde
3862 * expansion, parameter expansion, command substitution,
3863 * arithmetic expansion, and quote removal.
3864 * Pathname expansion shall not be performed
3821 * on the word by a non-interactive shell; an interactive 3865 * on the word by a non-interactive shell; an interactive
3822 * shell may perform it, but shall do so only when 3866 * shell may perform it, but shall do so only when
3823 * the expansion would result in one word." 3867 * the expansion would result in one word."
3824 */ 3868 */
3869//bash does not do parameter/command substitution or arithmetic expansion
3870//for _heredoc_ redirection word: these constructs look for exact eof marker
3871// as written:
3872// <<EOF$t
3873// <<EOF$((1))
3874// <<EOF`true` [this case also makes heredoc "quoted", a-la <<"EOF". Probably bash-4.3.43 bug]
3875
3825 ctx->pending_redirect->rd_filename = xstrdup(word->data); 3876 ctx->pending_redirect->rd_filename = xstrdup(word->data);
3826 /* Cater for >\file case: 3877 /* Cater for >\file case:
3827 * >\a creates file a; >\\a, >"\a", >"\\a" create file \a 3878 * >\a creates file a; >\\a, >"\a", >"\\a" create file \a
@@ -4011,7 +4062,7 @@ static int parse_redirect(struct parse_context *ctx,
4011 if (dup_num == REDIRFD_SYNTAX_ERR) 4062 if (dup_num == REDIRFD_SYNTAX_ERR)
4012 return 1; 4063 return 1;
4013 } else { 4064 } else {
4014 int ch = i_peek(input); 4065 int ch = i_peek_and_eat_bkslash_nl(input);
4015 dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */ 4066 dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */
4016 if (dup_num) { /* <<-... */ 4067 if (dup_num) { /* <<-... */
4017 ch = i_getch(input); 4068 ch = i_getch(input);
@@ -4021,7 +4072,7 @@ static int parse_redirect(struct parse_context *ctx,
4021 } 4072 }
4022 4073
4023 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) { 4074 if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) {
4024 int ch = i_peek(input); 4075 int ch = i_peek_and_eat_bkslash_nl(input);
4025 if (ch == '|') { 4076 if (ch == '|') {
4026 /* >|FILE redirect ("clobbering" >). 4077 /* >|FILE redirect ("clobbering" >).
4027 * Since we do not support "set -o noclobber" yet, 4078 * Since we do not support "set -o noclobber" yet,
@@ -4189,6 +4240,7 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
4189 4240
4190 redir->rd_type = REDIRECT_HEREDOC2; 4241 redir->rd_type = REDIRECT_HEREDOC2;
4191 /* redir->rd_dup is (ab)used to indicate <<- */ 4242 /* redir->rd_dup is (ab)used to indicate <<- */
4243bb_error_msg("redir->rd_filename:'%s'", redir->rd_filename);
4192 p = fetch_till_str(&ctx->as_string, input, 4244 p = fetch_till_str(&ctx->as_string, input,
4193 redir->rd_filename, redir->rd_dup); 4245 redir->rd_filename, redir->rd_dup);
4194 if (!p) { 4246 if (!p) {
@@ -4340,39 +4392,6 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4340 /* command remains "open", available for possible redirects */ 4392 /* command remains "open", available for possible redirects */
4341} 4393}
4342 4394
4343static int i_getch_and_eat_bkslash_nl(struct in_str *input)
4344{
4345 for (;;) {
4346 int ch, ch2;
4347
4348 ch = i_getch(input);
4349 if (ch != '\\')
4350 return ch;
4351 ch2 = i_peek(input);
4352 if (ch2 != '\n')
4353 return ch;
4354 /* backslash+newline, skip it */
4355 i_getch(input);
4356 }
4357}
4358
4359static int i_peek_and_eat_bkslash_nl(struct in_str *input)
4360{
4361 for (;;) {
4362 int ch, ch2;
4363
4364 ch = i_peek(input);
4365 if (ch != '\\')
4366 return ch;
4367 ch2 = i_peek2(input);
4368 if (ch2 != '\n')
4369 return ch;
4370 /* backslash+newline, skip it */
4371 i_getch(input);
4372 i_getch(input);
4373 }
4374}
4375
4376#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS 4395#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
4377/* Subroutines for copying $(...) and `...` things */ 4396/* Subroutines for copying $(...) and `...` things */
4378static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); 4397static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
@@ -4974,8 +4993,14 @@ static struct pipe *parse_stream(char **pstring,
4974 nommu_addchr(&ctx.as_string, ch); 4993 nommu_addchr(&ctx.as_string, ch);
4975 4994
4976 next = '\0'; 4995 next = '\0';
4977 if (ch != '\n') 4996 if (ch != '\n') {
4978 next = i_peek(input); 4997 next = i_peek(input);
4998 /* Can't use i_peek_and_eat_bkslash_nl(input) here:
4999 * echo '\
5000 * '
5001 * will break.
5002 */
5003 }
4979 5004
4980 is_special = "{}<>;&|()#'" /* special outside of "str" */ 5005 is_special = "{}<>;&|()#'" /* special outside of "str" */
4981 "\\$\"" IF_HUSH_TICK("`") /* always special */ 5006 "\\$\"" IF_HUSH_TICK("`") /* always special */
@@ -5178,6 +5203,8 @@ static struct pipe *parse_stream(char **pstring,
5178 goto parse_error; 5203 goto parse_error;
5179 } 5204 }
5180 redir_style = REDIRECT_OVERWRITE; 5205 redir_style = REDIRECT_OVERWRITE;
5206 if (next == '\\')
5207 next = i_peek_and_eat_bkslash_nl(input);
5181 if (next == '>') { 5208 if (next == '>') {
5182 redir_style = REDIRECT_APPEND; 5209 redir_style = REDIRECT_APPEND;
5183 ch = i_getch(input); 5210 ch = i_getch(input);
@@ -5198,6 +5225,8 @@ static struct pipe *parse_stream(char **pstring,
5198 goto parse_error; 5225 goto parse_error;
5199 } 5226 }
5200 redir_style = REDIRECT_INPUT; 5227 redir_style = REDIRECT_INPUT;
5228 if (next == '\\')
5229 next = i_peek_and_eat_bkslash_nl(input);
5201 if (next == '<') { 5230 if (next == '<') {
5202 redir_style = REDIRECT_HEREDOC; 5231 redir_style = REDIRECT_HEREDOC;
5203 heredoc_cnt++; 5232 heredoc_cnt++;
@@ -5365,7 +5394,7 @@ static struct pipe *parse_stream(char **pstring,
5365 /* Eat multiple semicolons, detect 5394 /* Eat multiple semicolons, detect
5366 * whether it means something special */ 5395 * whether it means something special */
5367 while (1) { 5396 while (1) {
5368 ch = i_peek(input); 5397 ch = i_peek_and_eat_bkslash_nl(input);
5369 if (ch != ';') 5398 if (ch != ';')
5370 break; 5399 break;
5371 ch = i_getch(input); 5400 ch = i_getch(input);
@@ -5387,6 +5416,8 @@ static struct pipe *parse_stream(char **pstring,
5387 if (done_word(&dest, &ctx)) { 5416 if (done_word(&dest, &ctx)) {
5388 goto parse_error; 5417 goto parse_error;
5389 } 5418 }
5419 if (next == '\\')
5420 next = i_peek_and_eat_bkslash_nl(input);
5390 if (next == '&') { 5421 if (next == '&') {
5391 ch = i_getch(input); 5422 ch = i_getch(input);
5392 nommu_addchr(&ctx.as_string, ch); 5423 nommu_addchr(&ctx.as_string, ch);
@@ -5403,6 +5434,8 @@ static struct pipe *parse_stream(char **pstring,
5403 if (ctx.ctx_res_w == RES_MATCH) 5434 if (ctx.ctx_res_w == RES_MATCH)
5404 break; /* we are in case's "word | word)" */ 5435 break; /* we are in case's "word | word)" */
5405#endif 5436#endif
5437 if (next == '\\')
5438 next = i_peek_and_eat_bkslash_nl(input);
5406 if (next == '|') { /* || */ 5439 if (next == '|') { /* || */
5407 ch = i_getch(input); 5440 ch = i_getch(input);
5408 nommu_addchr(&ctx.as_string, ch); 5441 nommu_addchr(&ctx.as_string, ch);
@@ -6123,7 +6156,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6123 } else 6156 } else
6124 /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....' 6157 /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....'
6125 * and in this case should treat it like '$*' - see 'else...' below */ 6158 * and in this case should treat it like '$*' - see 'else...' below */
6126 if (first_ch == ('@'|0x80) /* quoted $@ */ 6159 if (first_ch == (char)('@'|0x80) /* quoted $@ */
6127 && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */ 6160 && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */
6128 ) { 6161 ) {
6129 while (1) { 6162 while (1) {
@@ -6890,7 +6923,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6890 if (sq) for (; sq[i].orig_fd >= 0; i++) { 6923 if (sq) for (; sq[i].orig_fd >= 0; i++) {
6891 /* If we collide with an already moved fd... */ 6924 /* If we collide with an already moved fd... */
6892 if (fd == sq[i].moved_to) { 6925 if (fd == sq[i].moved_to) {
6893 sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); 6926 sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd);
6894 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); 6927 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to);
6895 if (sq[i].moved_to < 0) /* what? */ 6928 if (sq[i].moved_to < 0) /* what? */
6896 xfunc_die(); 6929 xfunc_die();
@@ -6904,7 +6937,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6904 } 6937 }
6905 6938
6906 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ 6939 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
6907 moved_to = fcntl_F_DUPFD(fd, avoid_fd); 6940 moved_to = dup_CLOEXEC(fd, avoid_fd);
6908 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); 6941 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
6909 if (moved_to < 0 && errno != EBADF) 6942 if (moved_to < 0 && errno != EBADF)
6910 xfunc_die(); 6943 xfunc_die();
@@ -7622,6 +7655,10 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7622 */ 7655 */
7623 close_saved_fds_and_FILE_fds(); 7656 close_saved_fds_and_FILE_fds();
7624//FIXME: should also close saved redir fds 7657//FIXME: should also close saved redir fds
7658//This casuses test failures in
7659//redir_children_should_not_see_saved_fd_2.tests
7660//redir_children_should_not_see_saved_fd_3.tests
7661//if you replace "busybox find" with just "find" in them
7625 /* Without this, "rm -i FILE" can't be ^C'ed: */ 7662 /* Without this, "rm -i FILE" can't be ^C'ed: */
7626 switch_off_special_sigs(G.special_sig_mask); 7663 switch_off_special_sigs(G.special_sig_mask);
7627 debug_printf_exec("running applet '%s'\n", argv[0]); 7664 debug_printf_exec("running applet '%s'\n", argv[0]);
@@ -8166,6 +8203,12 @@ static NOINLINE int run_pipe(struct pipe *pi)
8166 rcode = 1; /* exitcode if redir failed */ 8203 rcode = 1; /* exitcode if redir failed */
8167 if (setup_redirects(command, &squirrel) == 0) { 8204 if (setup_redirects(command, &squirrel) == 0) {
8168 debug_printf_exec(": run_list\n"); 8205 debug_printf_exec(": run_list\n");
8206//FIXME: we need to pass squirrel down into run_list()
8207//for SH_STANDALONE case, or else this construct:
8208// { find /proc/self/fd; true; } >FILE; cmd2
8209//has no way of closing saved fd#1 for "find",
8210//and in SH_STANDALONE mode, "find" is not execed,
8211//therefore CLOEXEC on saved fd does not help.
8169 rcode = run_list(command->group) & 0xff; 8212 rcode = run_list(command->group) & 0xff;
8170 } 8213 }
8171 restore_redirects(squirrel); 8214 restore_redirects(squirrel);
@@ -9347,7 +9390,7 @@ int hush_main(int argc, char **argv)
9347 G_saved_tty_pgrp = 0; 9390 G_saved_tty_pgrp = 0;
9348 9391
9349 /* try to dup stdin to high fd#, >= 255 */ 9392 /* try to dup stdin to high fd#, >= 255 */
9350 G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); 9393 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
9351 if (G_interactive_fd < 0) { 9394 if (G_interactive_fd < 0) {
9352 /* try to dup to any fd */ 9395 /* try to dup to any fd */
9353 G_interactive_fd = dup(STDIN_FILENO); 9396 G_interactive_fd = dup(STDIN_FILENO);
@@ -9420,10 +9463,10 @@ int hush_main(int argc, char **argv)
9420#elif ENABLE_HUSH_INTERACTIVE 9463#elif ENABLE_HUSH_INTERACTIVE
9421 /* No job control compiled in, only prompt/line editing */ 9464 /* No job control compiled in, only prompt/line editing */
9422 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 9465 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
9423 G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); 9466 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
9424 if (G_interactive_fd < 0) { 9467 if (G_interactive_fd < 0) {
9425 /* try to dup to any fd */ 9468 /* try to dup to any fd */
9426 G_interactive_fd = dup(STDIN_FILENO); 9469 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO);
9427 if (G_interactive_fd < 0) 9470 if (G_interactive_fd < 0)
9428 /* give up */ 9471 /* give up */
9429 G_interactive_fd = 0; 9472 G_interactive_fd = 0;