From 38e626df4ddac2426afb336d2e1794913c022c15 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 18 Apr 2009 12:58:19 +0000 Subject: [PATCH] hush: fix "trap -- handler SIGs..."; escape handlers in "trap" output --- shell/hush.c | 210 ++++++++++++++++++++++++++++----------------------- 1 file changed, 117 insertions(+), 93 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 0f93ae62b..6e181ce99 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -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)