aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coreutils/timeout.c18
-rw-r--r--include/mingw.h1
-rw-r--r--win32/process.c196
3 files changed, 101 insertions, 114 deletions
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index ff58a753a..802ddfc07 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -54,7 +54,9 @@ static HANDLE child = INVALID_HANDLE_VALUE;
54static void kill_child(void) 54static void kill_child(void)
55{ 55{
56 if (child != INVALID_HANDLE_VALUE) { 56 if (child != INVALID_HANDLE_VALUE) {
57 kill_signal_by_handle(child, SIGTERM); 57 pid_t pid = (pid_t)GetProcessId(child);
58 if (pid)
59 kill(pid, SIGTERM);
58 } 60 }
59} 61}
60 62
@@ -206,13 +208,15 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
206 status = signo == SIGKILL ? 137 : 124; 208 status = signo == SIGKILL ? 137 : 124;
207 209
208 pid = (pid_t)GetProcessId(child); 210 pid = (pid_t)GetProcessId(child);
209 kill(pid, signo); 211 if (pid) {
212 kill(pid, signo);
210 213
211 if (kill_timeout > 0) { 214 if (kill_timeout > 0) {
212 if (timeout_wait(kill_timeout, child, &status)) 215 if (timeout_wait(kill_timeout, child, &status))
213 goto finish; 216 goto finish;
214 kill(pid, SIGKILL); 217 kill(pid, SIGKILL);
215 status = 137; 218 status = 137;
219 }
216 } 220 }
217 finish: 221 finish:
218 CloseHandle(child); 222 CloseHandle(child);
diff --git a/include/mingw.h b/include/mingw.h
index 41d4cd940..56a7285e5 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -569,7 +569,6 @@ int mingw_execve(const char *cmd, char *const *argv, char *const *envp);
569#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') 569#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
570 570
571BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType); 571BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType);
572int kill_signal_by_handle(HANDLE process, int sig);
573int FAST_FUNC is_valid_signal(int number); 572int FAST_FUNC is_valid_signal(int number);
574int exit_code_to_wait_status(DWORD win_exit_code); 573int exit_code_to_wait_status(DWORD win_exit_code);
575int exit_code_to_posix(DWORD win_exit_code); 574int exit_code_to_posix(DWORD win_exit_code);
diff --git a/win32/process.c b/win32/process.c
index 5be07e54a..b993bb2be 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -685,14 +685,98 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
685} 685}
686 686
687/** 687/**
688 * Determine whether a process runs in the same architecture as the current
689 * one. That test is required before we assume that GetProcAddress() returns
690 * a valid address *for the target process*.
691 */
692static inline int process_architecture_matches_current(HANDLE process)
693{
694 static BOOL current_is_wow = -1;
695 BOOL is_wow;
696
697 if (current_is_wow == -1 &&
698 !IsWow64Process (GetCurrentProcess(), &current_is_wow))
699 current_is_wow = -2;
700 if (current_is_wow == -2)
701 return 0; /* could not determine current process' WoW-ness */
702 if (!IsWow64Process (process, &is_wow))
703 return 0; /* cannot determine */
704 return is_wow == current_is_wow;
705}
706
707/**
708 * This function tries to terminate a Win32 process, as gently as possible,
709 * by injecting a thread that calls ExitProcess().
710 *
711 * Note: as kernel32.dll is loaded before any process, the other process and
712 * this process will have ExitProcess() at the same address.
713 *
714 * The idea comes from the Dr Dobb's article "A Safer Alternative to
715 * TerminateProcess()" by Andrew Tucker (July 1, 1999),
716 * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547
717 *
718 */
719static int kill_signal_by_handle(HANDLE process, int sig)
720{
721 DECLARE_PROC_ADDR(DWORD, ExitProcess, LPVOID);
722 PVOID arg = (PVOID)(intptr_t)(sig << 24);
723 DWORD thread_id;
724 HANDLE thread;
725
726 if (!INIT_PROC_ADDR(kernel32, ExitProcess) ||
727 !process_architecture_matches_current(process)) {
728 SetLastError(ERROR_ACCESS_DENIED);
729 return -1;
730 }
731
732 if (sig != 0 && (thread = CreateRemoteThread(process, NULL, 0,
733 ExitProcess, arg, 0, &thread_id))) {
734 CloseHandle(thread);
735 }
736 return 0;
737}
738
739static int kill_signal(pid_t pid, int sig)
740{
741 HANDLE process;
742 int ret = 0;
743 DWORD code;
744
745 if (sig == SIGKILL)
746 process = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
747 else
748 process = OpenProcess(SYNCHRONIZE | PROCESS_CREATE_THREAD |
749 PROCESS_QUERY_INFORMATION |
750 PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
751 PROCESS_VM_READ, FALSE, pid);
752
753 if (!process)
754 return -1;
755
756 if (!GetExitCodeProcess(process, &code) || code != STILL_ACTIVE) {
757 SetLastError(ERROR_INVALID_PARAMETER);
758 ret = -1;
759 } else if (sig == SIGKILL) {
760 /* This way of terminating processes is not gentle: they get no
761 * chance to clean up after themselves (closing file handles,
762 * removing .lock files, terminating spawned processes (if any),
763 * etc). */
764 ret = !TerminateProcess(process, SIGKILL << 24);
765 } else {
766 ret = kill_signal_by_handle(process, sig);
767 }
768 CloseHandle(process);
769
770 return ret;
771}
772
773/**
688 * If the process ID is positive invoke the callback for that process 774 * If the process ID is positive invoke the callback for that process
689 * only. If negative or zero invoke the callback for all descendants 775 * only. If negative or zero invoke the callback for all descendants
690 * of the indicated process. Zero indicates the current process; negative 776 * of the indicated process. Zero indicates the current process; negative
691 * indicates the process with process ID -pid. 777 * indicates the process with process ID -pid.
692 */ 778 */
693typedef int (*kill_callback)(pid_t pid, int sig); 779static int kill_pids(pid_t pid, int sig)
694
695static int kill_pids(pid_t pid, int sig, kill_callback killer)
696{ 780{
697 DWORD pids[16384]; 781 DWORD pids[16384];
698 int max_len = sizeof(pids) / sizeof(*pids), i, len, ret = 0; 782 int max_len = sizeof(pids) / sizeof(*pids), i, len, ret = 0;
@@ -750,7 +834,7 @@ static int kill_pids(pid_t pid, int sig, kill_callback killer)
750 834
751 for (i = len - 1; i >= 0; i--) { 835 for (i = len - 1; i >= 0; i--) {
752 SetLastError(0); 836 SetLastError(0);
753 if (killer(pids[i], sig)) { 837 if (kill_signal(pids[i], sig)) {
754 errno = err_win_to_posix(); 838 errno = err_win_to_posix();
755 ret = -1; 839 ret = -1;
756 } 840 }
@@ -759,104 +843,6 @@ static int kill_pids(pid_t pid, int sig, kill_callback killer)
759 return ret; 843 return ret;
760} 844}
761 845
762/**
763 * Determine whether a process runs in the same architecture as the current
764 * one. That test is required before we assume that GetProcAddress() returns
765 * a valid address *for the target process*.
766 */
767static inline int process_architecture_matches_current(HANDLE process)
768{
769 static BOOL current_is_wow = -1;
770 BOOL is_wow;
771
772 if (current_is_wow == -1 &&
773 !IsWow64Process (GetCurrentProcess(), &current_is_wow))
774 current_is_wow = -2;
775 if (current_is_wow == -2)
776 return 0; /* could not determine current process' WoW-ness */
777 if (!IsWow64Process (process, &is_wow))
778 return 0; /* cannot determine */
779 return is_wow == current_is_wow;
780}
781
782/**
783 * This function tries to terminate a Win32 process, as gently as possible,
784 * by injecting a thread that calls ExitProcess().
785 *
786 * Note: as kernel32.dll is loaded before any process, the other process and
787 * this process will have ExitProcess() at the same address.
788 *
789 * The idea comes from the Dr Dobb's article "A Safer Alternative to
790 * TerminateProcess()" by Andrew Tucker (July 1, 1999),
791 * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547
792 *
793 */
794int kill_signal_by_handle(HANDLE process, int sig)
795{
796 DWORD code;
797 int ret = 0;
798
799 if (GetExitCodeProcess(process, &code) && code == STILL_ACTIVE) {
800 DECLARE_PROC_ADDR(DWORD, ExitProcess, LPVOID);
801 PVOID arg = (PVOID)(intptr_t)(sig << 24);
802 DWORD thread_id;
803 HANDLE thread;
804
805 if (!INIT_PROC_ADDR(kernel32, ExitProcess) ||
806 !process_architecture_matches_current(process)) {
807 SetLastError(ERROR_ACCESS_DENIED);
808 ret = -1;
809 goto finish;
810 }
811
812 if ((thread = CreateRemoteThread(process, NULL, 0,
813 ExitProcess, arg, 0, &thread_id))) {
814 CloseHandle(thread);
815 }
816 }
817
818 finish:
819 CloseHandle(process);
820 return ret;
821}
822
823static int kill_signal(pid_t pid, int sig)
824{
825 HANDLE process;
826
827 if (!(process = OpenProcess(SYNCHRONIZE | PROCESS_CREATE_THREAD |
828 PROCESS_QUERY_INFORMATION |
829 PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
830 PROCESS_VM_READ, FALSE, pid))) {
831 return -1;
832 }
833
834 return kill_signal_by_handle(process, sig);
835}
836
837/*
838 * This way of terminating processes is not gentle: they get no chance to
839 * clean up after themselves (closing file handles, removing .lock files,
840 * terminating spawned processes (if any), etc).
841 *
842 * If the signal isn't SIGKILL just check if the target process exists.
843 */
844static int kill_SIGKILL(pid_t pid, int sig)
845{
846 HANDLE process;
847 int ret = 0;
848
849 if (!(process=OpenProcess(PROCESS_TERMINATE, FALSE, pid))) {
850 return -1;
851 }
852
853 if (sig == SIGKILL)
854 ret = !TerminateProcess(process, SIGKILL << 24);
855 CloseHandle(process);
856
857 return ret;
858}
859
860int FAST_FUNC is_valid_signal(int number) 846int FAST_FUNC is_valid_signal(int number)
861{ 847{
862 return isalpha(*get_signame(number)); 848 return isalpha(*get_signame(number));
@@ -897,10 +883,8 @@ int exit_code_to_posix(DWORD exit_code)
897 883
898int kill(pid_t pid, int sig) 884int kill(pid_t pid, int sig)
899{ 885{
900 if (sig == SIGKILL || sig == 0) 886 if (is_valid_signal(sig))
901 return kill_pids(pid, sig, kill_SIGKILL); 887 return kill_pids(pid, sig);
902 else if (is_valid_signal(sig))
903 return kill_pids(pid, sig, kill_signal);
904 888
905 errno = EINVAL; 889 errno = EINVAL;
906 return -1; 890 return -1;