hush: fix trap clearing in subshells on MMU; simplify NOMMU a bit:
authorDenis Vlasenko <vda.linux@googlemail.com>
Sun, 5 Apr 2009 20:33:27 +0000 (20:33 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sun, 5 Apr 2009 20:33:27 +0000 (20:33 -0000)
function                                             old     new   delta
parse_stream_dquoted                                 335     324     -11
handle_dollar                                        849     800     -49
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-60)             Total: -60 bytes

shell/hush.c

index a3f80d512007e6cec9bdaca59524371284f536d7..f8f7482b18fedaa74704786eee41dce114a9cb7e 100644 (file)
@@ -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: