diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-31 12:03:40 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-31 12:03:40 +0000 |
commit | abedaac8423d72325ae05602bf1bdcde28ecd7fa (patch) | |
tree | 144592f8f52aafafa0af0a70e9656dd1467b343d | |
parent | d5762932fbcbc0a385047945276f10e2f3fea12d (diff) | |
download | busybox-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.c | 205 |
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) | 903 | static void sigexit(int sig) NORETURN; |
906 | //// + (1 << SIGTERM) | 904 | static 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 */ |
913 | static unsigned maybe_set_sighandler(int sig, void (*handler)(int)) | 924 | static 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 */ |
930 | static void set_fatal_sighandler(void (*handler)(int)) | 937 | static 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` */ |
957 | static void IGN_jobctrl_signals(void) | 960 | static 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. */ | ||
1025 | static void sigexit(int sig) NORETURN; | ||
1026 | static 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(); |