Mercurial > hg > xemacs-beta
comparison src/process-nt.c @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | de805c49cfc1 |
children | 11054d720c21 |
comparison
equal
deleted
inserted
replaced
411:12e008d41344 | 412:697ef44129c6 |
---|---|
1 /* Asynchronous subprocess implementation for Win32 | 1 /* Asynchronous subprocess implementation for Win32 |
2 Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995 | 2 Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995 |
3 Free Software Foundation, Inc. | 3 Free Software Foundation, Inc. |
4 Copyright (C) 1995 Sun Microsystems, Inc. | 4 Copyright (C) 1995 Sun Microsystems, Inc. |
5 Copyright (C) 1995, 1996, 2000 Ben Wing. | 5 Copyright (C) 1995, 1996 Ben Wing. |
6 | 6 |
7 This file is part of XEmacs. | 7 This file is part of XEmacs. |
8 | 8 |
9 XEmacs is free software; you can redistribute it and/or modify it | 9 XEmacs is free software; you can redistribute it and/or modify it |
10 under the terms of the GNU General Public License as published by the | 10 under the terms of the GNU General Public License as published by the |
24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */ | 24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */ |
25 | 25 |
26 #include <config.h> | 26 #include <config.h> |
27 #include "lisp.h" | 27 #include "lisp.h" |
28 | 28 |
29 #include "buffer.h" | |
30 #include "console-msw.h" | |
31 #include "hash.h" | 29 #include "hash.h" |
32 #include "lstream.h" | 30 #include "lstream.h" |
33 #include "nt.h" | |
34 #include "process.h" | 31 #include "process.h" |
35 #include "procimpl.h" | 32 #include "procimpl.h" |
36 #include "sysdep.h" | 33 #include "sysdep.h" |
37 | 34 |
35 #include <windows.h> | |
36 #ifndef __MINGW32__ | |
38 #include <shellapi.h> | 37 #include <shellapi.h> |
38 #else | |
39 #include <errno.h> | 39 #include <errno.h> |
40 #endif | |
40 #include <signal.h> | 41 #include <signal.h> |
41 #ifdef HAVE_SOCKETS | 42 #ifdef HAVE_SOCKETS |
42 #include <winsock.h> | 43 #include <winsock.h> |
43 #endif | 44 #endif |
44 | 45 |
45 /* Arbitrary size limit for code fragments passed to run_in_other_process */ | 46 /* Arbitrary size limit for code fragments passed to run_in_other_process */ |
46 #define FRAGMENT_CODE_SIZE 32 | 47 #define FRAGMENT_CODE_SIZE 32 |
47 | 48 |
49 /* Bound by winnt.el */ | |
50 Lisp_Object Qnt_quote_process_args; | |
51 | |
48 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */ | 52 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */ |
49 struct nt_process_data | 53 struct nt_process_data |
50 { | 54 { |
51 HANDLE h_process; | 55 HANDLE h_process; |
52 DWORD dwProcessId; | |
53 HWND hwnd; /* console window */ | |
54 }; | 56 }; |
55 | |
56 /* Control how args are quoted to ensure correct parsing by child | |
57 process. */ | |
58 Lisp_Object Vmswindows_quote_process_args; | |
59 | |
60 /* Control whether create_child causes the process to inherit Emacs' | |
61 console window, or be given a new one of its own. The default is | |
62 nil, to allow multiple DOS programs to run on Win95. Having separate | |
63 consoles also allows Emacs to cleanly terminate process groups. */ | |
64 Lisp_Object Vmswindows_start_process_share_console; | |
65 | |
66 /* Control whether create_child cause the process to inherit Emacs' | |
67 error mode setting. The default is t, to minimize the possibility of | |
68 subprocesses blocking when accessing unmounted drives. */ | |
69 Lisp_Object Vmswindows_start_process_inherit_error_mode; | |
70 | 57 |
71 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) | 58 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) |
72 | 59 |
73 /*-----------------------------------------------------------------------*/ | 60 /*-----------------------------------------------------------------------*/ |
74 /* Process helpers */ | 61 /* Process helpers */ |
75 /*-----------------------------------------------------------------------*/ | 62 /*-----------------------------------------------------------------------*/ |
76 | 63 |
77 /* This one breaks process abstraction. Prototype is in console-msw.h, | 64 /* This one breaks process abstraction. Prototype is in console-msw.h, |
78 used by select_process method in event-msw.c */ | 65 used by select_process method in event-msw.c */ |
79 HANDLE | 66 HANDLE |
80 get_nt_process_handle (Lisp_Process *p) | 67 get_nt_process_handle (struct Lisp_Process *p) |
81 { | 68 { |
82 return (NT_DATA (p)->h_process); | 69 return (NT_DATA (p)->h_process); |
83 } | 70 } |
84 | |
85 static struct Lisp_Process * | |
86 find_process_from_pid (DWORD pid) | |
87 { | |
88 Lisp_Object tail, proc; | |
89 | |
90 for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail)) | |
91 { | |
92 proc = XCAR (tail); | |
93 if (NT_DATA (XPROCESS (proc))->dwProcessId == pid) | |
94 return XPROCESS (proc); | |
95 } | |
96 return 0; | |
97 } | |
98 | |
99 | 71 |
100 /*-----------------------------------------------------------------------*/ | 72 /*-----------------------------------------------------------------------*/ |
101 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */ | 73 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */ |
102 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/ | 74 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/ |
103 /*-----------------------------------------------------------------------*/ | 75 /*-----------------------------------------------------------------------*/ |
194 run_in_other_process (HANDLE h_process, | 166 run_in_other_process (HANDLE h_process, |
195 LPTHREAD_START_ROUTINE routine, | 167 LPTHREAD_START_ROUTINE routine, |
196 LPVOID data, size_t data_size) | 168 LPVOID data, size_t data_size) |
197 { | 169 { |
198 process_memory pm; | 170 process_memory pm; |
199 const size_t code_size = FRAGMENT_CODE_SIZE; | 171 CONST size_t code_size = FRAGMENT_CODE_SIZE; |
200 /* Need at most 3 extra bytes of memory, for data alignment */ | 172 /* Need at most 3 extra bytes of memory, for data alignment */ |
201 size_t total_size = code_size + data_size + 3; | 173 size_t total_size = code_size + data_size + 3; |
202 LPVOID remote_data; | 174 LPVOID remote_data; |
203 HANDLE h_thread; | 175 HANDLE h_thread; |
204 DWORD dw_unused; | 176 DWORD dw_unused; |
249 } | 221 } |
250 | 222 |
251 /*-----------------------------------------------------------------------*/ | 223 /*-----------------------------------------------------------------------*/ |
252 /* Sending signals */ | 224 /* Sending signals */ |
253 /*-----------------------------------------------------------------------*/ | 225 /*-----------------------------------------------------------------------*/ |
254 | |
255 /* ---------------------------- the NT way ------------------------------- */ | |
256 | 226 |
257 /* | 227 /* |
258 * We handle the following signals: | 228 * We handle the following signals: |
259 * | 229 * |
260 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess | 230 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess |
315 /* | 285 /* |
316 * Send signal SIGNO to process H_PROCESS. | 286 * Send signal SIGNO to process H_PROCESS. |
317 * Return nonzero if successful. | 287 * Return nonzero if successful. |
318 */ | 288 */ |
319 | 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 | |
320 static int | 295 static int |
321 send_signal_the_nt_way (struct nt_process_data *cp, int pid, int signo) | 296 send_signal (HANDLE h_process, int signo) |
322 { | 297 { |
323 HANDLE h_process; | |
324 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 298 HMODULE h_kernel = GetModuleHandle ("kernel32"); |
325 int close_process = 0; | |
326 DWORD retval; | 299 DWORD retval; |
327 | 300 |
328 assert (h_kernel != NULL); | 301 assert (h_kernel != NULL); |
329 | 302 |
330 if (cp) | |
331 { | |
332 pid = cp->dwProcessId; | |
333 h_process = cp->h_process; | |
334 } | |
335 else | |
336 { | |
337 close_process = 1; | |
338 /* Try to open the process with required privileges */ | |
339 h_process = OpenProcess (PROCESS_CREATE_THREAD | |
340 | PROCESS_QUERY_INFORMATION | |
341 | PROCESS_VM_OPERATION | |
342 | PROCESS_VM_WRITE, | |
343 FALSE, pid); | |
344 if (!h_process) | |
345 return 0; | |
346 } | |
347 | |
348 switch (signo) | 303 switch (signo) |
349 { | 304 { |
350 case SIGKILL: | 305 case SIGKILL: |
351 case SIGTERM: | 306 case SIGTERM: |
352 case SIGQUIT: | 307 case SIGQUIT: |
353 case SIGHUP: | 308 case SIGHUP: |
354 { | 309 { |
355 sigkill_data d; | 310 sigkill_data d; |
356 | 311 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess"); |
357 d.adr_ExitProcess = | |
358 (void (WINAPI *) (UINT)) GetProcAddress (h_kernel, "ExitProcess"); | |
359 assert (d.adr_ExitProcess); | 312 assert (d.adr_ExitProcess); |
360 retval = run_in_other_process (h_process, | 313 retval = run_in_other_process (h_process, |
361 (LPTHREAD_START_ROUTINE)sigkill_proc, | 314 (LPTHREAD_START_ROUTINE)sigkill_proc, |
362 &d, sizeof (d)); | 315 &d, sizeof (d)); |
363 break; | 316 break; |
364 } | 317 } |
365 case SIGINT: | 318 case SIGINT: |
366 { | 319 { |
367 sigint_data d; | 320 sigint_data d; |
368 d.adr_GenerateConsoleCtrlEvent = | 321 d.adr_GenerateConsoleCtrlEvent = |
369 (BOOL (WINAPI *) (DWORD, DWORD)) | |
370 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); | 322 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); |
371 assert (d.adr_GenerateConsoleCtrlEvent); | 323 assert (d.adr_GenerateConsoleCtrlEvent); |
372 d.event = CTRL_C_EVENT; | 324 d.event = CTRL_C_EVENT; |
373 retval = run_in_other_process (h_process, | 325 retval = run_in_other_process (h_process, |
374 (LPTHREAD_START_ROUTINE)sigint_proc, | 326 (LPTHREAD_START_ROUTINE)sigint_proc, |
377 } | 329 } |
378 default: | 330 default: |
379 assert (0); | 331 assert (0); |
380 } | 332 } |
381 | 333 |
382 if (close_process) | |
383 CloseHandle (h_process); | |
384 return (int)retval > 0 ? 1 : 0; | 334 return (int)retval > 0 ? 1 : 0; |
385 } | 335 } |
386 | 336 |
387 /* | 337 /* |
388 * Enable CTRL_C_EVENT handling in a new child process | 338 * Enable CTRL_C_EVENT handling in a new child process |
393 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 343 HMODULE h_kernel = GetModuleHandle ("kernel32"); |
394 sig_enable_data d; | 344 sig_enable_data d; |
395 | 345 |
396 assert (h_kernel != NULL); | 346 assert (h_kernel != NULL); |
397 d.adr_SetConsoleCtrlHandler = | 347 d.adr_SetConsoleCtrlHandler = |
398 (BOOL (WINAPI *) (LPVOID, BOOL)) | |
399 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); | 348 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); |
400 assert (d.adr_SetConsoleCtrlHandler); | 349 assert (d.adr_SetConsoleCtrlHandler); |
401 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc, | 350 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc, |
402 &d, sizeof (d)); | 351 &d, sizeof (d)); |
403 } | 352 } |
404 | 353 |
405 #pragma warning (default : 4113) | 354 #pragma warning (default : 4113) |
406 | 355 |
407 /* ---------------------------- the 95 way ------------------------------- */ | |
408 | |
409 static BOOL CALLBACK | |
410 find_child_console (HWND hwnd, struct nt_process_data *cp) | |
411 { | |
412 DWORD thread_id; | |
413 DWORD process_id; | |
414 | |
415 thread_id = GetWindowThreadProcessId (hwnd, &process_id); | |
416 if (process_id == cp->dwProcessId) | |
417 { | |
418 char window_class[32]; | |
419 | |
420 GetClassName (hwnd, window_class, sizeof (window_class)); | |
421 if (strcmp (window_class, | |
422 mswindows_windows9x_p () | |
423 ? "tty" | |
424 : "ConsoleWindowClass") == 0) | |
425 { | |
426 cp->hwnd = hwnd; | |
427 return FALSE; | |
428 } | |
429 } | |
430 /* keep looking */ | |
431 return TRUE; | |
432 } | |
433 | |
434 static int | |
435 send_signal_the_95_way (struct nt_process_data *cp, int pid, int signo) | |
436 { | |
437 HANDLE h_process; | |
438 int close_process = 0; | |
439 int rc = 1; | |
440 | |
441 if (cp) | |
442 { | |
443 pid = cp->dwProcessId; | |
444 h_process = cp->h_process; | |
445 | |
446 /* Try to locate console window for process. */ | |
447 EnumWindows (find_child_console, (LPARAM) cp); | |
448 } | |
449 else | |
450 { | |
451 close_process = 1; | |
452 /* Try to open the process with required privileges */ | |
453 h_process = OpenProcess (PROCESS_TERMINATE, FALSE, pid); | |
454 if (!h_process) | |
455 return 0; | |
456 } | |
457 | |
458 if (signo == SIGINT) | |
459 { | |
460 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
461 { | |
462 BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0); | |
463 BYTE vk_break_code = VK_CANCEL; | |
464 BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | |
465 HWND foreground_window; | |
466 | |
467 if (break_scan_code == 0) | |
468 { | |
469 /* Fake Ctrl-C if we can't manage Ctrl-Break. */ | |
470 vk_break_code = 'C'; | |
471 break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | |
472 } | |
473 | |
474 foreground_window = GetForegroundWindow (); | |
475 if (foreground_window) | |
476 { | |
477 /* NT 5.0, and apparently also Windows 98, will not allow | |
478 a Window to be set to foreground directly without the | |
479 user's involvement. The workaround is to attach | |
480 ourselves to the thread that owns the foreground | |
481 window, since that is the only thread that can set the | |
482 foreground window. */ | |
483 DWORD foreground_thread, child_thread; | |
484 foreground_thread = | |
485 GetWindowThreadProcessId (foreground_window, NULL); | |
486 if (foreground_thread == GetCurrentThreadId () | |
487 || !AttachThreadInput (GetCurrentThreadId (), | |
488 foreground_thread, TRUE)) | |
489 foreground_thread = 0; | |
490 | |
491 child_thread = GetWindowThreadProcessId (cp->hwnd, NULL); | |
492 if (child_thread == GetCurrentThreadId () | |
493 || !AttachThreadInput (GetCurrentThreadId (), | |
494 child_thread, TRUE)) | |
495 child_thread = 0; | |
496 | |
497 /* Set the foreground window to the child. */ | |
498 if (SetForegroundWindow (cp->hwnd)) | |
499 { | |
500 /* Generate keystrokes as if user had typed Ctrl-Break or | |
501 Ctrl-C. */ | |
502 keybd_event (VK_CONTROL, control_scan_code, 0, 0); | |
503 keybd_event (vk_break_code, break_scan_code, | |
504 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0); | |
505 keybd_event (vk_break_code, break_scan_code, | |
506 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY) | |
507 | KEYEVENTF_KEYUP, 0); | |
508 keybd_event (VK_CONTROL, control_scan_code, | |
509 KEYEVENTF_KEYUP, 0); | |
510 | |
511 /* Sleep for a bit to give time for Emacs frame to respond | |
512 to focus change events (if Emacs was active app). */ | |
513 Sleep (100); | |
514 | |
515 SetForegroundWindow (foreground_window); | |
516 } | |
517 /* Detach from the foreground and child threads now that | |
518 the foreground switching is over. */ | |
519 if (foreground_thread) | |
520 AttachThreadInput (GetCurrentThreadId (), | |
521 foreground_thread, FALSE); | |
522 if (child_thread) | |
523 AttachThreadInput (GetCurrentThreadId (), | |
524 child_thread, FALSE); | |
525 } | |
526 } | |
527 /* Ctrl-Break is NT equivalent of SIGINT. */ | |
528 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid)) | |
529 { | |
530 #if 0 /* FSF Emacs */ | |
531 DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d " | |
532 "for pid %lu\n", GetLastError (), pid)); | |
533 errno = EINVAL; | |
534 #endif | |
535 rc = 0; | |
536 } | |
537 } | |
538 else | |
539 { | |
540 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
541 { | |
542 #if 1 | |
543 if (mswindows_windows9x_p ()) | |
544 { | |
545 /* | |
546 Another possibility is to try terminating the VDM out-right by | |
547 calling the Shell VxD (id 0x17) V86 interface, function #4 | |
548 "SHELL_Destroy_VM", ie. | |
549 | |
550 mov edx,4 | |
551 mov ebx,vm_handle | |
552 call shellapi | |
553 | |
554 First need to determine the current VM handle, and then arrange for | |
555 the shellapi call to be made from the system vm (by using | |
556 Switch_VM_and_callback). | |
557 | |
558 Could try to invoke DestroyVM through CallVxD. | |
559 | |
560 */ | |
561 #if 0 | |
562 /* On Win95, posting WM_QUIT causes the 16-bit subsystem | |
563 to hang when cmdproxy is used in conjunction with | |
564 command.com for an interactive shell. Posting | |
565 WM_CLOSE pops up a dialog that, when Yes is selected, | |
566 does the same thing. TerminateProcess is also less | |
567 than ideal in that subprocesses tend to stick around | |
568 until the machine is shutdown, but at least it | |
569 doesn't freeze the 16-bit subsystem. */ | |
570 PostMessage (cp->hwnd, WM_QUIT, 0xff, 0); | |
571 #endif | |
572 if (!TerminateProcess (h_process, 0xff)) | |
573 { | |
574 #if 0 /* FSF Emacs */ | |
575 DebPrint (("sys_kill.TerminateProcess returned %d " | |
576 "for pid %lu\n", GetLastError (), pid)); | |
577 errno = EINVAL; | |
578 #endif | |
579 rc = 0; | |
580 } | |
581 } | |
582 else | |
583 #endif | |
584 PostMessage (cp->hwnd, WM_CLOSE, 0, 0); | |
585 } | |
586 /* Kill the process. On W32 this doesn't kill child processes | |
587 so it doesn't work very well for shells which is why it's not | |
588 used in every case. */ | |
589 else if (!TerminateProcess (h_process, 0xff)) | |
590 { | |
591 #if 0 /* FSF Emacs */ | |
592 DebPrint (("sys_kill.TerminateProcess returned %d " | |
593 "for pid %lu\n", GetLastError (), pid)); | |
594 errno = EINVAL; | |
595 #endif | |
596 rc = 0; | |
597 } | |
598 } | |
599 | |
600 if (close_process) | |
601 CloseHandle (h_process); | |
602 | |
603 return rc; | |
604 } | |
605 | |
606 /* -------------------------- all-OS functions ---------------------------- */ | |
607 | |
608 static int | |
609 send_signal (struct nt_process_data *cp, int pid, int signo) | |
610 { | |
611 return send_signal_the_nt_way (cp, pid, signo) | |
612 || send_signal_the_95_way (cp, pid, signo); | |
613 } | |
614 | |
615 /* | 356 /* |
616 * Signal error if SIGNO is not supported | 357 * Signal error if SIGNO is not supported |
617 */ | 358 */ |
618 static void | 359 static void |
619 validate_signal_number (int signo) | 360 validate_signal_number (int signo) |
631 /* | 372 /* |
632 * Allocate and initialize Lisp_Process->process_data | 373 * Allocate and initialize Lisp_Process->process_data |
633 */ | 374 */ |
634 | 375 |
635 static void | 376 static void |
636 nt_alloc_process_data (Lisp_Process *p) | 377 nt_alloc_process_data (struct Lisp_Process *p) |
637 { | 378 { |
638 p->process_data = xnew_and_zero (struct nt_process_data); | 379 p->process_data = xnew_and_zero (struct nt_process_data); |
639 } | 380 } |
640 | 381 |
641 static void | 382 static void |
642 nt_finalize_process_data (Lisp_Process *p, int for_disksave) | 383 nt_finalize_process_data (struct Lisp_Process *p, int for_disksave) |
643 { | 384 { |
644 assert (!for_disksave); | 385 assert (!for_disksave); |
645 if (NT_DATA (p)->h_process) | 386 if (NT_DATA(p)->h_process) |
646 CloseHandle (NT_DATA (p)->h_process); | 387 CloseHandle (NT_DATA(p)->h_process); |
647 } | 388 } |
648 | 389 |
649 /* | 390 /* |
650 * Initialize XEmacs process implementation once | 391 * Initialize XEmacs process implementation once |
651 */ | 392 */ |
666 * The method must return PID of the new process, a (positive??? ####) number | 407 * The method must return PID of the new process, a (positive??? ####) number |
667 * which fits into Lisp_Int. No return value indicates an error, the method | 408 * which fits into Lisp_Int. No return value indicates an error, the method |
668 * must signal an error instead. | 409 * must signal an error instead. |
669 */ | 410 */ |
670 | 411 |
412 /* #### This function completely ignores Vprocess_environment */ | |
413 | |
671 static void | 414 static void |
672 signal_cannot_launch (Lisp_Object image_file, DWORD err) | 415 signal_cannot_launch (Lisp_Object image_file, DWORD err) |
673 { | 416 { |
674 mswindows_set_errno (err); | 417 mswindows_set_errno (err); |
675 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); | 418 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); |
676 } | 419 } |
677 | 420 |
678 static void | |
679 ensure_console_window_exists (void) | |
680 { | |
681 if (mswindows_windows9x_p ()) | |
682 mswindows_hide_console (); | |
683 } | |
684 | |
685 int | |
686 compare_env (const void *strp1, const void *strp2) | |
687 { | |
688 const char *str1 = *(const char**)strp1, *str2 = *(const char**)strp2; | |
689 | |
690 while (*str1 && *str2 && *str1 != '=' && *str2 != '=') | |
691 { | |
692 if ((*str1) > (*str2)) | |
693 return 1; | |
694 else if ((*str1) < (*str2)) | |
695 return -1; | |
696 str1++, str2++; | |
697 } | |
698 | |
699 if (*str1 == '=' && *str2 == '=') | |
700 return 0; | |
701 else if (*str1 == '=') | |
702 return -1; | |
703 else | |
704 return 1; | |
705 } | |
706 | |
707 static int | 421 static int |
708 nt_create_process (Lisp_Process *p, | 422 nt_create_process (struct Lisp_Process *p, |
709 Lisp_Object *argv, int nargv, | 423 Lisp_Object *argv, int nargv, |
710 Lisp_Object program, Lisp_Object cur_dir) | 424 Lisp_Object program, Lisp_Object cur_dir) |
711 { | 425 { |
712 /* Synched up with sys_spawnve in FSF 20.6. Significantly different | 426 HANDLE hmyshove, hmyslurp, hprocin, hprocout; |
713 but still synchable. */ | 427 LPTSTR command_line; |
714 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr; | |
715 Extbyte *command_line; | |
716 BOOL do_io, windowed; | 428 BOOL do_io, windowed; |
717 char *proc_env; | |
718 | |
719 /* No need to DOS-ize the filename; expand-file-name (called prior) | |
720 already does this. */ | |
721 | 429 |
722 /* Find out whether the application is windowed or not */ | 430 /* Find out whether the application is windowed or not */ |
723 { | 431 { |
724 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most | 432 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most |
725 errors. This leads to bogus error message. */ | 433 errors. This leads to bogus error message. */ |
763 sa.lpSecurityDescriptor = NULL; | 471 sa.lpSecurityDescriptor = NULL; |
764 | 472 |
765 CreatePipe (&hprocin, &hmyshove, &sa, 0); | 473 CreatePipe (&hprocin, &hmyshove, &sa, 0); |
766 CreatePipe (&hmyslurp, &hprocout, &sa, 0); | 474 CreatePipe (&hmyslurp, &hprocout, &sa, 0); |
767 | 475 |
768 /* Duplicate the stdout handle for use as stderr */ | |
769 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), | |
770 &hprocerr, 0, TRUE, DUPLICATE_SAME_ACCESS); | |
771 | |
772 /* Stupid Win32 allows to create a pipe with *both* ends either | 476 /* Stupid Win32 allows to create a pipe with *both* ends either |
773 inheritable or not. We need process ends inheritable, and local | 477 inheritable or not. We need process ends inheritable, and local |
774 ends not inheritable. */ | 478 ends not inheritable. */ |
775 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), | 479 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp, |
776 &htmp, 0, FALSE, | 480 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); |
777 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
778 hmyshove = htmp; | 481 hmyshove = htmp; |
779 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), | 482 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), &htmp, |
780 &htmp, 0, FALSE, | 483 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); |
781 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
782 hmyslurp = htmp; | 484 hmyslurp = htmp; |
783 } | 485 } |
784 | 486 |
785 /* Convert an argv vector into Win32 style command line. */ | 487 /* Convert an argv vector into Win32 style command line by a call to |
488 lisp function `nt-quote-process-args' which see (in winnt.el)*/ | |
786 { | 489 { |
787 int i; | 490 int i; |
788 Bufbyte **quoted_args; | 491 Lisp_Object args_or_ret = Qnil; |
789 int is_dos_app, is_cygnus_app; | 492 struct gcpro gcpro1; |
790 int is_command_shell; | 493 |
791 int do_quoting = 0; | 494 GCPRO1 (args_or_ret); |
792 char escape_char = 0; | 495 |
793 | |
794 nargv++; /* include program; we access argv offset by 1 below */ | |
795 quoted_args = alloca_array (Bufbyte *, nargv); | |
796 | |
797 /* Determine whether program is a 16-bit DOS executable, or a Win32 | |
798 executable that is implicitly linked to the Cygnus dll (implying it | |
799 was compiled with the Cygnus GNU toolchain and hence relies on | |
800 cygwin.dll to parse the command line - we use this to decide how to | |
801 escape quote chars in command line args that must be quoted). */ | |
802 mswindows_executable_type (XSTRING_DATA (program), | |
803 &is_dos_app, &is_cygnus_app); | |
804 | |
805 { | |
806 /* #### Bleeeeeeeeeeeeeeeeech!!!! The command shells appear to | |
807 use '^' as a quote character, at least under NT. #### I haven't | |
808 tested 95. If it allows no quoting conventions at all, set | |
809 escape_char to 0 and the code below will work. (e.g. NT tolerates | |
810 no quoting -- this command | |
811 | |
812 cmd /c "ls "/Program Files"" | |
813 | |
814 actually works.) */ | |
815 | |
816 struct gcpro gcpro1, gcpro2; | |
817 Lisp_Object progname = Qnil; | |
818 | |
819 GCPRO2 (program, progname); | |
820 progname = Ffile_name_nondirectory (program); | |
821 progname = Fdowncase (progname, Qnil); | |
822 | |
823 is_command_shell = | |
824 internal_equal (progname, build_string ("command.com"), 0) | |
825 || internal_equal (progname, build_string ("cmd.exe"), 0); | |
826 UNGCPRO; | |
827 } | |
828 | |
829 #if 0 | |
830 /* #### we need to port this. */ | |
831 /* On Windows 95, if cmdname is a DOS app, we invoke a helper | |
832 application to start it by specifying the helper app as cmdname, | |
833 while leaving the real app name as argv[0]. */ | |
834 if (is_dos_app) | |
835 { | |
836 cmdname = (char*) alloca (MAXPATHLEN); | |
837 if (egetenv ("CMDPROXY")) | |
838 strcpy ((char*)cmdname, egetenv ("CMDPROXY")); | |
839 else | |
840 { | |
841 strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory)); | |
842 strcat ((char*)cmdname, "cmdproxy.exe"); | |
843 } | |
844 } | |
845 #endif | |
846 | |
847 /* we have to do some conjuring here to put argv and envp into the | |
848 form CreateProcess wants... argv needs to be a space separated/null | |
849 terminated list of parameters, and envp is a null | |
850 separated/double-null terminated list of parameters. | |
851 | |
852 Additionally, zero-length args and args containing whitespace or | |
853 quote chars need to be wrapped in double quotes - for this to work, | |
854 embedded quotes need to be escaped as well. The aim is to ensure | |
855 the child process reconstructs the argv array we start with | |
856 exactly, so we treat quotes at the beginning and end of arguments | |
857 as embedded quotes. | |
858 | |
859 The Win32 GNU-based library from Cygnus doubles quotes to escape | |
860 them, while MSVC uses backslash for escaping. (Actually the MSVC | |
861 startup code does attempt to recognize doubled quotes and accept | |
862 them, but gets it wrong and ends up requiring three quotes to get a | |
863 single embedded quote!) So by default we decide whether to use | |
864 quote or backslash as the escape character based on whether the | |
865 binary is apparently a Cygnus compiled app. | |
866 | |
867 Note that using backslash to escape embedded quotes requires | |
868 additional special handling if an embedded quote is already | |
869 preceded by backslash, or if an arg requiring quoting ends with | |
870 backslash. In such cases, the run of escape characters needs to be | |
871 doubled. For consistency, we apply this special handling as long | |
872 as the escape character is not quote. | |
873 | |
874 Since we have no idea how large argv and envp are likely to be we | |
875 figure out list lengths on the fly and allocate them. */ | |
876 | |
877 if (!NILP (Vmswindows_quote_process_args)) | |
878 { | |
879 do_quoting = 1; | |
880 /* Override escape char by binding mswindows-quote-process-args to | |
881 desired character, or use t for auto-selection. */ | |
882 if (INTP (Vmswindows_quote_process_args)) | |
883 escape_char = (char) XINT (Vmswindows_quote_process_args); | |
884 else | |
885 escape_char = is_command_shell ? '^' : is_cygnus_app ? '"' : '\\'; | |
886 } | |
887 | |
888 /* do argv... */ | |
889 for (i = 0; i < nargv; ++i) | 496 for (i = 0; i < nargv; ++i) |
890 { | 497 args_or_ret = Fcons (*argv++, args_or_ret); |
891 Bufbyte *targ = XSTRING_DATA (i == 0 ? program : argv[i - 1]); | 498 args_or_ret = Fnreverse (args_or_ret); |
892 Bufbyte *p = targ; | 499 args_or_ret = Fcons (program, args_or_ret); |
893 int need_quotes = 0; | 500 |
894 int escape_char_run = 0; | 501 args_or_ret = call1 (Qnt_quote_process_args, args_or_ret); |
895 int arglen = 0; | 502 |
896 | 503 if (!STRINGP (args_or_ret)) |
897 if (*p == 0) | 504 /* Luser wrote his/her own clever version */ |
898 need_quotes = 1; | 505 error ("Bogus return value from `nt-quote-process-args'"); |
899 for ( ; *p; p++) | 506 |
900 { | 507 command_line = alloca_array (char, (XSTRING_LENGTH (program) |
901 if (*p == '"') | 508 + XSTRING_LENGTH (args_or_ret) + 2)); |
902 { | 509 strcpy (command_line, XSTRING_DATA (program)); |
903 /* allow for embedded quotes to be escaped */ | 510 strcat (command_line, " "); |
904 if (escape_char) | 511 strcat (command_line, XSTRING_DATA (args_or_ret)); |
905 arglen++; | 512 |
906 need_quotes = 1; | 513 UNGCPRO; /* args_or_ret */ |
907 /* handle the case where the embedded quote is already escaped */ | |
908 if (escape_char_run > 0) | |
909 { | |
910 /* To preserve the arg exactly, we need to double the | |
911 preceding escape characters (plus adding one to | |
912 escape the quote character itself). */ | |
913 arglen += escape_char_run; | |
914 } | |
915 } | |
916 else if (*p == ' ' || *p == '\t') | |
917 { | |
918 need_quotes = 1; | |
919 } | |
920 | |
921 if (escape_char && *p == escape_char && escape_char != '"') | |
922 escape_char_run++; | |
923 else | |
924 escape_char_run = 0; | |
925 } | |
926 if (need_quotes) | |
927 { | |
928 arglen += 2; | |
929 /* handle the case where the arg ends with an escape char - we | |
930 must not let the enclosing quote be escaped. */ | |
931 if (escape_char_run > 0) | |
932 arglen += escape_char_run; | |
933 } | |
934 arglen += strlen (targ) + 1; | |
935 | |
936 quoted_args[i] = alloca_array (Bufbyte, arglen); | |
937 } | |
938 | |
939 for (i = 0; i < nargv; ++i) | |
940 { | |
941 Bufbyte *targ = XSTRING_DATA (i == 0 ? program : argv[i - 1]); | |
942 Bufbyte *p = targ; | |
943 int need_quotes = 0; | |
944 Bufbyte *parg = quoted_args[i]; | |
945 | |
946 if (*p == 0) | |
947 need_quotes = 1; | |
948 | |
949 if (do_quoting) | |
950 { | |
951 for ( ; *p; p++) | |
952 if (*p == ' ' || *p == '\t' || *p == '"') | |
953 need_quotes = 1; | |
954 } | |
955 if (need_quotes) | |
956 { | |
957 int escape_char_run = 0; | |
958 Bufbyte * first; | |
959 Bufbyte * last; | |
960 | |
961 p = targ; | |
962 first = p; | |
963 last = p + strlen (p) - 1; | |
964 *parg++ = '"'; | |
965 #if 0 | |
966 /* This version does not escape quotes if they occur at the | |
967 beginning or end of the arg - this could lead to incorrect | |
968 behavior when the arg itself represents a command line | |
969 containing quoted args. I believe this was originally done | |
970 as a hack to make some things work, before | |
971 `mswindows-quote-process-args' was added. */ | |
972 while (*p) | |
973 { | |
974 if (*p == '"' && p > first && p < last) | |
975 *parg++ = escape_char; /* escape embedded quotes */ | |
976 *parg++ = *p++; | |
977 } | |
978 #else | |
979 for ( ; *p; p++) | |
980 { | |
981 if (escape_char && *p == '"') | |
982 { | |
983 /* double preceding escape chars if any */ | |
984 while (escape_char_run > 0) | |
985 { | |
986 *parg++ = escape_char; | |
987 escape_char_run--; | |
988 } | |
989 /* escape all quote chars, even at beginning or end */ | |
990 *parg++ = escape_char; | |
991 } | |
992 *parg++ = *p; | |
993 | |
994 if (escape_char && *p == escape_char && escape_char != '"') | |
995 escape_char_run++; | |
996 else | |
997 escape_char_run = 0; | |
998 } | |
999 /* double escape chars before enclosing quote */ | |
1000 while (escape_char_run > 0) | |
1001 { | |
1002 *parg++ = escape_char; | |
1003 escape_char_run--; | |
1004 } | |
1005 #endif | |
1006 *parg++ = '"'; | |
1007 } | |
1008 else | |
1009 { | |
1010 strcpy (parg, targ); | |
1011 parg += strlen (targ); | |
1012 } | |
1013 *parg = '\0'; | |
1014 } | |
1015 | |
1016 { | |
1017 int total_cmdline_len = 0; | |
1018 Extcount *extargcount = (Extcount *) alloca_array (Extcount, nargv); | |
1019 Extbyte **extarg = (Extbyte **) alloca_array (Extbyte *, nargv); | |
1020 Extbyte *command_ptr; | |
1021 | |
1022 for (i = 0; i < nargv; ++i) | |
1023 { | |
1024 TO_EXTERNAL_FORMAT (C_STRING, quoted_args[i], ALLOCA, | |
1025 (extarg[i], extargcount[i]), Qmswindows_tstr); | |
1026 /* account for space and terminating null */ | |
1027 total_cmdline_len += extargcount[i] + EITCHAR_SIZE; | |
1028 } | |
1029 | |
1030 command_line = alloca_array (char, total_cmdline_len); | |
1031 command_ptr = command_line; | |
1032 for (i = 0; i < nargv; ++i) | |
1033 { | |
1034 memcpy (command_ptr, extarg[i], extargcount[i]); | |
1035 command_ptr += extargcount[i]; | |
1036 EICOPY_TCHAR (command_ptr, ' '); | |
1037 command_ptr += EITCHAR_SIZE; | |
1038 } | |
1039 EICOPY_TCHAR (command_ptr, '\0'); | |
1040 command_ptr += EITCHAR_SIZE; | |
1041 } | |
1042 } | 514 } |
1043 /* Set `proc_env' to a nul-separated array of the strings in | 515 |
1044 Vprocess_environment terminated by 2 nuls. */ | |
1045 | |
1046 { | |
1047 char **env; | |
1048 REGISTER Lisp_Object tem; | |
1049 REGISTER char **new_env; | |
1050 REGISTER int new_length = 0, i, new_space; | |
1051 char *penv; | |
1052 | |
1053 for (tem = Vprocess_environment; | |
1054 (CONSP (tem) | |
1055 && STRINGP (XCAR (tem))); | |
1056 tem = XCDR (tem)) | |
1057 new_length++; | |
1058 | |
1059 /* FSF adds an extra env var to hold the current process ID of the | |
1060 Emacs process. Apparently this is used only by emacsserver.c, | |
1061 which we have superseded to gnuserv.c. (#### Does it work under | |
1062 MS Windows?) | |
1063 | |
1064 sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d", | |
1065 GetCurrentProcessId ()); | |
1066 arglen += strlen (ppid_env_var_buffer) + 1; | |
1067 numenv++; | |
1068 */ | |
1069 | |
1070 /* new_length + 1 to include terminating 0. */ | |
1071 env = new_env = alloca_array (char *, new_length + 1); | |
1072 | |
1073 /* Copy the Vprocess_environment strings into new_env. */ | |
1074 for (tem = Vprocess_environment; | |
1075 (CONSP (tem) | |
1076 && STRINGP (XCAR (tem))); | |
1077 tem = XCDR (tem)) | |
1078 { | |
1079 char **ep = env; | |
1080 char *string = (char *) XSTRING_DATA (XCAR (tem)); | |
1081 /* See if this string duplicates any string already in the env. | |
1082 If so, don't put it in. | |
1083 When an env var has multiple definitions, | |
1084 we keep the definition that comes first in process-environment. */ | |
1085 for (; ep != new_env; ep++) | |
1086 { | |
1087 char *p = *ep, *q = string; | |
1088 while (1) | |
1089 { | |
1090 if (*q == 0) | |
1091 /* The string is malformed; might as well drop it. */ | |
1092 goto duplicate; | |
1093 if (*q != *p) | |
1094 break; | |
1095 if (*q == '=') | |
1096 goto duplicate; | |
1097 p++, q++; | |
1098 } | |
1099 } | |
1100 *new_env++ = string; | |
1101 duplicate: ; | |
1102 } | |
1103 *new_env = 0; | |
1104 | |
1105 /* Sort the environment variables */ | |
1106 new_length = new_env - env; | |
1107 qsort (env, new_length, sizeof (char *), compare_env); | |
1108 | |
1109 /* Work out how much space to allocate */ | |
1110 new_space = 0; | |
1111 for (i = 0; i < new_length; i++) | |
1112 { | |
1113 new_space += strlen(env[i]) + 1; | |
1114 } | |
1115 new_space++; | |
1116 | |
1117 /* Allocate space and copy variables into it */ | |
1118 penv = proc_env = (char*) alloca(new_space); | |
1119 for (i = 0; i < new_length; i++) | |
1120 { | |
1121 strcpy(penv, env[i]); | |
1122 penv += strlen(env[i]) + 1; | |
1123 } | |
1124 *penv = 0; | |
1125 } | |
1126 | |
1127 /* Create process */ | 516 /* Create process */ |
1128 { | 517 { |
1129 STARTUPINFO si; | 518 STARTUPINFO si; |
1130 PROCESS_INFORMATION pi; | 519 PROCESS_INFORMATION pi; |
1131 DWORD err; | 520 DWORD err; |
1132 DWORD flags; | |
1133 | 521 |
1134 xzero (si); | 522 xzero (si); |
1135 si.dwFlags = STARTF_USESHOWWINDOW; | 523 si.dwFlags = STARTF_USESHOWWINDOW; |
1136 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; | 524 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; |
1137 if (do_io) | 525 if (do_io) |
1138 { | 526 { |
1139 si.hStdInput = hprocin; | 527 si.hStdInput = hprocin; |
1140 si.hStdOutput = hprocout; | 528 si.hStdOutput = hprocout; |
1141 si.hStdError = hprocerr; | 529 si.hStdError = hprocout; |
1142 si.dwFlags |= STARTF_USESTDHANDLES; | 530 si.dwFlags |= STARTF_USESTDHANDLES; |
1143 } | 531 } |
1144 | 532 |
1145 flags = CREATE_SUSPENDED; | 533 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, |
1146 if (mswindows_windows9x_p ()) | 534 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP |
1147 flags |= (!NILP (Vmswindows_start_process_share_console) | 535 | CREATE_SUSPENDED, |
1148 ? CREATE_NEW_PROCESS_GROUP | 536 NULL, (char *) XSTRING_DATA (cur_dir), &si, &pi) |
1149 : CREATE_NEW_CONSOLE); | |
1150 else | |
1151 flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; | |
1152 if (NILP (Vmswindows_start_process_inherit_error_mode)) | |
1153 flags |= CREATE_DEFAULT_ERROR_MODE; | |
1154 | |
1155 ensure_console_window_exists (); | |
1156 | |
1157 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, flags, | |
1158 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi) | |
1159 ? 0 : GetLastError ()); | 537 ? 0 : GetLastError ()); |
1160 | 538 |
1161 if (do_io) | 539 if (do_io) |
1162 { | 540 { |
1163 /* These just have been inherited; we do not need a copy */ | 541 /* These just have been inherited; we do not need a copy */ |
1164 CloseHandle (hprocin); | 542 CloseHandle (hprocin); |
1165 CloseHandle (hprocout); | 543 CloseHandle (hprocout); |
1166 CloseHandle (hprocerr); | |
1167 } | 544 } |
1168 | 545 |
1169 /* Handle process creation failure */ | 546 /* Handle process creation failure */ |
1170 if (err) | 547 if (err) |
1171 { | 548 { |
1179 | 556 |
1180 /* The process started successfully */ | 557 /* The process started successfully */ |
1181 if (do_io) | 558 if (do_io) |
1182 { | 559 { |
1183 NT_DATA(p)->h_process = pi.hProcess; | 560 NT_DATA(p)->h_process = pi.hProcess; |
1184 NT_DATA(p)->dwProcessId = pi.dwProcessId; | |
1185 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0); | 561 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0); |
1186 } | 562 } |
1187 else | 563 else |
1188 { | 564 { |
1189 /* Indicate as if the process has exited immediately. */ | 565 /* Indicate as if the process has exited immediately. */ |
1195 enable_child_signals (pi.hProcess); | 571 enable_child_signals (pi.hProcess); |
1196 | 572 |
1197 ResumeThread (pi.hThread); | 573 ResumeThread (pi.hThread); |
1198 CloseHandle (pi.hThread); | 574 CloseHandle (pi.hThread); |
1199 | 575 |
1200 return ((int)pi.dwProcessId); | 576 /* Hack to support Windows 95 negative pids */ |
577 return ((int)pi.dwProcessId < 0 | |
578 ? -(int)pi.dwProcessId : (int)pi.dwProcessId); | |
1201 } | 579 } |
1202 } | 580 } |
1203 | 581 |
1204 /* | 582 /* |
1205 * This method is called to update status fields of the process | 583 * This method is called to update status fields of the process |
1208 * | 586 * |
1209 * The method is called only for real child processes. | 587 * The method is called only for real child processes. |
1210 */ | 588 */ |
1211 | 589 |
1212 static void | 590 static void |
1213 nt_update_status_if_terminated (Lisp_Process* p) | 591 nt_update_status_if_terminated (struct Lisp_Process* p) |
1214 { | 592 { |
1215 DWORD exit_code; | 593 DWORD exit_code; |
1216 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) | 594 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) |
1217 && exit_code != STILL_ACTIVE) | 595 && exit_code != STILL_ACTIVE) |
1218 { | 596 { |
1242 unix_send_process... */ | 620 unix_send_process... */ |
1243 | 621 |
1244 static void | 622 static void |
1245 nt_send_process (Lisp_Object proc, struct lstream* lstream) | 623 nt_send_process (Lisp_Object proc, struct lstream* lstream) |
1246 { | 624 { |
1247 volatile Lisp_Object vol_proc = proc; | 625 struct Lisp_Process *p = XPROCESS (proc); |
1248 Lisp_Process *volatile p = XPROCESS (proc); | |
1249 | 626 |
1250 /* use a reasonable-sized buffer (somewhere around the size of the | 627 /* use a reasonable-sized buffer (somewhere around the size of the |
1251 stream buffer) so as to avoid inundating the stream with blocked | 628 stream buffer) so as to avoid inundating the stream with blocked |
1252 data. */ | 629 data. */ |
1253 Bufbyte chunkbuf[512]; | 630 Bufbyte chunkbuf[128]; |
1254 Bytecount chunklen; | 631 Bytecount chunklen; |
1255 | 632 |
1256 while (1) | 633 while (1) |
1257 { | 634 { |
1258 ssize_t writeret; | 635 int writeret; |
1259 | 636 |
1260 chunklen = Lstream_read (lstream, chunkbuf, 512); | 637 chunklen = Lstream_read (lstream, chunkbuf, 128); |
1261 if (chunklen <= 0) | 638 if (chunklen <= 0) |
1262 break; /* perhaps should abort() if < 0? | 639 break; /* perhaps should abort() if < 0? |
1263 This should never happen. */ | 640 This should never happen. */ |
1264 | 641 |
1265 /* Lstream_write() will never successfully write less than the | 642 /* Lstream_write() will never successfully write less than the |
1273 p->status_symbol = Qexit; | 650 p->status_symbol = Qexit; |
1274 p->exit_code = ERROR_BROKEN_PIPE; | 651 p->exit_code = ERROR_BROKEN_PIPE; |
1275 p->core_dumped = 0; | 652 p->core_dumped = 0; |
1276 p->tick++; | 653 p->tick++; |
1277 process_tick++; | 654 process_tick++; |
1278 deactivate_process (*((Lisp_Object *) (&vol_proc))); | 655 deactivate_process (proc); |
1279 error ("Broken pipe error sending to process %s; closed it", | 656 error ("Broken pipe error sending to process %s; closed it", |
1280 XSTRING_DATA (p->name)); | 657 XSTRING_DATA (p->name)); |
1281 } | 658 } |
1282 | 659 |
1283 { | 660 { |
1311 | 688 |
1312 static void | 689 static void |
1313 nt_kill_child_process (Lisp_Object proc, int signo, | 690 nt_kill_child_process (Lisp_Object proc, int signo, |
1314 int current_group, int nomsg) | 691 int current_group, int nomsg) |
1315 { | 692 { |
1316 Lisp_Process *p = XPROCESS (proc); | 693 struct Lisp_Process *p = XPROCESS (proc); |
1317 | 694 |
1318 /* Signal error if SIGNO cannot be sent */ | 695 /* Signal error if SIGNO cannot be sent */ |
1319 validate_signal_number (signo); | 696 validate_signal_number (signo); |
1320 | 697 |
1321 /* Send signal */ | 698 /* Send signal */ |
1322 if (!send_signal (NT_DATA (p), 0, signo)) | 699 if (!send_signal (NT_DATA(p)->h_process, signo)) |
1323 signal_simple_error ("Cannot send signal to process", proc); | 700 error ("Cannot send signal to process"); |
1324 } | 701 } |
1325 | 702 |
1326 /* | 703 /* |
1327 * Kill any process in the system given its PID | 704 * Kill any process in the system given its PID. |
1328 * | 705 * |
1329 * Returns zero if a signal successfully sent, or | 706 * Returns zero if a signal successfully sent, or |
1330 * negative number upon failure | 707 * negative number upon failure |
1331 */ | 708 */ |
1332 static int | 709 static int |
1333 nt_kill_process_by_pid (int pid, int signo) | 710 nt_kill_process_by_pid (int pid, int signo) |
1334 { | 711 { |
1335 struct Lisp_Process *p; | 712 HANDLE h_process; |
1336 | 713 int send_result; |
714 | |
1337 /* Signal error if SIGNO cannot be sent */ | 715 /* Signal error if SIGNO cannot be sent */ |
1338 validate_signal_number (signo); | 716 validate_signal_number (signo); |
1339 | 717 |
1340 p = find_process_from_pid (pid); | 718 /* Try to open the process with required privileges */ |
1341 return send_signal (p ? NT_DATA (p) : 0, pid, signo) ? 0 : -1; | 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; | |
1342 } | 732 } |
1343 | 733 |
1344 /*-----------------------------------------------------------------------*/ | 734 /*-----------------------------------------------------------------------*/ |
1345 /* Sockets connections */ | 735 /* Sockets connections */ |
1346 /*-----------------------------------------------------------------------*/ | 736 /*-----------------------------------------------------------------------*/ |
1393 if (msg.message == XM_SOCKREPLY) | 783 if (msg.message == XM_SOCKREPLY) |
1394 { | 784 { |
1395 /* Ok, got an answer */ | 785 /* Ok, got an answer */ |
1396 if (WSAGETASYNCERROR(msg.lParam) == NO_ERROR) | 786 if (WSAGETASYNCERROR(msg.lParam) == NO_ERROR) |
1397 success = 1; | 787 success = 1; |
1398 else | |
1399 { | |
1400 warn_when_safe(Qstream, Qwarning, | |
1401 "cannot get IP address for host \"%s\"", | |
1402 XSTRING_DATA (host)); | |
1403 } | |
1404 goto done; | 788 goto done; |
1405 } | 789 } |
1406 else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID) | 790 else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID) |
1407 { | 791 { |
1408 if (QUITP) | 792 if (QUITP) |
1447 differences are in status display and process deletion. A network | 831 differences are in status display and process deletion. A network |
1448 connection has no PID; you cannot signal it. All you can do is | 832 connection has no PID; you cannot signal it. All you can do is |
1449 deactivate and close it via delete-process */ | 833 deactivate and close it via delete-process */ |
1450 | 834 |
1451 static void | 835 static void |
1452 nt_open_network_stream (Lisp_Object name, Lisp_Object host, | 836 nt_open_network_stream (Lisp_Object name, Lisp_Object host, Lisp_Object service, |
1453 Lisp_Object service, | 837 Lisp_Object family, void** vinfd, void** voutfd) |
1454 Lisp_Object protocol, void** vinfd, void** voutfd) | 838 { |
1455 { | |
1456 /* !!#### not Mule-ized */ | |
1457 struct sockaddr_in address; | 839 struct sockaddr_in address; |
1458 SOCKET s; | 840 SOCKET s; |
1459 int port; | 841 int port; |
1460 int retval; | 842 int retval; |
1461 | 843 |
1462 CHECK_STRING (host); | 844 CHECK_STRING (host); |
1463 | 845 |
1464 if (!EQ (protocol, Qtcp)) | 846 if (!EQ (family, Qtcpip)) |
1465 signal_simple_error ("Unsupported protocol", protocol); | 847 error ("Unsupported protocol family \"%s\"", |
848 string_data (symbol_name (XSYMBOL (family)))); | |
1466 | 849 |
1467 if (INTP (service)) | 850 if (INTP (service)) |
1468 port = htons ((unsigned short) XINT (service)); | 851 port = htons ((unsigned short) XINT (service)); |
1469 else | 852 else |
1470 { | 853 { |
1471 struct servent *svc_info; | 854 struct servent *svc_info; |
1472 CHECK_STRING (service); | 855 CHECK_STRING (service); |
1473 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp"); | 856 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp"); |
1474 if (svc_info == 0) | 857 if (svc_info == 0) |
1475 signal_simple_error ("Unknown service", service); | 858 error ("Unknown service \"%s\"", XSTRING_DATA (service)); |
1476 port = svc_info->s_port; | 859 port = svc_info->s_port; |
1477 } | 860 } |
1478 | 861 |
1479 get_internet_address (host, &address, ERROR_ME); | 862 get_internet_address (host, &address, ERROR_ME); |
1480 address.sin_port = port; | 863 address.sin_port = port; |
1490 } | 873 } |
1491 | 874 |
1492 retval = connect (s, (struct sockaddr *) &address, sizeof (address)); | 875 retval = connect (s, (struct sockaddr *) &address, sizeof (address)); |
1493 if (retval != NO_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) | 876 if (retval != NO_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) |
1494 goto connect_failed; | 877 goto connect_failed; |
878 | |
1495 /* Wait while connection is established */ | 879 /* Wait while connection is established */ |
1496 while (1) | 880 while (1) |
1497 { | 881 { |
1498 fd_set fdset; | 882 fd_set fdset; |
1499 struct timeval tv; | 883 struct timeval tv; |
1532 0, FALSE, DUPLICATE_SAME_ACCESS); | 916 0, FALSE, DUPLICATE_SAME_ACCESS); |
1533 return; | 917 return; |
1534 | 918 |
1535 connect_failed: | 919 connect_failed: |
1536 closesocket (s); | 920 closesocket (s); |
1537 if (INTP (service)) | |
1538 { | |
1539 warn_when_safe (Qstream, Qwarning, | |
1540 "failure to open network stream to host \"%s\" for service \"%d\"", | |
1541 XSTRING_DATA (host), | |
1542 (unsigned short) XINT (service)); | |
1543 } | |
1544 else | |
1545 { | |
1546 warn_when_safe (Qstream, Qwarning, | |
1547 "failure to open network stream to host \"%s\" for service \"%s\"", | |
1548 XSTRING_DATA (host), | |
1549 XSTRING_DATA (service)); | |
1550 } | |
1551 report_file_error ("connection failed", list2 (host, name)); | 921 report_file_error ("connection failed", list2 (host, name)); |
1552 } | 922 } |
1553 | 923 |
1554 #endif | 924 #endif |
1555 | 925 |
1579 } | 949 } |
1580 | 950 |
1581 void | 951 void |
1582 syms_of_process_nt (void) | 952 syms_of_process_nt (void) |
1583 { | 953 { |
954 defsymbol (&Qnt_quote_process_args, "nt-quote-process-args"); | |
1584 } | 955 } |
1585 | 956 |
1586 void | 957 void |
1587 vars_of_process_nt (void) | 958 vars_of_process_nt (void) |
1588 { | 959 { |
1589 DEFVAR_LISP ("mswindows-quote-process-args", | 960 } |
1590 &Vmswindows_quote_process_args /* | |
1591 Non-nil enables quoting of process arguments to ensure correct parsing. | |
1592 Because Windows does not directly pass argv arrays to child processes, | |
1593 programs have to reconstruct the argv array by parsing the command | |
1594 line string. For an argument to contain a space, it must be enclosed | |
1595 in double quotes or it will be parsed as multiple arguments. | |
1596 | |
1597 If the value is a character, that character will be used to escape any | |
1598 quote characters that appear, otherwise a suitable escape character | |
1599 will be chosen based on the type of the program (normal or Cygwin). | |
1600 */ ); | |
1601 Vmswindows_quote_process_args = Qt; | |
1602 | |
1603 DEFVAR_LISP ("mswindows-start-process-share-console", | |
1604 &Vmswindows_start_process_share_console /* | |
1605 When nil, new child processes are given a new console. | |
1606 When non-nil, they share the Emacs console; this has the limitation of | |
1607 allowing only only DOS subprocess to run at a time (whether started directly | |
1608 or indirectly by Emacs), and preventing Emacs from cleanly terminating the | |
1609 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't | |
1610 otherwise respond to interrupts from Emacs. | |
1611 */ ); | |
1612 Vmswindows_start_process_share_console = Qnil; | |
1613 | |
1614 DEFVAR_LISP ("mswindows-start-process-inherit-error-mode", | |
1615 &Vmswindows_start_process_inherit_error_mode /* | |
1616 "When nil, new child processes revert to the default error mode. | |
1617 When non-nil, they inherit their error mode setting from Emacs, which stops | |
1618 them blocking when trying to access unmounted drives etc. | |
1619 */ ); | |
1620 Vmswindows_start_process_inherit_error_mode = Qt; | |
1621 } |