summaryrefslogtreecommitdiffhomepage
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-18 12:58:19 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-18 12:58:19 +0000
commit38e626df4ddac2426afb336d2e1794913c022c15 (patch)
treecac5eaf01d2219d515c93bd4e9e4eacd83f2e396 /shell/hush.c
parent6a07d1fb5c89c7710d91b74b21fe26eafa1f7a72 (diff)
hush: fix "trap -- handler SIGs..."; escape handlers in "trap" output
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c210
1 files 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)