aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2009-03-29 23:49:37 +0000
committerMike Frysinger <vapier@gentoo.org>2009-03-29 23:49:37 +0000
commit9f8128f48005da550e32f38e97ce349ba36faf8b (patch)
tree194be90516b34ee890219fc343d111c5a977840f
parent0d907eab6cd424963bf8b788710e7a68d50d0511 (diff)
downloadbusybox-w32-9f8128f48005da550e32f38e97ce349ba36faf8b.tar.gz
busybox-w32-9f8128f48005da550e32f38e97ce349ba36faf8b.tar.bz2
busybox-w32-9f8128f48005da550e32f38e97ce349ba36faf8b.zip
first pass at `trap` support in hush
-rw-r--r--shell/hush.c139
1 files changed, 129 insertions, 10 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 5203f2eef..17673c0cb 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -489,6 +489,10 @@ struct globals {
489#endif 489#endif
490 unsigned char charmap[256]; 490 unsigned char charmap[256];
491 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 491 char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
492 struct {
493 char *cmd;
494 struct sigaction oact;
495 } *traps;
492}; 496};
493 497
494#define G (*ptr_to_globals) 498#define G (*ptr_to_globals)
@@ -517,6 +521,8 @@ static int builtin_help(char **argv);
517static int builtin_pwd(char **argv); 521static int builtin_pwd(char **argv);
518static int builtin_read(char **argv); 522static int builtin_read(char **argv);
519static int builtin_test(char **argv); 523static int builtin_test(char **argv);
524static void handle_trap(int sig);
525static int builtin_trap(char **argv);
520static int builtin_true(char **argv); 526static int builtin_true(char **argv);
521static int builtin_set(char **argv); 527static int builtin_set(char **argv);
522static int builtin_set_mode(const char, const char); 528static int builtin_set_mode(const char, const char);
@@ -578,8 +584,8 @@ static const struct built_in_command bltins[] = {
578// BLTIN("return", builtin_not_written, "Return from a function"), 584// BLTIN("return", builtin_not_written, "Return from a function"),
579 BLTIN("set" , builtin_set, "Set/unset shell local variables"), 585 BLTIN("set" , builtin_set, "Set/unset shell local variables"),
580 BLTIN("shift" , builtin_shift, "Shift positional parameters"), 586 BLTIN("shift" , builtin_shift, "Shift positional parameters"),
581// BLTIN("trap" , builtin_not_written, "Trap signals"),
582 BLTIN("test" , builtin_test, "Test condition"), 587 BLTIN("test" , builtin_test, "Test condition"),
588 BLTIN("trap" , builtin_trap, "Trap signals"),
583// BLTIN("ulimit", builtin_not_written, "Control resource limits"), 589// BLTIN("ulimit", builtin_not_written, "Control resource limits"),
584 BLTIN("umask" , builtin_umask, "Set file creation mask"), 590 BLTIN("umask" , builtin_umask, "Set file creation mask"),
585 BLTIN("unset" , builtin_unset, "Unset environment variable"), 591 BLTIN("unset" , builtin_unset, "Unset environment variable"),
@@ -857,22 +863,27 @@ static void sigexit(int sig)
857 kill_myself_with_sig(sig); /* does not return */ 863 kill_myself_with_sig(sig); /* does not return */
858} 864}
859 865
860/* Restores tty foreground process group, and exits. */
861static void hush_exit(int exitcode) NORETURN;
862static void hush_exit(int exitcode)
863{
864 fflush(NULL); /* flush all streams */
865 sigexit(- (exitcode & 0xff));
866}
867
868#else /* !JOB */ 866#else /* !JOB */
869 867
870#define set_fatal_sighandler(handler) ((void)0) 868#define set_fatal_sighandler(handler) ((void)0)
871#define set_jobctrl_sighandler(handler) ((void)0) 869#define set_jobctrl_sighandler(handler) ((void)0)
872#define hush_exit(e) exit(e)
873 870
874#endif /* JOB */ 871#endif /* JOB */
875 872
873/* Restores tty foreground process group, and exits. */
874static void hush_exit(int exitcode) NORETURN;
875static void hush_exit(int exitcode)
876{
877 if (G.traps && G.traps[0].cmd)
878 handle_trap(0);
879
880 if (ENABLE_HUSH_JOB) {
881 fflush(NULL); /* flush all streams */
882 sigexit(- (exitcode & 0xff));
883 } else
884 exit(exitcode);
885}
886
876 887
877static const char *set_cwd(void) 888static const char *set_cwd(void)
878{ 889{
@@ -4516,6 +4527,114 @@ int lash_main(int argc, char **argv)
4516/* 4527/*
4517 * Built-ins 4528 * Built-ins
4518 */ 4529 */
4530/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_28
4531 *
4532 * Traps are also evaluated immediately instead of being delayed properly:
4533 * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_11
4534 * Example: hush -c 'trap "echo hi" 31; sleep 10; echo moo' & sleep 1; kill -31 $!
4535 * "hi" should not be displayed until the sleep finishes
4536 * This will have to get fixed ...
4537 */
4538static void handle_trap(int sig)
4539{
4540 int save_errno, save_rcode;
4541 char *argv[] = { NULL, G.traps[sig].cmd, NULL };
4542 /* Race! We transitioned from handled to ignore/default, but
4543 * the signal came in after updating .cmd but before we could
4544 * register the new signal handler.
4545 */
4546 if (!argv[1] || argv[1][0] == '\0')
4547 return;
4548 /* need to save/restore errno/$? across traps */
4549 save_errno = errno;
4550 save_rcode = G.last_return_code;
4551 builtin_eval(argv);
4552 errno = save_errno;
4553 G.last_return_code = save_rcode;
4554}
4555static int builtin_trap(char **argv)
4556{
4557 size_t i;
4558 int sig;
4559 bool ign = false;
4560 char *new_cmd = NULL;
4561
4562 if (!G.traps)
4563 G.traps = xzalloc(sizeof(*G.traps) * NSIG);
4564
4565 if (!argv[1]) {
4566 /* No args: print all trapped. This isn't 100% correct as we should
4567 * be escaping the cmd so that it can be pasted back in ...
4568 */
4569 for (i = 0; i < NSIG; ++i)
4570 if (G.traps[i].cmd)
4571 printf("trap -- '%s' %s\n", G.traps[i].cmd, get_signame(i));
4572 return EXIT_SUCCESS;
4573 }
4574
4575 /* first arg is decimal: reset all specified */
4576 sig = bb_strtou(argv[1], NULL, 10);
4577 if (errno == 0) {
4578 int ret;
4579 i = 0;
4580 set_all:
4581 ret = EXIT_SUCCESS;
4582 while (argv[++i]) {
4583 char *old_cmd;
4584
4585 sig = get_signum(argv[i]);
4586 if (sig < 0 || sig >= NSIG) {
4587 ret = EXIT_FAILURE;
4588 bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
4589 continue;
4590 }
4591
4592 /* Make sure .cmd is always a valid command list since
4593 * signals can occur at any time ...
4594 */
4595 old_cmd = G.traps[sig].cmd;
4596 G.traps[sig].cmd = xstrdup(new_cmd);
4597 free(old_cmd);
4598
4599 debug_printf("trap: setting SIG%s (%i) to: %s",
4600 get_signame(sig), sig, G.traps[sig].cmd);
4601
4602 /* There is no signal for 0 (EXIT) */
4603 if (sig == 0)
4604 continue;
4605
4606 if (new_cmd) {
4607 /* add/update a handler */
4608 struct sigaction act = {
4609 .sa_handler = ign ? SIG_IGN : handle_trap,
4610 .sa_flags = SA_RESTART,
4611 };
4612 sigemptyset(&act.sa_mask);
4613 sigaction(sig, &act, old_cmd ? NULL : &G.traps[sig].oact);
4614 } else if (old_cmd && !new_cmd)
4615 /* there was a handler, and we are removing it */
4616 sigaction_set(sig, &G.traps[sig].oact);
4617 }
4618 return ret;
4619 }
4620
4621 /* first arg is "-": reset all specified to default */
4622 /* first arg is "": ignore all specified */
4623 /* everything else: execute first arg upon signal */
4624 if (!argv[2]) {
4625 bb_error_msg("trap: invalid arguments");
4626 return EXIT_FAILURE;
4627 }
4628 if (LONE_DASH(argv[1]))
4629 /* nothing! */;
4630 else
4631 new_cmd = argv[1];
4632 if (argv[1][0] == '\0')
4633 ign = true;
4634 i = 1;
4635 goto set_all;
4636}
4637
4519static int builtin_true(char **argv UNUSED_PARAM) 4638static int builtin_true(char **argv UNUSED_PARAM)
4520{ 4639{
4521 return 0; 4640 return 0;