aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-03-31 12:03:40 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-03-31 12:03:40 +0000
commitabedaac8423d72325ae05602bf1bdcde28ecd7fa (patch)
tree144592f8f52aafafa0af0a70e9656dd1467b343d
parentd5762932fbcbc0a385047945276f10e2f3fea12d (diff)
downloadbusybox-w32-abedaac8423d72325ae05602bf1bdcde28ecd7fa.tar.gz
busybox-w32-abedaac8423d72325ae05602bf1bdcde28ecd7fa.tar.bz2
busybox-w32-abedaac8423d72325ae05602bf1bdcde28ecd7fa.zip
hush: do not reset sighaldlers after fork - instead, prevent them from doing any harm
if they will be called. saves many sigaction calls on every fork. function old new delta hush_main 887 971 +84 sigexit 54 65 +11 run_list 2006 2001 -5 maybe_set_sighandler 76 50 -26 set_fatal_sighandler 186 - -186 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 2/2 up/down: 95/-217) Total: -122 bytes
-rw-r--r--shell/hush.c205
1 files changed, 59 insertions, 146 deletions
diff --git a/shell/hush.c b/shell/hush.c
index bcccfb0bb..01690d9bc 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -493,8 +493,6 @@ struct globals {
493 char **traps; /* char *traps[NSIG] */ 493 char **traps; /* char *traps[NSIG] */
494 /* which signals have non-DFL handler (even with no traps set)? */ 494 /* which signals have non-DFL handler (even with no traps set)? */
495 unsigned non_DFL_mask; 495 unsigned non_DFL_mask;
496 /* which signals are known to be IGNed on entry to shell? */
497 unsigned IGN_mask;
498 sigset_t blocked_set; 496 sigset_t blocked_set;
499 sigset_t inherited_set; 497 sigset_t inherited_set;
500}; 498};
@@ -895,66 +893,71 @@ static void check_and_run_traps(void)
895 } 893 }
896} 894}
897 895
898/* The stuff below needs to be migrated to "Special action" above */ 896#if ENABLE_HUSH_JOB
899 897
900/////* Signals are grouped, we handle them in batches */ 898/* Restores tty foreground process group, and exits.
901////static void set_misc_sighandler(void (*handler)(int)) 899 * May be called as signal handler for fatal signal
902////{ 900 * (will faithfully resend signal to itself, producing correct exit state)
903//// bb_signals(0 901 * or called directly with -EXITCODE.
904//// + (1 << SIGINT) 902 * We also call it if xfunc is exiting. */
905//// + (1 << SIGQUIT) 903static void sigexit(int sig) NORETURN;
906//// + (1 << SIGTERM) 904static void sigexit(int sig)
907//// , handler); 905{
908////} 906 /* Disable all signals: job control, SIGPIPE, etc. */
907 sigprocmask_allsigs(SIG_BLOCK);
909 908
910#if ENABLE_HUSH_JOB 909#if ENABLE_HUSH_INTERACTIVE
910 /* Careful: we can end up here after [v]fork. Do not restore
911 * tty pgrp, only top-level shell process does that */
912 if (G.interactive_fd && getpid() == G.root_pid)
913 tcsetpgrp(G.interactive_fd, G.saved_tty_pgrp);
914#endif
915
916 /* Not a signal, just exit */
917 if (sig <= 0)
918 _exit(- sig);
919
920 kill_myself_with_sig(sig); /* does not return */
921}
911 922
912/* helper */ 923/* helper */
913static unsigned maybe_set_sighandler(int sig, void (*handler)(int)) 924static void maybe_set_sighandler(int sig)
914{ 925{
926 void (*handler)(int);
915 /* non_DFL_mask'ed signals are, well, masked, 927 /* non_DFL_mask'ed signals are, well, masked,
916 * no need to set handler for them. 928 * no need to set handler for them.
917 * IGN_mask'ed signals were found to be IGN on entry,
918 * do not change that -> no need to set handler for them either
919 */ 929 */
920 unsigned ign = ((G.IGN_mask|G.non_DFL_mask) >> sig) & 1; 930 if (!((G.non_DFL_mask >> sig) & 1)) {
921 if (!ign) { 931 handler = signal(sig, sigexit);
922 handler = signal(sig, handler); 932 if (handler == SIG_IGN) /* restore back to IGN! */
923 ign = (handler == SIG_IGN);
924 if (ign) /* restore back to IGN! */
925 signal(sig, handler); 933 signal(sig, handler);
926 } 934 }
927 return ign << sig; /* pass back knowledge about SIG_IGN */
928} 935}
929/* Used only to set handler to restore pgrp on exit, and to reset it to DFL */ 936/* Used only to set handler to restore pgrp on exit, and to reset it to DFL */
930static void set_fatal_sighandler(void (*handler)(int)) 937static void set_fatal_signals_to_sigexit(void)
931{ 938{
932 unsigned mask = 0;
933
934 if (HUSH_DEBUG) { 939 if (HUSH_DEBUG) {
935 mask |= maybe_set_sighandler(SIGILL , handler); 940 maybe_set_sighandler(SIGILL );
936 mask |= maybe_set_sighandler(SIGFPE , handler); 941 maybe_set_sighandler(SIGFPE );
937 mask |= maybe_set_sighandler(SIGBUS , handler); 942 maybe_set_sighandler(SIGBUS );
938 mask |= maybe_set_sighandler(SIGSEGV, handler); 943 maybe_set_sighandler(SIGSEGV);
939 mask |= maybe_set_sighandler(SIGTRAP, handler); 944 maybe_set_sighandler(SIGTRAP);
940 } /* else: hush is perfect. what SEGV? */ 945 } /* else: hush is perfect. what SEGV? */
941 946
942 mask |= maybe_set_sighandler(SIGABRT, handler); 947 maybe_set_sighandler(SIGABRT);
943 948
944 /* bash 3.2 seems to handle these just like 'fatal' ones */ 949 /* bash 3.2 seems to handle these just like 'fatal' ones */
945 mask |= maybe_set_sighandler(SIGPIPE, handler); 950 maybe_set_sighandler(SIGPIPE);
946 mask |= maybe_set_sighandler(SIGALRM, handler); 951 maybe_set_sighandler(SIGALRM);
947 mask |= maybe_set_sighandler(SIGHUP , handler); 952 maybe_set_sighandler(SIGHUP );
948 953
949 /* if we aren't interactive... but in this case 954 /* if we aren't interactive... but in this case
950 * we never want to restore pgrp on exit, and this fn is not called */ 955 * we never want to restore pgrp on exit, and this fn is not called */
951 /*mask |= maybe_set_sighandler(SIGTERM, handler); */ 956 /*maybe_set_sighandler(SIGTERM);*/
952 /*mask |= maybe_set_sighandler(SIGINT , handler); */ 957 /*maybe_set_sighandler(SIGINT );*/
953
954 G.IGN_mask = mask;
955} 958}
956/* Used only to suppress ^Z in `cmd` */ 959/* Used only to suppress ^Z in `cmd` */
957static void IGN_jobctrl_signals(void) 960static void set_jobctrl_signals_to_IGN(void)
958{ 961{
959 bb_signals(0 962 bb_signals(0
960 + (1 << SIGTSTP) 963 + (1 << SIGTSTP)
@@ -962,88 +965,11 @@ static void IGN_jobctrl_signals(void)
962 + (1 << SIGTTOU) 965 + (1 << SIGTTOU)
963 , SIG_IGN); 966 , SIG_IGN);
964} 967}
965/* SIGCHLD is special and handled separately */
966
967////static void set_every_sighandler(void (*handler)(int))
968////{
969//// set_fatal_sighandler(handler);
970//// set_jobctrl_sighandler(handler);
971//// set_misc_sighandler(handler);
972//// signal(SIGCHLD, handler);
973////}
974
975////static void handler_ctrl_c(int sig UNUSED_PARAM)
976////{
977//// debug_printf_jobs("got sig %d\n", sig);
978////// as usual we can have all kinds of nasty problems with leaked malloc data here
979//// siglongjmp(G.toplevel_jb, 1);
980////}
981
982////static void handler_ctrl_z(int sig UNUSED_PARAM)
983////{
984//// pid_t pid;
985////
986//// debug_printf_jobs("got tty sig %d in pid %d\n", sig, getpid());
987////
988//// if (!BB_MMU) {
989//// fputs("Sorry, backgrounding (CTRL+Z) of foreground scripts not supported on nommu\n", stderr);
990//// return;
991//// }
992////
993//// pid = fork();
994//// if (pid < 0) /* can't fork. Pretend there was no ctrl-Z */
995//// return;
996//// G.ctrl_z_flag = 1;
997//// if (!pid) { /* child */
998//// if (ENABLE_HUSH_JOB)
999//// die_sleep = 0; /* let nofork's xfuncs die */
1000//// bb_setpgrp();
1001//// debug_printf_jobs("set pgrp for child %d ok\n", getpid());
1002//////// set_every_sighandler(SIG_DFL);
1003//// raise(SIGTSTP); /* resend TSTP so that child will be stopped */
1004//// debug_printf_jobs("returning in child\n");
1005//// /* return to nofork, it will eventually exit now,
1006//// * not return back to shell */
1007//// return;
1008//// }
1009//// /* parent */
1010//// /* finish filling up pipe info */
1011//// G.toplevel_list->pgrp = pid; /* child is in its own pgrp */
1012//// G.toplevel_list->cmds[0].pid = pid;
1013//// /* parent needs to longjmp out of running nofork.
1014//// * we will "return" exitcode 0, with child put in background */
1015////// as usual we can have all kinds of nasty problems with leaked malloc data here
1016//// debug_printf_jobs("siglongjmp in parent\n");
1017//// siglongjmp(G.toplevel_jb, 1);
1018////}
1019
1020/* Restores tty foreground process group, and exits.
1021 * May be called as signal handler for fatal signal
1022 * (will faithfully resend signal to itself, producing correct exit state)
1023 * or called directly with -EXITCODE.
1024 * We also call it if xfunc is exiting. */
1025static void sigexit(int sig) NORETURN;
1026static void sigexit(int sig)
1027{
1028 /* Disable all signals: job control, SIGPIPE, etc. */
1029 sigprocmask_allsigs(SIG_BLOCK);
1030
1031#if ENABLE_HUSH_INTERACTIVE
1032 if (G.interactive_fd)
1033 tcsetpgrp(G.interactive_fd, G.saved_tty_pgrp);
1034#endif
1035
1036 /* Not a signal, just exit */
1037 if (sig <= 0)
1038 _exit(- sig);
1039
1040 kill_myself_with_sig(sig); /* does not return */
1041}
1042 968
1043#else /* !JOB */ 969#else /* !JOB */
1044 970
1045#define set_fatal_sighandler(handler) ((void)0) 971#define set_fatal_signals_to_sigexit(handler) ((void)0)
1046#define IGN_jobctrl_signals(handler) ((void)0) 972#define set_jobctrl_signals_to_IGN(handler) ((void)0)
1047 973
1048#endif /* JOB */ 974#endif /* JOB */
1049 975
@@ -1057,11 +983,12 @@ static void hush_exit(int exitcode)
1057 free(argv[1]); 983 free(argv[1]);
1058 } 984 }
1059 985
1060 if (ENABLE_HUSH_JOB) { 986#if ENABLE_HUSH_JOB
1061 fflush(NULL); /* flush all streams */ 987 fflush(NULL); /* flush all streams */
1062 sigexit(- (exitcode & 0xff)); 988 sigexit(- (exitcode & 0xff));
1063 } else 989#else
1064 exit(exitcode); 990 exit(exitcode);
991#endif
1065} 992}
1066 993
1067 994
@@ -2641,10 +2568,6 @@ static int run_pipe(struct pipe *pi)
2641 * might include `cmd` runs! Do not rerun it! We *must* 2568 * might include `cmd` runs! Do not rerun it! We *must*
2642 * use argv_expanded if it's non-NULL */ 2569 * use argv_expanded if it's non-NULL */
2643 2570
2644 /* Disable job control signals for shell (parent) and
2645 * for initial child code after fork */
2646//// set_jobctrl_sighandler(SIG_IGN);
2647
2648 /* Going to fork a child per each pipe member */ 2571 /* Going to fork a child per each pipe member */
2649 pi->alive_cmds = 0; 2572 pi->alive_cmds = 0;
2650 nextin = 0; 2573 nextin = 0;
@@ -2677,8 +2600,6 @@ static int run_pipe(struct pipe *pi)
2677 * with pgid == pid_of_first_child_in_pipe */ 2600 * with pgid == pid_of_first_child_in_pipe */
2678 if (G.run_list_level == 1 && G.interactive_fd) { 2601 if (G.run_list_level == 1 && G.interactive_fd) {
2679 pid_t pgrp; 2602 pid_t pgrp;
2680 /* Don't do pgrp restore anymore on fatal signals */
2681 set_fatal_sighandler(SIG_DFL);
2682 pgrp = pi->pgrp; 2603 pgrp = pi->pgrp;
2683 if (pgrp < 0) /* true for 1st process only */ 2604 if (pgrp < 0) /* true for 1st process only */
2684 pgrp = getpid(); 2605 pgrp = getpid();
@@ -2698,9 +2619,8 @@ static int run_pipe(struct pipe *pi)
2698 setup_redirects(command, NULL); 2619 setup_redirects(command, NULL);
2699 2620
2700 /* Restore default handlers just prior to exec */ 2621 /* Restore default handlers just prior to exec */
2701//// set_jobctrl_sighandler(SIG_DFL); 2622 /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */
2702//// set_misc_sighandler(SIG_DFL); 2623
2703//// signal(SIGCHLD, SIG_DFL);
2704 /* Stores to nommu_save list of env vars putenv'ed 2624 /* Stores to nommu_save list of env vars putenv'ed
2705 * (NOMMU, on MMU we don't need that) */ 2625 * (NOMMU, on MMU we don't need that) */
2706 /* cast away volatility... */ 2626 /* cast away volatility... */
@@ -2877,7 +2797,7 @@ static int run_list(struct pipe *pi)
2877 * in order to return, no direct "return" statements please. 2797 * in order to return, no direct "return" statements please.
2878 * This helps to ensure that no memory is leaked. */ 2798 * This helps to ensure that no memory is leaked. */
2879 2799
2880//TODO: needs re-thinking 2800////TODO: ctrl-Z handling needs re-thinking and re-testing
2881 2801
2882#if ENABLE_HUSH_JOB 2802#if ENABLE_HUSH_JOB
2883 /* Example of nested list: "while true; do { sleep 1 | exit 2; } done". 2803 /* Example of nested list: "while true; do { sleep 1 | exit 2; } done".
@@ -3674,12 +3594,11 @@ static FILE *generate_stream_from_list(struct pipe *head)
3674#endif 3594#endif
3675 /* Process substitution is not considered to be usual 3595 /* Process substitution is not considered to be usual
3676 * 'command execution'. 3596 * 'command execution'.
3677 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. */ 3597 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not.
3678//// /* Not needed, we are relying on it being disabled 3598 */
3679//// * everywhere outside actual command execution. */ 3599 set_jobctrl_signals_to_IGN();
3680 IGN_jobctrl_signals(); 3600
3681//// set_misc_sighandler(SIG_DFL); 3601 /* Note: freeing 'head' here would break NOMMU. */
3682 /* Freeing 'head' here would break NOMMU. */
3683 _exit(run_list(head)); 3602 _exit(run_list(head));
3684 } 3603 }
3685 close(channel[1]); 3604 close(channel[1]);
@@ -4493,13 +4412,8 @@ static void setup_job_control(void)
4493 shell_pgrp = getpgrp(); 4412 shell_pgrp = getpgrp();
4494 } 4413 }
4495 4414
4496 /* Ignore job-control and misc signals. */
4497//// set_jobctrl_sighandler(SIG_IGN);
4498//// set_misc_sighandler(SIG_IGN);
4499//huh? signal(SIGCHLD, SIG_IGN);
4500
4501 /* We _must_ restore tty pgrp on fatal signals */ 4415 /* We _must_ restore tty pgrp on fatal signals */
4502 set_fatal_sighandler(sigexit); 4416 set_fatal_signals_to_sigexit();
4503 4417
4504 /* Put ourselves in our own process group. */ 4418 /* Put ourselves in our own process group. */
4505 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 4419 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
@@ -4682,7 +4596,6 @@ int hush_main(int argc, char **argv)
4682 } 4596 }
4683 if (G.interactive_fd) { 4597 if (G.interactive_fd) {
4684 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC); 4598 fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC);
4685//// set_misc_sighandler(SIG_IGN);
4686 } 4599 }
4687 } 4600 }
4688 init_signal_mask(); 4601 init_signal_mask();