diff --git a/shell/hush.c b/shell/hush.c index a3f80d512..f8f7482b1 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1603,10 +1603,10 @@ static int process_command_subs(o_string *dest, const char *s); #endif static char *expand_string_to_string(const char *str); #if BB_MMU -#define parse_stream_dquoted(ctx, dest, input, dquote_end) \ +#define parse_stream_dquoted(as_string, dest, input, dquote_end) \ parse_stream_dquoted(dest, input, dquote_end) #endif -static int parse_stream_dquoted(struct parse_context *ctx, +static int parse_stream_dquoted(o_string *as_string, o_string *dest, struct in_str *input, int dquote_end); @@ -2275,7 +2275,38 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, _exit(EXIT_FAILURE); } -#if !BB_MMU +#if BB_MMU +static void reset_traps_to_defaults(void) +{ + unsigned sig; + int dirty; + + if (!G.traps) + return; + dirty = 0; + for (sig = 0; sig < NSIG; sig++) { + if (!G.traps[sig]) + continue; + free(G.traps[sig]); + G.traps[sig] = NULL; + /* There is no signal for 0 (EXIT) */ + if (sig == 0) + continue; + /* there was a trap handler, we are removing it + * (if sig has non-DFL handling, + * we don't need to do anything) */ + if (sig < 32 && (G.non_DFL_mask & (1 << sig))) + continue; + sigdelset(&G.blocked_set, sig); + dirty = 1; + } + if (dirty) + sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); +} +#define clean_up_after_re_execute() ((void)0) + +#else /* !BB_MMU */ + static void re_execute_shell(const char *s) NORETURN; static void re_execute_shell(const char *s) { @@ -2310,13 +2341,32 @@ static void re_execute_shell(const char *s) *pp++ = cur->varstr; } } +//TODO: pass functions + /* We can pass activated traps here. Say, -Tnn:trap_string + * + * However, POSIX says that subshells reset signals with traps + * to SIG_DFL. + * I tested bash-3.2 and it not only does that with true subshells + * of the form ( list ), but with any forked children shells. + * I set trap "echo W" WINCH; and then tried: + * + * { echo 1; sleep 20; echo 2; } & + * while true; do echo 1; sleep 20; echo 2; break; done & + * true | { echo 1; sleep 20; echo 2; } | cat + * + * In all these cases sending SIGWINCH to the child shell + * did not run the trap. If I add trap "echo V" WINCH; + * _inside_ group (just before echo 1), it works. + * + * I conclude it means we don't need to pass active traps here. + * exec syscall below resets them to SIG_DFL for us. + */ *pp++ = (char *) "-c"; *pp++ = (char *) s; pp2 = G.global_argv; while (*pp2) *pp++ = *pp2++; /* *pp = NULL; - is already there */ -//TODO: pass traps and functions debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); @@ -2343,8 +2393,6 @@ static void clean_up_after_re_execute(void) G.argv_from_re_execing = NULL; } } -#else -#define clean_up_after_re_execute() ((void)0) #endif static int run_list(struct pipe *pi); @@ -2373,6 +2421,7 @@ static void pseudo_exec(nommu_save_t *nommu_save, #if BB_MMU int rcode; debug_printf_exec("pseudo_exec: run_list\n"); + reset_traps_to_defaults(); rcode = run_list(command->group); /* OK to leak memory by not calling free_pipe_list, * since this process is about to exit */ @@ -3846,6 +3895,7 @@ static FILE *generate_stream_from_string(const char *s) /* Prevent it from trying to handle ctrl-z etc */ USE_HUSH_JOB(G.run_list_level = 1;) #if BB_MMU + reset_traps_to_defaults(); parse_and_run_string(s); _exit(G.last_return_code); #else @@ -4097,10 +4147,10 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, bool db /* Return code: 0 for OK, 1 for syntax error */ #if BB_MMU -#define handle_dollar(ctx, dest, input) \ +#define handle_dollar(as_string, dest, input) \ handle_dollar(dest, input) #endif -static int handle_dollar(struct parse_context *ctx, +static int handle_dollar(o_string *as_string, o_string *dest, struct in_str *input) { @@ -4112,7 +4162,7 @@ static int handle_dollar(struct parse_context *ctx, if (isalpha(ch)) { ch = i_getch(input); #if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); #endif make_var: o_addchr(dest, SPECIAL_VAR_SYMBOL); @@ -4125,7 +4175,7 @@ static int handle_dollar(struct parse_context *ctx, break; ch = i_getch(input); #if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); #endif } o_addchr(dest, SPECIAL_VAR_SYMBOL); @@ -4133,7 +4183,7 @@ static int handle_dollar(struct parse_context *ctx, make_one_char_var: ch = i_getch(input); #if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); #endif o_addchr(dest, SPECIAL_VAR_SYMBOL); debug_printf_parse(": '%c'\n", ch); @@ -4153,7 +4203,7 @@ static int handle_dollar(struct parse_context *ctx, o_addchr(dest, SPECIAL_VAR_SYMBOL); ch = i_getch(input); #if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); #endif /* XXX maybe someone will try to escape the '}' */ expansion = 0; @@ -4162,7 +4212,7 @@ static int handle_dollar(struct parse_context *ctx, while (1) { ch = i_getch(input); #if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); #endif if (ch == '}') break; @@ -4235,13 +4285,13 @@ static int handle_dollar(struct parse_context *ctx, # endif ch = i_getch(input); # if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); # endif # if ENABLE_SH_MATH_SUPPORT if (i_peek(input) == '(') { ch = i_getch(input); # if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); # endif o_addchr(dest, SPECIAL_VAR_SYMBOL); o_addchr(dest, /*quote_mask |*/ '+'); @@ -4250,10 +4300,10 @@ static int handle_dollar(struct parse_context *ctx, # endif add_till_closing_paren(dest, input, true); # if !BB_MMU - if (ctx) { - o_addstr(&ctx->as_string, dest->data + pos); - o_addchr(&ctx->as_string, ')'); - o_addchr(&ctx->as_string, ')'); + if (as_string) { + o_addstr(as_string, dest->data + pos); + o_addchr(as_string, ')'); + o_addchr(as_string, ')'); } # endif o_addchr(dest, SPECIAL_VAR_SYMBOL); @@ -4269,9 +4319,9 @@ static int handle_dollar(struct parse_context *ctx, # endif add_till_closing_paren(dest, input, false); # if !BB_MMU - if (ctx) { - o_addstr(&ctx->as_string, dest->data + pos); - o_addchr(&ctx->as_string, '`'); + if (as_string) { + o_addstr(as_string, dest->data + pos); + o_addchr(as_string, '`'); } # endif //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); @@ -4283,7 +4333,7 @@ static int handle_dollar(struct parse_context *ctx, case '_': ch = i_getch(input); #if !BB_MMU - if (ctx) o_addchr(&ctx->as_string, ch); + if (as_string) o_addchr(as_string, ch); #endif ch = i_peek(input); if (isalnum(ch)) { /* it's $_name or $_123 */ @@ -4302,10 +4352,10 @@ static int handle_dollar(struct parse_context *ctx, } #if BB_MMU -#define parse_stream_dquoted(ctx, dest, input, dquote_end) \ +#define parse_stream_dquoted(as_string, dest, input, dquote_end) \ parse_stream_dquoted(dest, input, dquote_end) #endif -static int parse_stream_dquoted(struct parse_context *ctx, +static int parse_stream_dquoted(o_string *as_string, o_string *dest, struct in_str *input, int dquote_end) @@ -4316,8 +4366,8 @@ static int parse_stream_dquoted(struct parse_context *ctx, again: ch = i_getch(input); #if !BB_MMU - if (ctx && ch != EOF) - o_addchr(&ctx->as_string, ch); + if (as_string && ch != EOF) + o_addchr(as_string, ch); #endif if (ch == dquote_end) { /* may be only '"' or EOF */ dest->nonnull = 1; @@ -4360,7 +4410,7 @@ static int parse_stream_dquoted(struct parse_context *ctx, goto again; } if (ch == '$') { - if (handle_dollar(ctx, dest, input) != 0) { + if (handle_dollar(as_string, dest, input) != 0) { debug_printf_parse("parse_stream_dquoted return 1: " "handle_dollar returned non-0\n"); return 1; @@ -4432,7 +4482,7 @@ static struct pipe *parse_stream(char **pstring, redir_type redir_style; if (is_in_dquote) { - if (parse_stream_dquoted(&ctx, &dest, input, '"')) { + if (parse_stream_dquoted(&ctx.as_string, &dest, input, '"')) { goto parse_error; } /* We reached closing '"' */ @@ -4579,8 +4629,7 @@ static struct pipe *parse_stream(char **pstring, #endif break; case '$': -//NOMMU TODO! - if (handle_dollar(&ctx, &dest, input) != 0) { + if (handle_dollar(&ctx.as_string, &dest, input) != 0) { debug_printf_parse("parse_stream parse error: " "handle_dollar returned non-0\n"); goto parse_error; @@ -5023,6 +5072,15 @@ int hush_main(int argc, char **argv) G.PS2 = "> "; #endif + /* Shell is non-interactive at first. We need to call + * block_signals(0) if we are going to execute "sh script", + * "sh -c cmds" or login shell's /etc/profile and friends. + * If we later decide that we are interactive, we run block_signals(0) + * (or re-run block_signals(1) if we ran block_signals(0) before) + * in order to intercept (more) signals. + */ + + /* Parse options */ /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ while (1) { opt = getopt(argc, argv, "c:xins" @@ -5136,7 +5194,9 @@ int hush_main(int argc, char **argv) goto final_return; } - /* Up to here, shell was non-interactive. Now it may become one. */ + /* Up to here, shell was non-interactive. Now it may become one. + * NB: don't forget to (re)run block_signals(0/1) as needed. + */ /* A shell is interactive if the '-i' flag was given, or if all of * the following conditions are met: