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--;
|
fg_pipe->alive_cmds--;
|
||||||
if (i == fg_pipe->num_cmds - 1) {
|
if (i == fg_pipe->num_cmds - 1) {
|
||||||
/* last process gives overall exitstatus */
|
/* last process gives overall exitstatus */
|
||||||
|
/* Note: is WIFSIGNALED, WEXITSTATUS = sig + 128 */
|
||||||
rcode = WEXITSTATUS(status);
|
rcode = WEXITSTATUS(status);
|
||||||
IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
|
IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
|
||||||
/* bash prints killing signal's name for *last*
|
/* bash prints killing signal's name for *last*
|
||||||
* process in pipe (prints just newline for SIGINT).
|
* process in pipe (prints just newline for SIGINT).
|
||||||
* we just print newline for any sig:
|
* Mimic this. Example: "sleep 5" + ^\
|
||||||
*/
|
*/
|
||||||
if (WIFSIGNALED(status)) {
|
if (WIFSIGNALED(status)) {
|
||||||
bb_putchar('\n');
|
int sig = WTERMSIG(status);
|
||||||
|
printf("%s\n", sig == SIGINT ? "" : get_signame(sig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -3489,6 +3491,7 @@ static int run_pipe(struct pipe *pi)
|
|||||||
debug_printf_exec(": builtin '%s' '%s'...\n",
|
debug_printf_exec(": builtin '%s' '%s'...\n",
|
||||||
x->cmd, argv_expanded[1]);
|
x->cmd, argv_expanded[1]);
|
||||||
rcode = x->function(argv_expanded) & 0xff;
|
rcode = x->function(argv_expanded) & 0xff;
|
||||||
|
fflush(NULL);
|
||||||
}
|
}
|
||||||
#if ENABLE_HUSH_FUNCTIONS
|
#if ENABLE_HUSH_FUNCTIONS
|
||||||
else {
|
else {
|
||||||
@ -6251,81 +6254,6 @@ int lash_main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Built-ins
|
* 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)
|
static int builtin_true(char **argv UNUSED_PARAM)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -6427,6 +6355,26 @@ static int builtin_exit(char **argv)
|
|||||||
hush_exit(xatoi(*argv) & 0xff);
|
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)
|
static int builtin_export(char **argv)
|
||||||
{
|
{
|
||||||
if (*++argv == NULL) {
|
if (*++argv == NULL) {
|
||||||
@ -6446,25 +6394,11 @@ static int builtin_export(char **argv)
|
|||||||
continue;
|
continue;
|
||||||
/* export var= */
|
/* export var= */
|
||||||
printf("export %.*s", (int)(p - s) + 1, s);
|
printf("export %.*s", (int)(p - s) + 1, s);
|
||||||
s = p + 1;
|
print_escaped(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('"');
|
|
||||||
}
|
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
/*fflush(stdout); - done after each builtin anyway */
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -6494,6 +6428,96 @@ static int builtin_export(char **argv)
|
|||||||
return EXIT_SUCCESS;
|
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
|
#if ENABLE_HUSH_JOB
|
||||||
/* built-in 'fg' and 'bg' handler */
|
/* built-in 'fg' and 'bg' handler */
|
||||||
static int builtin_fg_bg(char **argv)
|
static int builtin_fg_bg(char **argv)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user