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) |
