hush: fix "trap -- handler SIGs..."; escape handlers in "trap" output
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 18 Apr 2009 12:58:19 +0000 (12:58 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 18 Apr 2009 12:58:19 +0000 (12:58 -0000)
shell/hush.c

index 0f93ae62bc5b17b4b1f104eacf78001281fbb07d..6e181ce992eb5e9a33a2038231eb4ac1cc989332 100644 (file)
@@ -3246,14 +3246,16 @@ static int checkjobs(struct pipe* fg_pipe)
                                        fg_pipe->alive_cmds--;
                                        if (i == fg_pipe->num_cmds - 1) {
                                                /* last process gives overall exitstatus */
+                                               /* Note: is WIFSIGNALED, WEXITSTATUS = sig + 128 */
                                                rcode = WEXITSTATUS(status);
                                                IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
                                                /* bash prints killing signal's name for *last*
                                                 * process in pipe (prints just newline for SIGINT).
-                                                * we just print newline for any sig:
+                                                * Mimic this. Example: "sleep 5" + ^\
                                                 */
                                                if (WIFSIGNALED(status)) {
-                                                       bb_putchar('\n');
+                                                       int sig = WTERMSIG(status);
+                                                       printf("%s\n", sig == SIGINT ? "" : get_signame(sig));
                                                }
                                        }
                                } else {
@@ -3489,6 +3491,7 @@ static int run_pipe(struct pipe *pi)
                                        debug_printf_exec(": builtin '%s' '%s'...\n",
                                                x->cmd, argv_expanded[1]);
                                        rcode = x->function(argv_expanded) & 0xff;
+                                       fflush(NULL);
                                }
 #if ENABLE_HUSH_FUNCTIONS
                                else {
@@ -6251,81 +6254,6 @@ int lash_main(int argc, char **argv)
 /*
  * Built-ins
  */
-static int builtin_trap(char **argv)
-{
-       int i;
-       int sig;
-       char *new_cmd;
-
-       if (!G.traps)
-               G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
-
-       argv++;
-       if (!*argv) {
-               /* No args: print all trapped. This isn't 100% correct as we
-                * should be escaping the cmd so that it can be pasted back in
-                */
-               for (i = 0; i < NSIG; ++i)
-                       if (G.traps[i])
-                               printf("trap -- '%s' %s\n", G.traps[i], get_signame(i));
-               return EXIT_SUCCESS;
-       }
-
-       new_cmd = NULL;
-       i = 0;
-       /* If first arg is decimal: reset all specified signals */
-       sig = bb_strtou(*argv, NULL, 10);
-       if (errno == 0) {
-               int ret;
- set_all:
-               ret = EXIT_SUCCESS;
-               while (*argv) {
-                       sig = get_signum(*argv++);
-                       if (sig < 0 || sig >= NSIG) {
-                               ret = EXIT_FAILURE;
-                               /* Mimic bash message exactly */
-                               bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
-                               continue;
-                       }
-
-                       free(G.traps[sig]);
-                       G.traps[sig] = xstrdup(new_cmd);
-
-                       debug_printf("trap: setting SIG%s (%i) to '%s'",
-                               get_signame(sig), sig, G.traps[sig]);
-
-                       /* There is no signal for 0 (EXIT) */
-                       if (sig == 0)
-                               continue;
-
-                       if (new_cmd) {
-                               sigaddset(&G.blocked_set, sig);
-                       } else {
-                               /* 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);
-                       }
-                       sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
-               }
-               return ret;
-       }
-
-       /* First arg is "-": reset all specified to default */
-       /* First arg is "": ignore all specified */
-       /* Everything else: execute first arg upon signal */
-       if (!argv[1]) {
-               bb_error_msg("trap: invalid arguments");
-               return EXIT_FAILURE;
-       }
-       if (NOT_LONE_DASH(*argv))
-               new_cmd = *argv;
-       argv++;
-       goto set_all;
-}
-
 static int builtin_true(char **argv UNUSED_PARAM)
 {
        return 0;
@@ -6427,6 +6355,26 @@ static int builtin_exit(char **argv)
        hush_exit(xatoi(*argv) & 0xff);
 }
 
+static void print_escaped(const char *s)
+{
+       do {
+               if (*s != '\'') {
+                       const char *p;
+
+                       p = strchrnul(s, '\'');
+                       /* print 'xxxx', possibly just '' */
+                       printf("'%.*s'", (int)(p - s), s);
+                       if (*p == '\0')
+                               break;
+                       s = p;
+               }
+               /* s points to '; print "'''...'''" */
+               putchar('"');
+               do putchar('\''); while (*++s == '\'');
+               putchar('"');
+       } while (*s);
+}
+
 static int builtin_export(char **argv)
 {
        if (*++argv == NULL) {
@@ -6446,25 +6394,11 @@ static int builtin_export(char **argv)
                                        continue;
                                /* export var= */
                                printf("export %.*s", (int)(p - s) + 1, s);
-                               s = p + 1;
-                               while (*s) {
-                                       if (*s != '\'') {
-                                               p = strchrnul(s, '\'');
-                                               /* print 'xxxx' */
-                                               printf("'%.*s'", (int)(p - s), s);
-                                               if (*p == '\0')
-                                                       break;
-                                               s = p;
-                                       }
-                                       /* s points to '; print ''...'''" */
-                                       putchar('"');
-                                       do putchar('\''); while (*++s == '\'');
-                                       putchar('"');
-                               }
+                               print_escaped(p + 1);
                                putchar('\n');
 #endif
                        }
-                       fflush(stdout);
+                       /*fflush(stdout); - done after each builtin anyway */
                }
                return EXIT_SUCCESS;
        }
@@ -6494,6 +6428,96 @@ static int builtin_export(char **argv)
        return EXIT_SUCCESS;
 }
 
+static int builtin_trap(char **argv)
+{
+       int i;
+       int sig;
+       char *new_cmd;
+
+       if (!G.traps)
+               G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
+
+       argv++;
+       if (!*argv) {
+               /* No args: print all trapped */
+               for (i = 0; i < NSIG; ++i) {
+                       if (G.traps[i]) {
+                               printf("trap -- ");
+                               print_escaped(G.traps[i]);
+                               printf(" %s\n", get_signame(i));
+                       }
+               }
+               /*fflush(stdout); - done after each builtin anyway */
+               return EXIT_SUCCESS;
+       }
+
+       new_cmd = NULL;
+       i = 0;
+       /* If first arg is a number: reset all specified signals */
+       sig = bb_strtou(*argv, NULL, 10);
+       if (errno == 0) {
+               int ret;
+ process_sig_list:
+               ret = EXIT_SUCCESS;
+               while (*argv) {
+                       sig = get_signum(*argv++);
+                       if (sig < 0 || sig >= NSIG) {
+                               ret = EXIT_FAILURE;
+                               /* Mimic bash message exactly */
+                               bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
+                               continue;
+                       }
+
+                       free(G.traps[sig]);
+                       G.traps[sig] = xstrdup(new_cmd);
+
+                       debug_printf("trap: setting SIG%s (%i) to '%s'",
+                               get_signame(sig), sig, G.traps[sig]);
+
+                       /* There is no signal for 0 (EXIT) */
+                       if (sig == 0)
+                               continue;
+
+                       if (new_cmd) {
+                               sigaddset(&G.blocked_set, sig);
+                       } else {
+                               /* 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);
+                       }
+                       sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
+               }
+               return ret;
+       }
+
+       if (!argv[1]) { /* no second arg */
+               bb_error_msg("trap: invalid arguments");
+               return EXIT_FAILURE;
+       }
+
+       /* First arg is "-": reset all specified to default */
+       /* First arg is "--": skip it, the rest is "handler SIGs..." */
+       /* Everything else: set arg as signal handler
+        * (includes "" case, which ignores signal) */
+       if (argv[0][0] == '-') {
+               if (argv[0][1] == '\0') { /* "-" */
+                       /* new_cmd remains NULL: "reset these sigs" */
+                       goto reset_traps;
+               }
+               if (argv[0][1] == '-' && argv[0][2] == '\0') { /* "--" */
+                       argv++;
+               }
+               /* else: "-something", no special meaning */
+       }
+       new_cmd = *argv;
+ reset_traps:
+       argv++;
+       goto process_sig_list;
+}
+
 #if ENABLE_HUSH_JOB
 /* built-in 'fg' and 'bg' handler */
 static int builtin_fg_bg(char **argv)