diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-18 12:58:19 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-18 12:58:19 +0000 |
commit | 38e626df4ddac2426afb336d2e1794913c022c15 (patch) | |
tree | cac5eaf01d2219d515c93bd4e9e4eacd83f2e396 /shell | |
parent | 6a07d1fb5c89c7710d91b74b21fe26eafa1f7a72 (diff) | |
download | busybox-w32-38e626df4ddac2426afb336d2e1794913c022c15.tar.gz busybox-w32-38e626df4ddac2426afb336d2e1794913c022c15.tar.bz2 busybox-w32-38e626df4ddac2426afb336d2e1794913c022c15.zip |
hush: fix "trap -- handler SIGs..."; escape handlers in "trap" output
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 210 |
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) | |||
3246 | fg_pipe->alive_cmds--; | 3246 | fg_pipe->alive_cmds--; |
3247 | if (i == fg_pipe->num_cmds - 1) { | 3247 | if (i == fg_pipe->num_cmds - 1) { |
3248 | /* last process gives overall exitstatus */ | 3248 | /* last process gives overall exitstatus */ |
3249 | /* Note: is WIFSIGNALED, WEXITSTATUS = sig + 128 */ | ||
3249 | rcode = WEXITSTATUS(status); | 3250 | rcode = WEXITSTATUS(status); |
3250 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) | 3251 | IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) |
3251 | /* bash prints killing signal's name for *last* | 3252 | /* bash prints killing signal's name for *last* |
3252 | * process in pipe (prints just newline for SIGINT). | 3253 | * process in pipe (prints just newline for SIGINT). |
3253 | * we just print newline for any sig: | 3254 | * Mimic this. Example: "sleep 5" + ^\ |
3254 | */ | 3255 | */ |
3255 | if (WIFSIGNALED(status)) { | 3256 | if (WIFSIGNALED(status)) { |
3256 | bb_putchar('\n'); | 3257 | int sig = WTERMSIG(status); |
3258 | printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); | ||
3257 | } | 3259 | } |
3258 | } | 3260 | } |
3259 | } else { | 3261 | } else { |
@@ -3489,6 +3491,7 @@ static int run_pipe(struct pipe *pi) | |||
3489 | debug_printf_exec(": builtin '%s' '%s'...\n", | 3491 | debug_printf_exec(": builtin '%s' '%s'...\n", |
3490 | x->cmd, argv_expanded[1]); | 3492 | x->cmd, argv_expanded[1]); |
3491 | rcode = x->function(argv_expanded) & 0xff; | 3493 | rcode = x->function(argv_expanded) & 0xff; |
3494 | fflush(NULL); | ||
3492 | } | 3495 | } |
3493 | #if ENABLE_HUSH_FUNCTIONS | 3496 | #if ENABLE_HUSH_FUNCTIONS |
3494 | else { | 3497 | else { |
@@ -6251,81 +6254,6 @@ int lash_main(int argc, char **argv) | |||
6251 | /* | 6254 | /* |
6252 | * Built-ins | 6255 | * Built-ins |
6253 | */ | 6256 | */ |
6254 | static int builtin_trap(char **argv) | ||
6255 | { | ||
6256 | int i; | ||
6257 | int sig; | ||
6258 | char *new_cmd; | ||
6259 | |||
6260 | if (!G.traps) | ||
6261 | G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); | ||
6262 | |||
6263 | argv++; | ||
6264 | if (!*argv) { | ||
6265 | /* No args: print all trapped. This isn't 100% correct as we | ||
6266 | * should be escaping the cmd so that it can be pasted back in | ||
6267 | */ | ||
6268 | for (i = 0; i < NSIG; ++i) | ||
6269 | if (G.traps[i]) | ||
6270 | printf("trap -- '%s' %s\n", G.traps[i], get_signame(i)); | ||
6271 | return EXIT_SUCCESS; | ||
6272 | } | ||
6273 | |||
6274 | new_cmd = NULL; | ||
6275 | i = 0; | ||
6276 | /* If first arg is decimal: reset all specified signals */ | ||
6277 | sig = bb_strtou(*argv, NULL, 10); | ||
6278 | if (errno == 0) { | ||
6279 | int ret; | ||
6280 | set_all: | ||
6281 | ret = EXIT_SUCCESS; | ||
6282 | while (*argv) { | ||
6283 | sig = get_signum(*argv++); | ||
6284 | if (sig < 0 || sig >= NSIG) { | ||
6285 | ret = EXIT_FAILURE; | ||
6286 | /* Mimic bash message exactly */ | ||
6287 | bb_perror_msg("trap: %s: invalid signal specification", argv[i]); | ||
6288 | continue; | ||
6289 | } | ||
6290 | |||
6291 | free(G.traps[sig]); | ||
6292 | G.traps[sig] = xstrdup(new_cmd); | ||
6293 | |||
6294 | debug_printf("trap: setting SIG%s (%i) to '%s'", | ||
6295 | get_signame(sig), sig, G.traps[sig]); | ||
6296 | |||
6297 | /* There is no signal for 0 (EXIT) */ | ||
6298 | if (sig == 0) | ||
6299 | continue; | ||
6300 | |||
6301 | if (new_cmd) { | ||
6302 | sigaddset(&G.blocked_set, sig); | ||
6303 | } else { | ||
6304 | /* There was a trap handler, we are removing it | ||
6305 | * (if sig has non-DFL handling, | ||
6306 | * we don't need to do anything) */ | ||
6307 | if (sig < 32 && (G.non_DFL_mask & (1 << sig))) | ||
6308 | continue; | ||
6309 | sigdelset(&G.blocked_set, sig); | ||
6310 | } | ||
6311 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | ||
6312 | } | ||
6313 | return ret; | ||
6314 | } | ||
6315 | |||
6316 | /* First arg is "-": reset all specified to default */ | ||
6317 | /* First arg is "": ignore all specified */ | ||
6318 | /* Everything else: execute first arg upon signal */ | ||
6319 | if (!argv[1]) { | ||
6320 | bb_error_msg("trap: invalid arguments"); | ||
6321 | return EXIT_FAILURE; | ||
6322 | } | ||
6323 | if (NOT_LONE_DASH(*argv)) | ||
6324 | new_cmd = *argv; | ||
6325 | argv++; | ||
6326 | goto set_all; | ||
6327 | } | ||
6328 | |||
6329 | static int builtin_true(char **argv UNUSED_PARAM) | 6257 | static int builtin_true(char **argv UNUSED_PARAM) |
6330 | { | 6258 | { |
6331 | return 0; | 6259 | return 0; |
@@ -6427,6 +6355,26 @@ static int builtin_exit(char **argv) | |||
6427 | hush_exit(xatoi(*argv) & 0xff); | 6355 | hush_exit(xatoi(*argv) & 0xff); |
6428 | } | 6356 | } |
6429 | 6357 | ||
6358 | static void print_escaped(const char *s) | ||
6359 | { | ||
6360 | do { | ||
6361 | if (*s != '\'') { | ||
6362 | const char *p; | ||
6363 | |||
6364 | p = strchrnul(s, '\''); | ||
6365 | /* print 'xxxx', possibly just '' */ | ||
6366 | printf("'%.*s'", (int)(p - s), s); | ||
6367 | if (*p == '\0') | ||
6368 | break; | ||
6369 | s = p; | ||
6370 | } | ||
6371 | /* s points to '; print "'''...'''" */ | ||
6372 | putchar('"'); | ||
6373 | do putchar('\''); while (*++s == '\''); | ||
6374 | putchar('"'); | ||
6375 | } while (*s); | ||
6376 | } | ||
6377 | |||
6430 | static int builtin_export(char **argv) | 6378 | static int builtin_export(char **argv) |
6431 | { | 6379 | { |
6432 | if (*++argv == NULL) { | 6380 | if (*++argv == NULL) { |
@@ -6446,25 +6394,11 @@ static int builtin_export(char **argv) | |||
6446 | continue; | 6394 | continue; |
6447 | /* export var= */ | 6395 | /* export var= */ |
6448 | printf("export %.*s", (int)(p - s) + 1, s); | 6396 | printf("export %.*s", (int)(p - s) + 1, s); |
6449 | s = p + 1; | 6397 | print_escaped(p + 1); |
6450 | while (*s) { | ||
6451 | if (*s != '\'') { | ||
6452 | p = strchrnul(s, '\''); | ||
6453 | /* print 'xxxx' */ | ||
6454 | printf("'%.*s'", (int)(p - s), s); | ||
6455 | if (*p == '\0') | ||
6456 | break; | ||
6457 | s = p; | ||
6458 | } | ||
6459 | /* s points to '; print ''...'''" */ | ||
6460 | putchar('"'); | ||
6461 | do putchar('\''); while (*++s == '\''); | ||
6462 | putchar('"'); | ||
6463 | } | ||
6464 | putchar('\n'); | 6398 | putchar('\n'); |
6465 | #endif | 6399 | #endif |
6466 | } | 6400 | } |
6467 | fflush(stdout); | 6401 | /*fflush(stdout); - done after each builtin anyway */ |
6468 | } | 6402 | } |
6469 | return EXIT_SUCCESS; | 6403 | return EXIT_SUCCESS; |
6470 | } | 6404 | } |
@@ -6494,6 +6428,96 @@ static int builtin_export(char **argv) | |||
6494 | return EXIT_SUCCESS; | 6428 | return EXIT_SUCCESS; |
6495 | } | 6429 | } |
6496 | 6430 | ||
6431 | static int builtin_trap(char **argv) | ||
6432 | { | ||
6433 | int i; | ||
6434 | int sig; | ||
6435 | char *new_cmd; | ||
6436 | |||
6437 | if (!G.traps) | ||
6438 | G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); | ||
6439 | |||
6440 | argv++; | ||
6441 | if (!*argv) { | ||
6442 | /* No args: print all trapped */ | ||
6443 | for (i = 0; i < NSIG; ++i) { | ||
6444 | if (G.traps[i]) { | ||
6445 | printf("trap -- "); | ||
6446 | print_escaped(G.traps[i]); | ||
6447 | printf(" %s\n", get_signame(i)); | ||
6448 | } | ||
6449 | } | ||
6450 | /*fflush(stdout); - done after each builtin anyway */ | ||
6451 | return EXIT_SUCCESS; | ||
6452 | } | ||
6453 | |||
6454 | new_cmd = NULL; | ||
6455 | i = 0; | ||
6456 | /* If first arg is a number: reset all specified signals */ | ||
6457 | sig = bb_strtou(*argv, NULL, 10); | ||
6458 | if (errno == 0) { | ||
6459 | int ret; | ||
6460 | process_sig_list: | ||
6461 | ret = EXIT_SUCCESS; | ||
6462 | while (*argv) { | ||
6463 | sig = get_signum(*argv++); | ||
6464 | if (sig < 0 || sig >= NSIG) { | ||
6465 | ret = EXIT_FAILURE; | ||
6466 | /* Mimic bash message exactly */ | ||
6467 | bb_perror_msg("trap: %s: invalid signal specification", argv[i]); | ||
6468 | continue; | ||
6469 | } | ||
6470 | |||
6471 | free(G.traps[sig]); | ||
6472 | G.traps[sig] = xstrdup(new_cmd); | ||
6473 | |||
6474 | debug_printf("trap: setting SIG%s (%i) to '%s'", | ||
6475 | get_signame(sig), sig, G.traps[sig]); | ||
6476 | |||
6477 | /* There is no signal for 0 (EXIT) */ | ||
6478 | if (sig == 0) | ||
6479 | continue; | ||
6480 | |||
6481 | if (new_cmd) { | ||
6482 | sigaddset(&G.blocked_set, sig); | ||
6483 | } else { | ||
6484 | /* There was a trap handler, we are removing it | ||
6485 | * (if sig has non-DFL handling, | ||
6486 | * we don't need to do anything) */ | ||
6487 | if (sig < 32 && (G.non_DFL_mask & (1 << sig))) | ||
6488 | continue; | ||
6489 | sigdelset(&G.blocked_set, sig); | ||
6490 | } | ||
6491 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | ||
6492 | } | ||
6493 | return ret; | ||
6494 | } | ||
6495 | |||
6496 | if (!argv[1]) { /* no second arg */ | ||
6497 | bb_error_msg("trap: invalid arguments"); | ||
6498 | return EXIT_FAILURE; | ||
6499 | } | ||
6500 | |||
6501 | /* First arg is "-": reset all specified to default */ | ||
6502 | /* First arg is "--": skip it, the rest is "handler SIGs..." */ | ||
6503 | /* Everything else: set arg as signal handler | ||
6504 | * (includes "" case, which ignores signal) */ | ||
6505 | if (argv[0][0] == '-') { | ||
6506 | if (argv[0][1] == '\0') { /* "-" */ | ||
6507 | /* new_cmd remains NULL: "reset these sigs" */ | ||
6508 | goto reset_traps; | ||
6509 | } | ||
6510 | if (argv[0][1] == '-' && argv[0][2] == '\0') { /* "--" */ | ||
6511 | argv++; | ||
6512 | } | ||
6513 | /* else: "-something", no special meaning */ | ||
6514 | } | ||
6515 | new_cmd = *argv; | ||
6516 | reset_traps: | ||
6517 | argv++; | ||
6518 | goto process_sig_list; | ||
6519 | } | ||
6520 | |||
6497 | #if ENABLE_HUSH_JOB | 6521 | #if ENABLE_HUSH_JOB |
6498 | /* built-in 'fg' and 'bg' handler */ | 6522 | /* built-in 'fg' and 'bg' handler */ |
6499 | static int builtin_fg_bg(char **argv) | 6523 | static int builtin_fg_bg(char **argv) |