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 /shell | |
| 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
Diffstat (limited to 'shell')
| -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(); |
