comparison src/process-nt.c @ 280:7df0dd720c89 r21-0b38

Import from CVS: tag r21-0b38
author cvs
date Mon, 13 Aug 2007 10:32:22 +0200
parents 90d73dddcdc4
children c42ec1d1cded
comparison
equal deleted inserted replaced
279:c20b2fb5bb0a 280:7df0dd720c89
32 #include "procimpl.h" 32 #include "procimpl.h"
33 #include "sysdep.h" 33 #include "sysdep.h"
34 34
35 #include <windows.h> 35 #include <windows.h>
36 #include <shellapi.h> 36 #include <shellapi.h>
37 #include <signal.h>
37 38
38 /* Implemenation-specific data. Pointed to by Lisp_Process->process_data */ 39 /* Implemenation-specific data. Pointed to by Lisp_Process->process_data */
39 struct nt_process_data 40 struct nt_process_data
40 { 41 {
41 HANDLE h_process; 42 HANDLE h_process;
52 HANDLE 53 HANDLE
53 get_nt_process_handle (struct Lisp_Process *p) 54 get_nt_process_handle (struct Lisp_Process *p)
54 { 55 {
55 return (NT_DATA (p)->h_process); 56 return (NT_DATA (p)->h_process);
56 } 57 }
57 58
59 /*-----------------------------------------------------------------------*/
60 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */
61 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/
62 /*-----------------------------------------------------------------------*/
63
64 typedef struct
65 {
66 HANDLE h_process;
67 HANDLE h_thread;
68 LPVOID address;
69 } process_memory;
70
71 /*
72 * Allocate SIZE bytes in H_PROCESS address space. Fill in PMC used
73 * further by other routines. Return nonzero if successful.
74 *
75 * The memory in other process is allocated by creating a suspended
76 * thread. Initial stack of that thread is used as the memory
77 * block. The thread entry point is the routine ExitThread in
78 * kernel32.dll, so the allocated memory is freed just by resuming the
79 * thread, which immediately terminates after that.
80 */
81
82 static int
83 alloc_process_memory (HANDLE h_process, size_t size,
84 process_memory* pmc)
85 {
86 LPTHREAD_START_ROUTINE adr_ExitThread =
87 (LPTHREAD_START_ROUTINE)
88 GetProcAddress (GetModuleHandle ("kernel32"), "ExitThread");
89 DWORD dw_unused;
90 CONTEXT context;
91 MEMORY_BASIC_INFORMATION mbi;
92
93 pmc->h_process = h_process;
94 pmc->h_thread = CreateRemoteThread (h_process, NULL, size,
95 adr_ExitThread, NULL,
96 CREATE_SUSPENDED, &dw_unused);
97 if (pmc->h_thread == NULL)
98 return 0;
99
100 /* Get context, for thread's stack pointer */
101 context.ContextFlags = CONTEXT_CONTROL;
102 if (!GetThreadContext (pmc->h_thread, &context))
103 goto failure;
104
105 /* Determine base address of the committed range */
106 if (sizeof(mbi) != VirtualQueryEx (h_process,
107 #if defined (_X86_)
108 (LPDWORD)context.Esp - 1,
109 #elif defined (_ALPHA_)
110 (LPDWORD)context.IntSp - 1,
111 #else
112 #error Unknown processor architecture
113 #endif
114 &mbi, sizeof(mbi)))
115 goto failure;
116
117 /* Change the page protection of the allocated memory to executable,
118 read, and write. */
119 if (!VirtualProtectEx (h_process, mbi.BaseAddress, size,
120 PAGE_EXECUTE_READWRITE, &dw_unused))
121 goto failure;
122
123 pmc->address = mbi.BaseAddress;
124 return 1;
125
126 failure:
127 ResumeThread (pmc->h_thread);
128 pmc->address = 0;
129 return 0;
130 }
131
132 static void
133 free_process_memory (process_memory* pmc)
134 {
135 ResumeThread (pmc->h_thread);
136 }
137
138 /*
139 * Run ROUTINE in the context of process determined by H_PROCESS. The
140 * routine is passed the address of DATA as parameter. CODE_END is the
141 * address immediately after ROUTINE's code. DATA_SIZE is the size of
142 * DATA structure.
143 *
144 * Note that the code must be positionally independent, and compiled
145 * without stack checks (they cause implicit calls into CRT so will
146 * fail). DATA should not refer any data in calling process, as both
147 * routine and its data are copied into remote process. Size of data
148 * and code together should not exceed one page (4K on x86 systems).
149 *
150 * Return the value returned by ROUTINE, or (DWORD)-1 if call failed.
151 */
152 static DWORD
153 run_in_other_process (HANDLE h_process,
154 LPTHREAD_START_ROUTINE routine, LPVOID code_end,
155 LPVOID data, size_t data_size)
156 {
157 process_memory pm;
158 size_t code_size = (LPBYTE)code_end - (LPBYTE)routine;
159 /* Need at most 3 extra bytes of memory, for data alignment */
160 size_t total_size = code_size + data_size + 3;
161 LPVOID remote_data;
162 HANDLE h_thread;
163 DWORD dw_unused;
164
165 /* Allocate memory */
166 if (!alloc_process_memory (h_process, total_size, &pm))
167 return (DWORD)-1;
168
169 /* Copy code */
170 if (!WriteProcessMemory (h_process, pm.address, (LPVOID)routine,
171 code_size, NULL))
172 goto failure;
173
174 /* Copy data */
175 if (data_size)
176 {
177 remote_data = (LPBYTE)pm.address + ((code_size + 4) & ~3);
178 if (!WriteProcessMemory (h_process, remote_data, data, data_size, NULL))
179 goto failure;
180 }
181 else
182 remote_data = NULL;
183
184 /* Execute the remote copy of code, passing it remote data */
185 h_thread = CreateRemoteThread (h_process, NULL, 0,
186 (LPTHREAD_START_ROUTINE) pm.address,
187 remote_data, 0, &dw_unused);
188 if (h_thread == NULL)
189 goto failure;
190
191 /* Wait till thread finishes */
192 WaitForSingleObject (h_thread, INFINITE);
193
194 /* Free remote memory */
195 free_process_memory (&pm);
196
197 /* Return thread's exit code */
198 {
199 DWORD exit_code;
200 GetExitCodeThread (h_thread, &exit_code);
201 CloseHandle (h_thread);
202 return exit_code;
203 }
204
205 failure:
206 free_process_memory (&pm);
207 return (DWORD)-1;
208 }
209
210 /*-----------------------------------------------------------------------*/
211 /* Sending signals */
212 /*-----------------------------------------------------------------------*/
213
214 /*
215 * We handle the following signals:
216 *
217 * SIGKILL, SIGTERM, SIGQUIT - These three translate to ExitProcess
218 * executed by the remote process
219 * SIGINT - The remote process is sent CTRL_BREAK_EVENT
220 */
221
222 /*
223 * Sending SIGKILL
224 */
225 typedef struct
226 {
227 void (WINAPI *adr_ExitProcess) (UINT);
228 } sigkill_data;
229
230 static DWORD WINAPI
231 sigkill_proc (sigkill_data* data)
232 {
233 (*data->adr_ExitProcess)(255);
234 return 1;
235 }
236
237 /* Watermark in code space */
238 static void
239 sigkill_code_end (void)
240 {
241 }
242
243 /*
244 * Sending break or control c
245 */
246 typedef struct
247 {
248 BOOL (WINAPI *adr_GenerateConsoleCtrlEvent) (DWORD, DWORD);
249 DWORD event;
250 } sigint_data;
251
252 static DWORD WINAPI
253 sigint_proc (sigint_data* data)
254 {
255 return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0);
256 }
257
258 /* Watermark in code space */
259 static void
260 sigint_code_end (void)
261 {
262 }
263
264 /*
265 * Enabling signals
266 */
267 typedef struct
268 {
269 BOOL (WINAPI *adr_SetConsoleCtrlHandler) (LPVOID, BOOL);
270 } sig_enable_data;
271
272 static DWORD WINAPI
273 sig_enable_proc (sig_enable_data* data)
274 {
275 (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE);
276 return 1;
277 }
278
279 /* Watermark in code space */
280 static void
281 sig_enable_code_end (void)
282 {
283 }
284
285 /*
286 * Send signal SIGNO to process H_PROCESS.
287 * Return nonzero if successful.
288 */
289
290 /* This code assigns a return value of GetProcAddress to function pointers
291 of many different types. Instead of heavy obscure casts, we just disable
292 warnings about assignments to different function pointer types. */
293 #pragma warning (disable : 4113)
294
295 static int
296 send_signal (HANDLE h_process, int signo)
297 {
298 HMODULE h_kernel = GetModuleHandle ("kernel32");
299 DWORD retval;
300
301 assert (h_kernel != NULL);
302
303 switch (signo)
304 {
305 case SIGKILL:
306 case SIGTERM:
307 case SIGQUIT:
308 {
309 sigkill_data d;
310 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess");
311 assert (d.adr_ExitProcess);
312 retval = run_in_other_process (h_process,
313 sigkill_proc, sigkill_code_end,
314 &d, sizeof (d));
315 break;
316 }
317 case SIGINT:
318 {
319 sigint_data d;
320 d.adr_GenerateConsoleCtrlEvent =
321 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent");
322 assert (d.adr_GenerateConsoleCtrlEvent);
323 d.event = CTRL_C_EVENT;
324 retval = run_in_other_process (h_process,
325 sigint_proc, sigint_code_end,
326 &d, sizeof (d));
327 break;
328 }
329 default:
330 assert (0);
331 }
332
333 return (int)retval > 0 ? 1 : 0;
334 }
335
336 /*
337 * Enable CTRL_C_EVENT handling in a new child process
338 */
339 static void
340 enable_child_signals (HANDLE h_process)
341 {
342 HMODULE h_kernel = GetModuleHandle ("kernel32");
343 sig_enable_data d;
344
345 assert (h_kernel != NULL);
346 d.adr_SetConsoleCtrlHandler =
347 GetProcAddress (h_kernel, "SetConsoleCtrlHandler");
348 assert (d.adr_SetConsoleCtrlHandler);
349 run_in_other_process (h_process,
350 sig_enable_proc, sig_enable_code_end,
351 &d, sizeof (d));
352 }
353
354 #pragma warning (default : 4113)
355
356 /*
357 * Signal error if SIGNO is not supported
358 */
359 static void
360 validate_signal_number (int signo)
361 {
362 if (signo != SIGKILL && signo != SIGTERM
363 && signo != SIGQUIT && signo != SIGINT)
364 error ("Signal number %d not supported", signo);
365 }
366
58 /*-----------------------------------------------------------------------*/ 367 /*-----------------------------------------------------------------------*/
59 /* Process methods */ 368 /* Process methods */
60 /*-----------------------------------------------------------------------*/ 369 /*-----------------------------------------------------------------------*/
61 370
62 /* 371 /*
224 si.hStdError = hprocout; 533 si.hStdError = hprocout;
225 si.dwFlags |= STARTF_USESTDHANDLES; 534 si.dwFlags |= STARTF_USESTDHANDLES;
226 } 535 }
227 536
228 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, 537 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE,
229 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 538 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP
539 | CREATE_SUSPENDED,
230 NULL, current_dir, &si, &pi) 540 NULL, current_dir, &si, &pi)
231 ? 0 : GetLastError ()); 541 ? 0 : GetLastError ());
232 542
233 if (do_io) 543 if (do_io)
234 { 544 {
259 /* Indicate as if the process has exited immediately. */ 569 /* Indicate as if the process has exited immediately. */
260 p->status_symbol = Qexit; 570 p->status_symbol = Qexit;
261 CloseHandle (pi.hProcess); 571 CloseHandle (pi.hProcess);
262 } 572 }
263 573
574 if (!windowed)
575 enable_child_signals (pi.hProcess);
576
577 ResumeThread (pi.hThread);
264 CloseHandle (pi.hThread); 578 CloseHandle (pi.hThread);
265 579
266 /* Hack to support Windows 95 negative pids */ 580 /* Hack to support Windows 95 negative pids */
267 return ((int)pi.dwProcessId < 0 581 return ((int)pi.dwProcessId < 0
268 ? -(int)pi.dwProcessId : (int)pi.dwProcessId); 582 ? -(int)pi.dwProcessId : (int)pi.dwProcessId);
355 } 669 }
356 } 670 }
357 Lstream_flush (XLSTREAM (DATA_OUTSTREAM(p))); 671 Lstream_flush (XLSTREAM (DATA_OUTSTREAM(p)));
358 } 672 }
359 673
674 /*
675 * Send a signal number SIGNO to PROCESS.
676 * CURRENT_GROUP means send to the process group that currently owns
677 * the terminal being used to communicate with PROCESS.
678 * This is used for various commands in shell mode.
679 * If NOMSG is zero, insert signal-announcements into process's buffers
680 * right away.
681 *
682 * If we can, we try to signal PROCESS by sending control characters
683 * down the pty. This allows us to signal inferiors who have changed
684 * their uid, for which killpg would return an EPERM error.
685 *
686 * The method signals an error if the given SIGNO is not valid
687 */
688
689 static void
690 nt_kill_child_process (Lisp_Object proc, int signo,
691 int current_group, int nomsg)
692 {
693 struct Lisp_Process *p = XPROCESS (proc);
694
695 /* Signal error if SIGNO cannot be sent */
696 validate_signal_number (signo);
697
698 /* Send signal */
699 if (!send_signal (NT_DATA(p)->h_process, signo))
700 error ("Cannot send signal to process");
701 }
702
703 /*
704 * Kill any process in the system given its PID.
705 *
706 * Returns zero if a signal successfully sent, or
707 * negative number upon failure
708 */
709 static int
710 nt_kill_process_by_pid (int pid, int signo)
711 {
712 HANDLE h_process;
713 int send_result;
714
715 /* Signal error if SIGNO cannot be sent */
716 validate_signal_number (signo);
717
718 /* Try to open the process with required privileges */
719 h_process = OpenProcess (PROCESS_CREATE_THREAD
720 | PROCESS_QUERY_INFORMATION
721 | PROCESS_VM_OPERATION
722 | PROCESS_VM_WRITE,
723 FALSE, pid);
724 if (h_process == NULL)
725 return -1;
726
727 send_result = send_signal (h_process, signo);
728
729 CloseHandle (h_process);
730
731 return send_result ? 0 : -1;
732 }
733
734
360 /*-----------------------------------------------------------------------*/ 735 /*-----------------------------------------------------------------------*/
361 /* Initialization */ 736 /* Initialization */
362 /*-----------------------------------------------------------------------*/ 737 /*-----------------------------------------------------------------------*/
363 738
364 void 739 void
370 /* PROCESS_HAS_METHOD (nt, init_process); */ 745 /* PROCESS_HAS_METHOD (nt, init_process); */
371 /* PROCESS_HAS_METHOD (nt, init_process_io_handles); */ 746 /* PROCESS_HAS_METHOD (nt, init_process_io_handles); */
372 PROCESS_HAS_METHOD (nt, create_process); 747 PROCESS_HAS_METHOD (nt, create_process);
373 PROCESS_HAS_METHOD (nt, update_status_if_terminated); 748 PROCESS_HAS_METHOD (nt, update_status_if_terminated);
374 PROCESS_HAS_METHOD (nt, send_process); 749 PROCESS_HAS_METHOD (nt, send_process);
375 /* PROCESS_HAS_METHOD (nt, kill_child_process); */ 750 PROCESS_HAS_METHOD (nt, kill_child_process);
376 /* PROCESS_HAS_METHOD (nt, kill_process_by_pid); */ 751 PROCESS_HAS_METHOD (nt, kill_process_by_pid);
377 #if 0 /* Yet todo */ 752 #if 0 /* Yet todo */
378 #ifdef HAVE_SOCKETS 753 #ifdef HAVE_SOCKETS
379 PROCESS_HAS_METHOD (nt, canonicalize_host_name); 754 PROCESS_HAS_METHOD (nt, canonicalize_host_name);
380 PROCESS_HAS_METHOD (nt, open_network_stream); 755 PROCESS_HAS_METHOD (nt, open_network_stream);
381 #ifdef HAVE_MULTICAST 756 #ifdef HAVE_MULTICAST