diff options
author | Ron Yorston <rmy@pobox.com> | 2023-05-23 10:57:56 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2023-05-23 10:57:56 +0100 |
commit | 89aa9d783c535670c6aed1d32c8740b7474cca00 (patch) | |
tree | 52a494ad5f8a89fbdb5ad2a6155a62d7d3a6a024 | |
parent | c2c0cfbeb6f07fa3257a60760d5c8a5382cee6e9 (diff) | |
download | busybox-w32-89aa9d783c535670c6aed1d32c8740b7474cca00.tar.gz busybox-w32-89aa9d783c535670c6aed1d32c8740b7474cca00.tar.bz2 busybox-w32-89aa9d783c535670c6aed1d32c8740b7474cca00.zip |
win32: changes to signal handling
Use an exit code of the form (signal << 24) when a process exits
due to a signal. This replaces the previous use of (signal + 128).
This makes it easier to distinguish exit codes from signals.
Allow kill(2) to handle all defined signals, not just EXIT, TERM
and KILL.
The kill and timeout applets now accept any defined signals.
Convert certain Windows status codes Unix-style signal codes.
In ash:
- Exit as if with SIGINT in raise_interrupt() rather than call
raise(SIGINT). The latter returns an exit code of 3.
- Detect if a child process exits as if with SIGINT. If not and if
the parent is an interactive top-level shell, reset pending_int.
This prevents the parent from seeing an INT if the child hasn't
reported it exited due to INT. (Probably due to it being an
interactive shell.)
Costs 132-136 bytes.
-rw-r--r-- | coreutils/timeout.c | 4 | ||||
-rw-r--r-- | findutils/xargs.c | 2 | ||||
-rw-r--r-- | include/mingw.h | 3 | ||||
-rw-r--r-- | shell/ash.c | 31 | ||||
-rw-r--r-- | win32/process.c | 21 |
5 files changed, 43 insertions, 18 deletions
diff --git a/coreutils/timeout.c b/coreutils/timeout.c index 3565c005d..8f306529f 100644 --- a/coreutils/timeout.c +++ b/coreutils/timeout.c | |||
@@ -54,7 +54,7 @@ static HANDLE child = INVALID_HANDLE_VALUE; | |||
54 | static void kill_child(void) | 54 | static void kill_child(void) |
55 | { | 55 | { |
56 | if (child != INVALID_HANDLE_VALUE) { | 56 | if (child != INVALID_HANDLE_VALUE) { |
57 | kill_SIGTERM_by_handle(child); | 57 | kill_signal_by_handle(child, SIGTERM); |
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
@@ -130,7 +130,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
130 | #if !ENABLE_PLATFORM_MINGW32 | 130 | #if !ENABLE_PLATFORM_MINGW32 |
131 | if (signo < 0) | 131 | if (signo < 0) |
132 | #else | 132 | #else |
133 | if (signo != SIGTERM && signo != SIGKILL && signo != 0) | 133 | if (!is_valid_signal(signo)) |
134 | #endif | 134 | #endif |
135 | bb_error_msg_and_die("unknown signal '%s'", opt_s); | 135 | bb_error_msg_and_die("unknown signal '%s'", opt_s); |
136 | 136 | ||
diff --git a/findutils/xargs.c b/findutils/xargs.c index bc47a869f..1e7d8de02 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -216,7 +216,7 @@ static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | |||
216 | } | 216 | } |
217 | } | 217 | } |
218 | # endif | 218 | # endif |
219 | exit(128 + SIGINT); | 219 | exit(SIGINT << 24); |
220 | return TRUE; | 220 | return TRUE; |
221 | } | 221 | } |
222 | return FALSE; | 222 | return FALSE; |
diff --git a/include/mingw.h b/include/mingw.h index 6204ded6d..f94804d91 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -540,7 +540,8 @@ int mingw_execve(const char *cmd, char *const *argv, char *const *envp); | |||
540 | 540 | ||
541 | #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') | 541 | #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') |
542 | 542 | ||
543 | int kill_SIGTERM_by_handle(HANDLE process); | 543 | int kill_signal_by_handle(HANDLE process, int sig); |
544 | int FAST_FUNC is_valid_signal(int number); | ||
544 | 545 | ||
545 | #define find_mount_point(n, s) find_mount_point(n) | 546 | #define find_mount_point(n, s) find_mount_point(n) |
546 | 547 | ||
diff --git a/shell/ash.c b/shell/ash.c index 93c402a8b..87df555dd 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -884,9 +884,13 @@ raise_interrupt(void) | |||
884 | /* pending_sig = 0; - now done in signal_handler() */ | 884 | /* pending_sig = 0; - now done in signal_handler() */ |
885 | 885 | ||
886 | if (!(rootshell && iflag)) { | 886 | if (!(rootshell && iflag)) { |
887 | #if !ENABLE_PLATFORM_MINGW32 | ||
887 | /* Kill ourself with SIGINT */ | 888 | /* Kill ourself with SIGINT */ |
888 | signal(SIGINT, SIG_DFL); | 889 | signal(SIGINT, SIG_DFL); |
889 | raise(SIGINT); | 890 | raise(SIGINT); |
891 | #else | ||
892 | exit(SIGINT << 24); | ||
893 | #endif | ||
890 | } | 894 | } |
891 | #if ENABLE_PLATFORM_MINGW32 | 895 | #if ENABLE_PLATFORM_MINGW32 |
892 | if (iflag) | 896 | if (iflag) |
@@ -4122,8 +4126,10 @@ struct job { | |||
4122 | #define JOBDONE 2 /* all procs are completed */ | 4126 | #define JOBDONE 2 /* all procs are completed */ |
4123 | unsigned | 4127 | unsigned |
4124 | state: 8, | 4128 | state: 8, |
4125 | #if JOBS | 4129 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
4126 | sigint: 1, /* job was killed by SIGINT */ | 4130 | sigint: 1, /* job was killed by SIGINT */ |
4131 | #endif | ||
4132 | #if JOBS | ||
4127 | jobctl: 1, /* job running under job control */ | 4133 | jobctl: 1, /* job running under job control */ |
4128 | #endif | 4134 | #endif |
4129 | waited: 1, /* true if this entry has been waited for */ | 4135 | waited: 1, /* true if this entry has been waited for */ |
@@ -4840,7 +4846,7 @@ waitpid_child(int *status, int wait_flags) | |||
4840 | HANDLE *proclist; | 4846 | HANDLE *proclist; |
4841 | pid_t pid = -1; | 4847 | pid_t pid = -1; |
4842 | DWORD win_status, idx; | 4848 | DWORD win_status, idx; |
4843 | int i; | 4849 | int i, sig; |
4844 | 4850 | ||
4845 | for (jb = curjob; jb; jb = jb->prev_job) { | 4851 | for (jb = curjob; jb; jb = jb->prev_job) { |
4846 | if (jb->state != JOBDONE) | 4852 | if (jb->state != JOBDONE) |
@@ -4872,9 +4878,18 @@ waitpid_child(int *status, int wait_flags) | |||
4872 | wait_flags&WNOHANG ? 1 : INFINITE); | 4878 | wait_flags&WNOHANG ? 1 : INFINITE); |
4873 | if (idx < pid_nr) { | 4879 | if (idx < pid_nr) { |
4874 | GetExitCodeProcess(proclist[idx], &win_status); | 4880 | GetExitCodeProcess(proclist[idx], &win_status); |
4875 | *status = (int)win_status << 8; | 4881 | if (win_status == 0xc0000005) |
4876 | if (win_status == 128 + SIGTERM || win_status == 128 + SIGKILL) | 4882 | win_status = SIGSEGV << 24; |
4877 | *status += win_status - 128; | 4883 | else if (win_status == 0xc000013a) |
4884 | win_status = SIGINT << 24; | ||
4885 | |||
4886 | // When a process is terminated as if by a signal the exit | ||
4887 | // code is zero apart from the signal in its topmost byte. | ||
4888 | sig = win_status >> 24; | ||
4889 | if (sig != 0 && win_status == sig << 24 && is_valid_signal(sig)) | ||
4890 | *status = sig; | ||
4891 | else | ||
4892 | *status = (int)win_status << 8; | ||
4878 | pid = pidlist[idx]; | 4893 | pid = pidlist[idx]; |
4879 | } | 4894 | } |
4880 | done: | 4895 | done: |
@@ -5241,7 +5256,7 @@ getstatus(struct job *job) | |||
5241 | { | 5256 | { |
5242 | /* XXX: limits number of signals */ | 5257 | /* XXX: limits number of signals */ |
5243 | retval = WTERMSIG(status); | 5258 | retval = WTERMSIG(status); |
5244 | #if JOBS | 5259 | #if JOBS || ENABLE_PLATFORM_MINGW32 |
5245 | if (retval == SIGINT) | 5260 | if (retval == SIGINT) |
5246 | job->sigint = 1; | 5261 | job->sigint = 1; |
5247 | #endif | 5262 | #endif |
@@ -6051,6 +6066,10 @@ waitforjob(struct job *jp) | |||
6051 | return exitstatus; | 6066 | return exitstatus; |
6052 | 6067 | ||
6053 | st = getstatus(jp); | 6068 | st = getstatus(jp); |
6069 | #if ENABLE_PLATFORM_MINGW32 | ||
6070 | if (!jp->sigint && iflag && rootshell) | ||
6071 | pending_int = 0; | ||
6072 | #endif | ||
6054 | #if JOBS | 6073 | #if JOBS |
6055 | if (jp->jobctl) { | 6074 | if (jp->jobctl) { |
6056 | xtcsetpgrp(ttyfd, rootpid); | 6075 | xtcsetpgrp(ttyfd, rootpid); |
diff --git a/win32/process.c b/win32/process.c index 228b0b30e..ebc006d4e 100644 --- a/win32/process.c +++ b/win32/process.c | |||
@@ -705,14 +705,14 @@ static inline int process_architecture_matches_current(HANDLE process) | |||
705 | * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 | 705 | * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 |
706 | * | 706 | * |
707 | */ | 707 | */ |
708 | int kill_SIGTERM_by_handle(HANDLE process) | 708 | int kill_signal_by_handle(HANDLE process, int sig) |
709 | { | 709 | { |
710 | DWORD code; | 710 | DWORD code; |
711 | int ret = 0; | 711 | int ret = 0; |
712 | 712 | ||
713 | if (GetExitCodeProcess(process, &code) && code == STILL_ACTIVE) { | 713 | if (GetExitCodeProcess(process, &code) && code == STILL_ACTIVE) { |
714 | DECLARE_PROC_ADDR(DWORD, ExitProcess, LPVOID); | 714 | DECLARE_PROC_ADDR(DWORD, ExitProcess, LPVOID); |
715 | PVOID arg = (PVOID)(intptr_t)(128 + SIGTERM); | 715 | PVOID arg = (PVOID)(intptr_t)(sig << 24); |
716 | DWORD thread_id; | 716 | DWORD thread_id; |
717 | HANDLE thread; | 717 | HANDLE thread; |
718 | 718 | ||
@@ -734,7 +734,7 @@ int kill_SIGTERM_by_handle(HANDLE process) | |||
734 | return ret; | 734 | return ret; |
735 | } | 735 | } |
736 | 736 | ||
737 | static int kill_SIGTERM(pid_t pid, int sig UNUSED_PARAM) | 737 | static int kill_signal(pid_t pid, int sig) |
738 | { | 738 | { |
739 | HANDLE process; | 739 | HANDLE process; |
740 | 740 | ||
@@ -745,7 +745,7 @@ static int kill_SIGTERM(pid_t pid, int sig UNUSED_PARAM) | |||
745 | return -1; | 745 | return -1; |
746 | } | 746 | } |
747 | 747 | ||
748 | return kill_SIGTERM_by_handle(process); | 748 | return kill_signal_by_handle(process, sig); |
749 | } | 749 | } |
750 | 750 | ||
751 | /* | 751 | /* |
@@ -765,18 +765,23 @@ static int kill_SIGKILL(pid_t pid, int sig) | |||
765 | } | 765 | } |
766 | 766 | ||
767 | if (sig == SIGKILL) | 767 | if (sig == SIGKILL) |
768 | ret = !TerminateProcess(process, 128 + SIGKILL); | 768 | ret = !TerminateProcess(process, SIGKILL << 24); |
769 | CloseHandle(process); | 769 | CloseHandle(process); |
770 | 770 | ||
771 | return ret; | 771 | return ret; |
772 | } | 772 | } |
773 | 773 | ||
774 | int FAST_FUNC is_valid_signal(int number) | ||
775 | { | ||
776 | return isalpha(*get_signame(number)); | ||
777 | } | ||
778 | |||
774 | int kill(pid_t pid, int sig) | 779 | int kill(pid_t pid, int sig) |
775 | { | 780 | { |
776 | if (sig == SIGTERM) | 781 | if (sig == SIGKILL || sig == 0) |
777 | return kill_pids(pid, sig, kill_SIGTERM); | ||
778 | else if (sig == SIGKILL || sig == 0) | ||
779 | return kill_pids(pid, sig, kill_SIGKILL); | 782 | return kill_pids(pid, sig, kill_SIGKILL); |
783 | else if (is_valid_signal(sig)) | ||
784 | return kill_pids(pid, sig, kill_signal); | ||
780 | 785 | ||
781 | errno = EINVAL; | 786 | errno = EINVAL; |
782 | return -1; | 787 | return -1; |