hush: fix "trap -- handler SIGs..."; escape handlers in "trap" output
This commit is contained in:
parent
6a07d1fb5c
commit
38e626df4d
210
shell/hush.c
210
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)
|
||||
|
Loading…
Reference in New Issue
Block a user