diff options
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 65 |
1 files changed, 36 insertions, 29 deletions
diff --git a/shell/hush.c b/shell/hush.c index 21fa95429..a96b179c6 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -753,14 +753,14 @@ static void free_strings(char **strings) | |||
| 753 | 753 | ||
| 754 | /* Basic theory of signal handling in shell | 754 | /* Basic theory of signal handling in shell |
| 755 | * ======================================== | 755 | * ======================================== |
| 756 | * This does not describe what hush does, rahter, it is current understanding | 756 | * This does not describe what hush does, rather, it is current understanding |
| 757 | * what it _should_ do. | 757 | * what it _should_ do. If it doesn't, it's a bug. |
| 758 | * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap | 758 | * http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap |
| 759 | * | 759 | * |
| 760 | * Signals are handled only after each pipe ("cmd | cmd | cmd" thing) | 760 | * Signals are handled only after each pipe ("cmd | cmd | cmd" thing) |
| 761 | * is finished or backgrounded. It is the same in interactive and | 761 | * is finished or backgrounded. It is the same in interactive and |
| 762 | * non-interactive shells, and is the same regardless of whether | 762 | * non-interactive shells, and is the same regardless of whether |
| 763 | * a user trap handler is installed or a default one is in effect. | 763 | * a user trap handler is installed or a shell special one is in effect. |
| 764 | * ^C or ^Z from keyboard seem to execute "at once" because it usually | 764 | * ^C or ^Z from keyboard seem to execute "at once" because it usually |
| 765 | * backgrounds (i.e. stops) or kills all members of currently running | 765 | * backgrounds (i.e. stops) or kills all members of currently running |
| 766 | * pipe. | 766 | * pipe. |
| @@ -770,33 +770,38 @@ static void free_strings(char **strings) | |||
| 770 | * | 770 | * |
| 771 | * Trap handlers will execute even within trap handlers. (right?) | 771 | * Trap handlers will execute even within trap handlers. (right?) |
| 772 | * | 772 | * |
| 773 | * User trap handlers are forgotten when subshell is entered. | 773 | * User trap handlers are forgotten when subshell ("(cmd)") is entered. [TODO] |
| 774 | * | 774 | * |
| 775 | * If job control is off, backgrounded commands ("cmd &") | 775 | * If job control is off, backgrounded commands ("cmd &") |
| 776 | * have SIGINT, SIGQUIT set to SIG_IGN. | 776 | * have SIGINT, SIGQUIT set to SIG_IGN. |
| 777 | * | 777 | * |
| 778 | * Commands run in command substitution ("`cmd`") | 778 | * Commands run in command substitution ("`cmd`") |
| 779 | * have SIGTTIN, SIGTTOU, SIGTSTP set to SIG_IGN. | 779 | * have SIGTTIN, SIGTTOU, SIGTSTP set to SIG_IGN. |
| 780 | * | 780 | * |
| 781 | * Ordinary commands have IGN/DFL set as inherited by the shell | 781 | * Ordinary commands have signals set to SIG_IGN/DFL set as inherited |
| 782 | * from its parent. | 782 | * by the shell from its parent. |
| 783 | * | 783 | * |
| 784 | * Default handlers which differ from DFL action | 784 | * Siganls which differ from SIG_DFL action |
| 785 | * (note: subshell is not an interactive shell): | 785 | * (note: child (i.e., [v]forked) shell is not an interactive shell): |
| 786 | * | 786 | * |
| 787 | * SIGQUIT: ignore | 787 | * SIGQUIT: ignore |
| 788 | * SIGTERM (interactive): ignore | 788 | * SIGTERM (interactive): ignore |
| 789 | * SUGHUP (interactive): send SIGCONT to stopped jobs, | 789 | * SIGHUP (interactive): |
| 790 | * send SIGHUP to all jobs and exit | 790 | * send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit |
| 791 | * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore | 791 | * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore |
| 792 | * (note that ^Z is handled not by trapping SIGTSTP, but by seeing | 792 | * (note that ^Z is handled not by trapping SIGTSTP, but by seeing |
| 793 | * that all pipe members are stopped) (right?) | 793 | * that all pipe members are stopped) (right?) |
| 794 | * SIGINT (interactive): wait for last pipe, ignore the rest | 794 | * SIGINT (interactive): wait for last pipe, ignore the rest |
| 795 | * of the command line, show prompt. (check/expand this) | 795 | * of the command line, show prompt. NB: ^C does not send SIGINT |
| 796 | * Example 1: this waits 5 sec, but does not execute ls: | 796 | * to interactive shell while shell is waiting for a pipe, |
| 797 | * "echo $$; sleep 5; ls -l" + "kill -INT <pid>" | 797 | * since shell is bg'ed (is not in foreground process group). |
| 798 | * Example 2: this does not wait and does not execute ls: | 798 | * (check/expand this) |
| 799 | * "echo $$; sleep 5 & wait; ls -l" + "kill -INT <pid>" | 799 | * Example 1: this waits 5 sec, but does not execute ls: |
| 800 | * "echo $$; sleep 5; ls -l" + "kill -INT <pid>" | ||
| 801 | * Example 2: this does not wait and does not execute ls: | ||
| 802 | * "echo $$; sleep 5 & wait; ls -l" + "kill -INT <pid>" | ||
| 803 | * Example 3: this does not wait 5 sec, but executes ls: | ||
| 804 | * "sleep 5; ls -l" + press ^C | ||
| 800 | * | 805 | * |
| 801 | * (What happens to signals which are IGN on shell start?) | 806 | * (What happens to signals which are IGN on shell start?) |
| 802 | * (What happens with signal mask on shell start?) | 807 | * (What happens with signal mask on shell start?) |
| @@ -813,14 +818,16 @@ static void free_strings(char **strings) | |||
| 813 | * unsigned non_DFL_mask: a mask of such "special" signals | 818 | * unsigned non_DFL_mask: a mask of such "special" signals |
| 814 | * sigset_t blocked_set: current blocked signal set | 819 | * sigset_t blocked_set: current blocked signal set |
| 815 | * | 820 | * |
| 816 | * "trap - SIGxxx": clear bit in blocked_set unless it is also in non_DFL | 821 | * "trap - SIGxxx": |
| 817 | * "trap 'cmd' SIGxxx": set bit in blocked_set (even if 'cmd' is '') | 822 | * clear bit in blocked_set unless it is also in non_DFL |
| 823 | * "trap 'cmd' SIGxxx": | ||
| 824 | * set bit in blocked_set (even if 'cmd' is '') | ||
| 818 | * after [v]fork, if we plan to be a shell: | 825 | * after [v]fork, if we plan to be a shell: |
| 819 | * nothing for {} subshell (say, "true | { true; true; } | true") | 826 | * nothing for {} child shell (say, "true | { true; true; } | true") |
| 820 | * unset all traps if () shell. [TODO] | 827 | * unset all traps if () shell. [TODO] |
| 821 | * after [v]fork, if we plan to exec: | 828 | * after [v]fork, if we plan to exec: |
| 822 | * POSIX says pending signal mask is cleared in child - no need to clear it. | 829 | * POSIX says pending signal mask is cleared in child - no need to clear it. |
| 823 | * restore blocked signal set to one inherited by shell just prior to exec. | 830 | * Restore blocked signal set to one inherited by shell just prior to exec. |
| 824 | * | 831 | * |
| 825 | * Note: as a result, we do not use signal handlers much. The only use | 832 | * Note: as a result, we do not use signal handlers much. The only use |
| 826 | * is to restore terminal pgrp on exit. | 833 | * is to restore terminal pgrp on exit. |
| @@ -848,7 +855,6 @@ static void init_signal_mask(void) | |||
| 848 | #endif | 855 | #endif |
| 849 | G.non_DFL_mask = mask; | 856 | G.non_DFL_mask = mask; |
| 850 | 857 | ||
| 851 | /*sigemptyset(&G.blocked_set); - already is */ | ||
| 852 | sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); | 858 | sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); |
| 853 | sig = 0; | 859 | sig = 0; |
| 854 | while (mask) { | 860 | while (mask) { |
| @@ -859,6 +865,7 @@ static void init_signal_mask(void) | |||
| 859 | } | 865 | } |
| 860 | sigprocmask(SIG_SETMASK, &G.blocked_set, &G.inherited_set); | 866 | sigprocmask(SIG_SETMASK, &G.blocked_set, &G.inherited_set); |
| 861 | } | 867 | } |
| 868 | |||
| 862 | static void check_and_run_traps(void) | 869 | static void check_and_run_traps(void) |
| 863 | { | 870 | { |
| 864 | static const struct timespec zero_ts = { 0, 0 }; | 871 | static const struct timespec zero_ts = { 0, 0 }; |
| @@ -910,7 +917,7 @@ static void sigexit(int sig) | |||
| 910 | 917 | ||
| 911 | #if ENABLE_HUSH_INTERACTIVE | 918 | #if ENABLE_HUSH_INTERACTIVE |
| 912 | /* Careful: we can end up here after [v]fork. Do not restore | 919 | /* Careful: we can end up here after [v]fork. Do not restore |
| 913 | * tty pgrp, only top-level shell process does that */ | 920 | * tty pgrp then, only top-level shell process does that */ |
| 914 | if (G.interactive_fd && getpid() == G.root_pid) | 921 | if (G.interactive_fd && getpid() == G.root_pid) |
| 915 | tcsetpgrp(G.interactive_fd, G.saved_tty_pgrp); | 922 | tcsetpgrp(G.interactive_fd, G.saved_tty_pgrp); |
| 916 | #endif | 923 | #endif |
| @@ -931,11 +938,11 @@ static void maybe_set_sighandler(int sig) | |||
| 931 | */ | 938 | */ |
| 932 | if (!((G.non_DFL_mask >> sig) & 1)) { | 939 | if (!((G.non_DFL_mask >> sig) & 1)) { |
| 933 | handler = signal(sig, sigexit); | 940 | handler = signal(sig, sigexit); |
| 934 | if (handler == SIG_IGN) /* restore back to IGN! */ | 941 | if (handler == SIG_IGN) /* oops... restore back to IGN! */ |
| 935 | signal(sig, handler); | 942 | signal(sig, handler); |
| 936 | } | 943 | } |
| 937 | } | 944 | } |
| 938 | /* Used only to set handler to restore pgrp on exit, and to reset it to DFL */ | 945 | /* Used only to set handler to restore pgrp on exit */ |
| 939 | static void set_fatal_signals_to_sigexit(void) | 946 | static void set_fatal_signals_to_sigexit(void) |
| 940 | { | 947 | { |
| 941 | if (HUSH_DEBUG) { | 948 | if (HUSH_DEBUG) { |
