* child_info.h (child_info::sync): Pass pid and HANDLE rather than using pinfo.
(child_info::child_info): Accept an argument controlling whether to create proc_subproc. (child_info_spawn::child_info_spawn): Ditto. * sigproc.cc (child_info::child_info): Ditto. (child_info_spawn::child_info_spawn): Ditto. (child_info::sync): Use passed in pid and HANDLE. * fork.cc (fork_parent): Reflect additional arguments required for child_info::sync. * hookapi.cc (hook_or_detect_cygwin): Rename. Change so that NULL 'fn' argument just returns "true", indicating that program uses cygwin1.dll. * spawn.cc (av::win16_exe): New element. * spawn.cc (av::iscygwin): New element. (av::fixup): New function. (spawn_guts): Protect against SEGV. Use fixup function to detect when it is safe to wait for a spawned (as opposed to an execed) program. Reflect changes in child_info::sync arguments. * external.cc (cygwin_internal): Reflect function renaming to hook_or_detect_cygwin. * cygheap.cc (cygheap_fixup_in_child): Close handle after debug fixup has been done to prevent false positives in handle collision. * exceptions.cc (try_to_debug): Notify debugger if already being debugged.
This commit is contained in:
		| @@ -1,3 +1,32 @@ | |||||||
|  | 2005-07-16  Christopher Faylor  <cgf@timesys.com> | ||||||
|  |  | ||||||
|  | 	* child_info.h (child_info::sync): Pass pid and HANDLE rather than | ||||||
|  | 	using pinfo. | ||||||
|  | 	(child_info::child_info): Accept an argument controlling whether to | ||||||
|  | 	create proc_subproc. | ||||||
|  | 	(child_info_spawn::child_info_spawn): Ditto. | ||||||
|  | 	* sigproc.cc (child_info::child_info): Ditto. | ||||||
|  | 	(child_info_spawn::child_info_spawn): Ditto. | ||||||
|  | 	(child_info::sync): Use passed in pid and HANDLE. | ||||||
|  | 	* fork.cc (fork_parent): Reflect additional arguments required for | ||||||
|  | 	child_info::sync. | ||||||
|  | 	* hookapi.cc (hook_or_detect_cygwin): Rename.  Change so that NULL 'fn' | ||||||
|  | 	argument just returns "true", indicating that program uses cygwin1.dll. | ||||||
|  | 	* spawn.cc (av::win16_exe): New element. | ||||||
|  | 	* spawn.cc (av::iscygwin): New element. | ||||||
|  | 	(av::fixup): New function. | ||||||
|  | 	(spawn_guts): Protect against SEGV.  Use fixup function to detect when | ||||||
|  | 	it is safe to wait for a spawned (as opposed to an execed) program. | ||||||
|  | 	Reflect changes in child_info::sync arguments. | ||||||
|  | 	* external.cc (cygwin_internal): Reflect function renaming to | ||||||
|  | 	hook_or_detect_cygwin. | ||||||
|  |  | ||||||
|  | 	* cygheap.cc (cygheap_fixup_in_child): Close handle after debug fixup | ||||||
|  | 	has been done to prevent false positives in handle collision. | ||||||
|  |  | ||||||
|  | 	* exceptions.cc (try_to_debug): Notify debugger if already being | ||||||
|  | 	debugged. | ||||||
|  |  | ||||||
| 2005-07-09  Christopher Faylor  <cgf@timesys.com> | 2005-07-09  Christopher Faylor  <cgf@timesys.com> | ||||||
|  |  | ||||||
| 	* path.cc (mount): Only check win32_path when we know we need it. | 	* path.cc (mount): Only check win32_path when we know we need it. | ||||||
| @@ -47,6 +76,7 @@ | |||||||
| 	(handler_dev_raw::close): Ditto. | 	(handler_dev_raw::close): Ditto. | ||||||
| 	(fhandler_dev_clipboard::fixup_after_exec): New method. | 	(fhandler_dev_clipboard::fixup_after_exec): New method. | ||||||
| 	* fhandler_dev_mem.cc (fhandler_dev_mem::close): Eliminate pass through | 	* fhandler_dev_mem.cc (fhandler_dev_mem::close): Eliminate pass through | ||||||
|  | 	function in favor of virtual method. | ||||||
| 	* fhandler_dev_raw.cc (fhandler_dev_raw::close): Ditto. | 	* fhandler_dev_raw.cc (fhandler_dev_raw::close): Ditto. | ||||||
| 	* fhandler_clipboard.cc (fhandler_dev_clipboard::close): Don't go to | 	* fhandler_clipboard.cc (fhandler_dev_clipboard::close): Don't go to | ||||||
| 	extra effort when execing. | 	extra effort when execing. | ||||||
| @@ -55,8 +85,8 @@ | |||||||
| 	when we know we're execing. | 	when we know we're execing. | ||||||
| 	* fhandler_disk_file.cc (fhandler_disk_file::close): Ditto. | 	* fhandler_disk_file.cc (fhandler_disk_file::close): Ditto. | ||||||
| 	* fhandler_dsp.cc (fhandler_dev_dsp::close): Ditto. | 	* fhandler_dsp.cc (fhandler_dev_dsp::close): Ditto. | ||||||
| 	* fhandler_fifo.cc (fhandler_fifo.cc::close): Ditto. | 	* fhandler_fifo.cc (fhandler_fifo.cc::close): Ditto.  function in favor | ||||||
| 	function in favor of base function. | 	of base function. | ||||||
| 	* fhandler_random.cc (fhandler_dev_random::close): Ditto. | 	* fhandler_random.cc (fhandler_dev_random::close): Ditto. | ||||||
| 	* fhandler_registry.cc (fhandler_registry::close): Ditto. | 	* fhandler_registry.cc (fhandler_registry::close): Ditto. | ||||||
| 	* fhandler_tty.cc (fhandler_tty_slave::close): Ditto. | 	* fhandler_tty.cc (fhandler_tty_slave::close): Ditto. | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ enum child_info_types | |||||||
|  |  | ||||||
| #define EXEC_MAGIC_SIZE sizeof(child_info) | #define EXEC_MAGIC_SIZE sizeof(child_info) | ||||||
|  |  | ||||||
| #define CURR_CHILD_INFO_MAGIC 0xd94c588aU | #define CURR_CHILD_INFO_MAGIC 0x5eecb012U | ||||||
|  |  | ||||||
| /* NOTE: Do not make gratuitous changes to the names or organization of the | /* NOTE: Do not make gratuitous changes to the names or organization of the | ||||||
|    below class.  The layout is checksummed to determine compatibility between |    below class.  The layout is checksummed to determine compatibility between | ||||||
| @@ -50,10 +50,10 @@ public: | |||||||
|   DWORD cygheap_reserve_sz; |   DWORD cygheap_reserve_sz; | ||||||
|   DWORD dwProcessId; |   DWORD dwProcessId; | ||||||
|   unsigned fhandler_union_cb; |   unsigned fhandler_union_cb; | ||||||
|   child_info (unsigned, child_info_types); |   child_info (unsigned, child_info_types, bool); | ||||||
|   ~child_info (); |   ~child_info (); | ||||||
|   void ready (bool); |   void ready (bool); | ||||||
|   bool sync (pinfo&, DWORD); |   bool sync (int, HANDLE, DWORD) __attribute__ ((regparm (3))); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class mount_info; | class mount_info; | ||||||
| @@ -104,7 +104,7 @@ public: | |||||||
| 	cfree (moreinfo); | 	cfree (moreinfo); | ||||||
|       } |       } | ||||||
|   } |   } | ||||||
|   child_info_spawn (child_info_types); |   child_info_spawn (child_info_types, bool); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| void __stdcall init_child_info (DWORD, child_info *, HANDLE); | void __stdcall init_child_info (DWORD, child_info *, HANDLE); | ||||||
|   | |||||||
| @@ -60,13 +60,16 @@ cygheap_fixup_in_child (bool execed) | |||||||
|   cygheap = (init_cygheap *) cygheap_max; |   cygheap = (init_cygheap *) cygheap_max; | ||||||
|   _csbrk ((char *) child_proc_info->cygheap_max - (char *) cygheap); |   _csbrk ((char *) child_proc_info->cygheap_max - (char *) cygheap); | ||||||
|   child_copy (child_proc_info->parent, child_proc_info->dwProcessId, "cygheap", cygheap, cygheap_max); |   child_copy (child_proc_info->parent, child_proc_info->dwProcessId, "cygheap", cygheap, cygheap_max); | ||||||
|  |   cygheap_init (); | ||||||
|  |   debug_fixup_after_fork_exec (); | ||||||
|  |  | ||||||
|  |   /* Need to do this after debug_fixup_after_fork_exec or DEBUGGING handling of | ||||||
|  |      handles might get confused. */ | ||||||
|   if (execed) |   if (execed) | ||||||
|     { |     { | ||||||
|       CloseHandle (child_proc_info->parent); |       CloseHandle (child_proc_info->parent); | ||||||
|       child_proc_info->parent = NULL; |       child_proc_info->parent = NULL; | ||||||
|     } |     } | ||||||
|   cygheap_init (); |  | ||||||
|   debug_fixup_after_fork_exec (); |  | ||||||
|  |  | ||||||
|   if (execed) |   if (execed) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -320,8 +320,13 @@ extern "C" int | |||||||
| try_to_debug (bool waitloop) | try_to_debug (bool waitloop) | ||||||
| { | { | ||||||
|   debug_printf ("debugger_command '%s'", debugger_command); |   debug_printf ("debugger_command '%s'", debugger_command); | ||||||
|   if (*debugger_command == '\0' || being_debugged ()) |   if (*debugger_command == '\0') | ||||||
|     return 0; |     return 0; | ||||||
|  |   if (being_debugged ()) | ||||||
|  |     { | ||||||
|  |       DebugBreak (); | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|   __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ()); |   __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ()); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,7 +29,6 @@ details. */ | |||||||
| #include "cygtls.h" | #include "cygtls.h" | ||||||
| #include "child_info.h" | #include "child_info.h" | ||||||
|  |  | ||||||
| void *hook_cygwin (const char *, const void *); |  | ||||||
| child_info *get_cygwin_startup_info (); | child_info *get_cygwin_startup_info (); | ||||||
|  |  | ||||||
| static winpids pids; | static winpids pids; | ||||||
| @@ -295,7 +294,7 @@ cygwin_internal (cygwin_getinfo_types t, ...) | |||||||
| 	{ | 	{ | ||||||
| 	  const char *name = va_arg (arg, const char *); | 	  const char *name = va_arg (arg, const char *); | ||||||
| 	  const void *hookfn = va_arg (arg, const void *); | 	  const void *hookfn = va_arg (arg, const void *); | ||||||
| 	  return (unsigned long) hook_cygwin (name, hookfn); | 	  return (unsigned long) hook_or_detect_cygwin (name, hookfn); | ||||||
| 	} | 	} | ||||||
|       case CW_ARGV: |       case CW_ARGV: | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -414,7 +414,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   /* Wait for subproc to initialize itself. */ |   /* Wait for subproc to initialize itself. */ | ||||||
|   if (!ch.sync (child, FORK_WAIT_TIMEOUT)) |   if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) | ||||||
|     { |     { | ||||||
|       system_printf ("child %d died waiting for longjmp before initialization", child_pid); |       system_printf ("child %d died waiting for longjmp before initialization", child_pid); | ||||||
|       goto cleanup; |       goto cleanup; | ||||||
| @@ -465,7 +465,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ | |||||||
|   /* Start thread, and wait for it to reload dlls.  */ |   /* Start thread, and wait for it to reload dlls.  */ | ||||||
|   if (!resume_child (forker_finished)) |   if (!resume_child (forker_finished)) | ||||||
|     goto cleanup; |     goto cleanup; | ||||||
|   else if (!ch.sync (child, FORK_WAIT_TIMEOUT)) |   else if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) | ||||||
|     { |     { | ||||||
|       system_printf ("child %d died waiting for dll loading", child_pid); |       system_printf ("child %d died waiting for dll loading", child_pid); | ||||||
|       goto cleanup; |       goto cleanup; | ||||||
|   | |||||||
| @@ -150,7 +150,7 @@ makename (const char *name, char *&buf, int& i, int inc) | |||||||
|  |  | ||||||
| // Top level routine to find the EXE's imports, and redirect them | // Top level routine to find the EXE's imports, and redirect them | ||||||
| void * | void * | ||||||
| hook_cygwin (const char *name, const void *fn) | hook_or_detect_cygwin (const char *name, const void *fn) | ||||||
| { | { | ||||||
|   HMODULE hm = GetModuleHandle (NULL); |   HMODULE hm = GetModuleHandle (NULL); | ||||||
|   PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm); |   PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm); | ||||||
| @@ -170,16 +170,19 @@ hook_cygwin (const char *name, const void *fn) | |||||||
|   fh.origfn = NULL; |   fh.origfn = NULL; | ||||||
|   fh.hookfn = fn; |   fh.hookfn = fn; | ||||||
|   char *buf = (char *) alloca (strlen (name) + strlen ("64") + sizeof ("_")); |   char *buf = (char *) alloca (strlen (name) + strlen ("64") + sizeof ("_")); | ||||||
|   int i = -1; |   int i; | ||||||
|   while (!fh.origfn && (fh.name = makename (name, buf, i, 1))) |  | ||||||
|     { |  | ||||||
|   // Iterate through each import descriptor, and redirect if appropriate |   // Iterate through each import descriptor, and redirect if appropriate | ||||||
|   for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++) |   for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++) | ||||||
|     { |     { | ||||||
| 	  PSTR modname = rva (PSTR, hm, pd->Name); |       if (!strcasematch (rva (PSTR, hm, pd->Name), "cygwin1.dll")) | ||||||
| 	  if (strcasematch (modname, "cygwin1.dll")) | 	continue; | ||||||
|  |       if (!fn) | ||||||
|  | 	return (void *) "found it";	// just checking if executable used cygwin1.dll | ||||||
|  |       i = -1; | ||||||
|  |       while (!fh.origfn && (fh.name = makename (name, buf, i, 1))) | ||||||
| 	RedirectIAT (fh, pd, hm); | 	RedirectIAT (fh, pd, hm); | ||||||
| 	} |       if (fh.origfn) | ||||||
|  | 	break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   while (!fh.origfn && (fh.name = makename (name, buf, i, -1))) |   while (!fh.origfn && (fh.name = makename (name, buf, i, -1))) | ||||||
|   | |||||||
| @@ -721,7 +721,7 @@ out: | |||||||
| /* Initialize some of the memory block passed to child processes | /* Initialize some of the memory block passed to child processes | ||||||
|    by fork/spawn/exec. */ |    by fork/spawn/exec. */ | ||||||
|  |  | ||||||
| child_info::child_info (unsigned in_cb, child_info_types chtype) | child_info::child_info (unsigned in_cb, child_info_types chtype, bool need_subproc_ready) | ||||||
| { | { | ||||||
|   memset (this, 0, in_cb); |   memset (this, 0, in_cb); | ||||||
|   cb = in_cb; |   cb = in_cb; | ||||||
| @@ -730,7 +730,7 @@ child_info::child_info (unsigned in_cb, child_info_types chtype) | |||||||
|   type = chtype; |   type = chtype; | ||||||
|   fhandler_union_cb = sizeof (fhandler_union); |   fhandler_union_cb = sizeof (fhandler_union); | ||||||
|   user_h = cygwin_user_h; |   user_h = cygwin_user_h; | ||||||
|   if (chtype != PROC_SPAWN) |   if (need_subproc_ready) | ||||||
|     subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL); |     subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL); | ||||||
|   sigproc_printf ("subproc_ready %p", subproc_ready); |   sigproc_printf ("subproc_ready %p", subproc_ready); | ||||||
|   cygheap = ::cygheap; |   cygheap = ::cygheap; | ||||||
| @@ -753,12 +753,12 @@ child_info::~child_info () | |||||||
| } | } | ||||||
|  |  | ||||||
| child_info_fork::child_info_fork () : | child_info_fork::child_info_fork () : | ||||||
|   child_info (sizeof *this, _PROC_FORK) |   child_info (sizeof *this, _PROC_FORK, true) | ||||||
| { | { | ||||||
| } | } | ||||||
|  |  | ||||||
| child_info_spawn::child_info_spawn (child_info_types chtype) : | child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_ready) : | ||||||
|   child_info (sizeof *this, chtype) |   child_info (sizeof *this, chtype, need_subproc_ready) | ||||||
| { | { | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -786,7 +786,7 @@ child_info::ready (bool execed) | |||||||
| } | } | ||||||
|  |  | ||||||
| bool | bool | ||||||
| child_info::sync (pinfo& vchild, DWORD howlong) | child_info::sync (pid_t pid, HANDLE hProcess, DWORD howlong) | ||||||
| { | { | ||||||
|   if (!subproc_ready) |   if (!subproc_ready) | ||||||
|     { |     { | ||||||
| @@ -796,14 +796,14 @@ child_info::sync (pinfo& vchild, DWORD howlong) | |||||||
|  |  | ||||||
|   HANDLE w4[2]; |   HANDLE w4[2]; | ||||||
|   w4[0] = subproc_ready; |   w4[0] = subproc_ready; | ||||||
|   w4[1] = vchild.hProcess; |   w4[1] = hProcess; | ||||||
|  |  | ||||||
|   bool res; |   bool res; | ||||||
|   sigproc_printf ("waiting for subproc_ready(%p) and child process(%p)", w4[0], w4[1]); |   sigproc_printf ("waiting for subproc_ready(%p) and child process(%p)", w4[0], w4[1]); | ||||||
|   switch (WaitForMultipleObjects (2, w4, FALSE, howlong)) |   switch (WaitForMultipleObjects (2, w4, FALSE, howlong)) | ||||||
|     { |     { | ||||||
|     case WAIT_OBJECT_0: |     case WAIT_OBJECT_0: | ||||||
|       sigproc_printf ("got subproc_ready for pid %d", vchild->pid); |       sigproc_printf ("got subproc_ready for pid %d", pid); | ||||||
|       res = true; |       res = true; | ||||||
|       break; |       break; | ||||||
|     case WAIT_OBJECT_0 + 1: |     case WAIT_OBJECT_0 + 1: | ||||||
| @@ -813,7 +813,7 @@ child_info::sync (pinfo& vchild, DWORD howlong) | |||||||
|       res = false; |       res = false; | ||||||
|       break; |       break; | ||||||
|     default: |     default: | ||||||
|       system_printf ("wait failed, pid %d, %E", vchild->pid); |       system_printf ("wait failed, pid %d, %E", pid); | ||||||
|       res = false; |       res = false; | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ details. */ | |||||||
| #include "pinfo.h" | #include "pinfo.h" | ||||||
| #include "registry.h" | #include "registry.h" | ||||||
| #include "environ.h" | #include "environ.h" | ||||||
| #include "cygthread.h" | #include "cygtls.h" | ||||||
|  |  | ||||||
| #define LINE_BUF_CHUNK (CYG_MAX_PATH * 2) | #define LINE_BUF_CHUNK (CYG_MAX_PATH * 2) | ||||||
|  |  | ||||||
| @@ -264,7 +264,9 @@ class av | |||||||
|  public: |  public: | ||||||
|   int error; |   int error; | ||||||
|   int argc; |   int argc; | ||||||
|   av (int ac, const char * const *av) : calloced (0), error (false), argc (ac) |   bool win16_exe; | ||||||
|  |   bool iscygwin; | ||||||
|  |   av (int ac, const char * const *av) : calloced (0), error (false), argc (ac), win16_exe (false), iscygwin (true) | ||||||
|   { |   { | ||||||
|     argv = (char **) cmalloc (HEAP_1_ARGV, (argc + 5) * sizeof (char *)); |     argv = (char **) cmalloc (HEAP_1_ARGV, (argc + 5) * sizeof (char *)); | ||||||
|     memcpy (argv, av, (argc + 1) * sizeof (char *)); |     memcpy (argv, av, (argc + 1) * sizeof (char *)); | ||||||
| @@ -303,6 +305,7 @@ class av | |||||||
|       if (!(argv[i] = cstrdup1 (argv[i]))) |       if (!(argv[i] = cstrdup1 (argv[i]))) | ||||||
| 	error = errno; | 	error = errno; | ||||||
|   } |   } | ||||||
|  |   int fixup (child_info_types, const char *, path_conv&, const char *); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| int | int | ||||||
| @@ -360,8 +363,6 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
|   bool rc; |   bool rc; | ||||||
|   pid_t cygpid; |   pid_t cygpid; | ||||||
|  |  | ||||||
|   MALLOC_CHECK; |  | ||||||
|  |  | ||||||
|   if (prog_arg == NULL) |   if (prog_arg == NULL) | ||||||
|     { |     { | ||||||
|       syscall_printf ("prog_arg is NULL"); |       syscall_printf ("prog_arg is NULL"); | ||||||
| @@ -400,9 +401,12 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
|   for (ac = 0; argv[ac]; ac++) |   for (ac = 0; argv[ac]; ac++) | ||||||
|     /* nothing */; |     /* nothing */; | ||||||
|  |  | ||||||
|  |   myfault efault; | ||||||
|  |   if (efault.faulted (EFAULT)) | ||||||
|  |     return -1;		// FIXME: Could be very leaky | ||||||
|  |  | ||||||
|   av newargv (ac, argv); |   av newargv (ac, argv); | ||||||
|  |  | ||||||
|   bool win16_exe = false; |  | ||||||
|   int null_app_name = 0; |   int null_app_name = 0; | ||||||
|   if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' && |   if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' && | ||||||
|       (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe"))) |       (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe"))) | ||||||
| @@ -431,100 +435,10 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|   MALLOC_CHECK; |   MALLOC_CHECK; | ||||||
|  |   int res; | ||||||
|   /* If the file name ends in either .exe, .com, .bat, or .cmd we assume |   res = newargv.fixup (chtype, prog_arg, real_path, ext); | ||||||
|      that it is NOT a script file */ |   if (res) | ||||||
|   while (*ext == '\0' || (wincap.detect_win16_exe () && strcasematch (ext, ".exe"))) |     return res; | ||||||
|     { |  | ||||||
|       HANDLE hnd = CreateFile (real_path, GENERIC_READ, |  | ||||||
| 			       FILE_SHARE_READ | FILE_SHARE_WRITE, |  | ||||||
| 			       &sec_none_nih, OPEN_EXISTING, |  | ||||||
| 			       FILE_ATTRIBUTE_NORMAL, 0); |  | ||||||
|       if (hnd == INVALID_HANDLE_VALUE) |  | ||||||
| 	{ |  | ||||||
| 	  __seterrno (); |  | ||||||
| 	  return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|       DWORD done; |  | ||||||
|  |  | ||||||
|       char buf[2 * CYG_MAX_PATH]; |  | ||||||
|       buf[0] = buf[1] = buf[2] = buf[sizeof (buf) - 1] = '\0'; |  | ||||||
|       if (!ReadFile (hnd, buf, sizeof (buf) - 1, &done, 0)) |  | ||||||
| 	{ |  | ||||||
| 	  CloseHandle (hnd); |  | ||||||
| 	  __seterrno (); |  | ||||||
| 	  return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|       CloseHandle (hnd); |  | ||||||
|  |  | ||||||
|       if (buf[0] == 'M' && buf[1] == 'Z') |  | ||||||
| 	{ |  | ||||||
| 	  unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8); |  | ||||||
| 	  win16_exe = off < sizeof (IMAGE_DOS_HEADER); |  | ||||||
| 	  break; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|       debug_printf ("%s is a script", (char *) real_path); |  | ||||||
|  |  | ||||||
|       if (real_path.has_acls () && allow_ntsec |  | ||||||
| 	  && check_file_access (real_path, X_OK)) |  | ||||||
| 	{ |  | ||||||
| 	  debug_printf ("... but not executable"); |  | ||||||
| 	  break; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|       char *pgm, *arg1; |  | ||||||
|  |  | ||||||
|       if (buf[0] != '#' || buf[1] != '!') |  | ||||||
| 	{ |  | ||||||
| 	  pgm = (char *) "/bin/sh"; |  | ||||||
| 	  arg1 = NULL; |  | ||||||
| 	} |  | ||||||
|       else |  | ||||||
| 	{ |  | ||||||
| 	  char *ptr; |  | ||||||
| 	  pgm = buf + 2; |  | ||||||
| 	  pgm += strspn (pgm, " \t"); |  | ||||||
| 	  for (ptr = pgm, arg1 = NULL; |  | ||||||
| 	       *ptr && *ptr != '\r' && *ptr != '\n'; |  | ||||||
| 	       ptr++) |  | ||||||
| 	    if (!arg1 && (*ptr == ' ' || *ptr == '\t')) |  | ||||||
| 	      { |  | ||||||
| 		/* Null terminate the initial command and step over |  | ||||||
| 		   any additional white space.  If we've hit the |  | ||||||
| 		   end of the line, exit the loop.  Otherwise, we've |  | ||||||
| 		   found the first argument. Position the current |  | ||||||
| 		   pointer on the last known white space. */ |  | ||||||
| 		*ptr = '\0'; |  | ||||||
| 		char *newptr = ptr + 1; |  | ||||||
| 		newptr += strspn (newptr, " \t"); |  | ||||||
| 		if (!*newptr || *newptr == '\r' || *newptr == '\n') |  | ||||||
| 		  break; |  | ||||||
| 		arg1 = newptr; |  | ||||||
| 		ptr = newptr - 1; |  | ||||||
| 	      } |  | ||||||
|  |  | ||||||
| 	  *ptr = '\0'; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|       /* Replace argv[0] with the full path to the script if this is the |  | ||||||
| 	 first time through the loop. */ |  | ||||||
|       newargv.replace0_maybe (prog_arg); |  | ||||||
|  |  | ||||||
|       /* pointers: |  | ||||||
|        * pgm	interpreter name |  | ||||||
|        * arg1	optional string |  | ||||||
|        */ |  | ||||||
|       if (arg1) |  | ||||||
| 	newargv.unshift (arg1); |  | ||||||
|  |  | ||||||
|       /* FIXME: This should not be using FE_NATIVE.  It should be putting |  | ||||||
| 	 the posix path on the argv list. */ |  | ||||||
|       find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext); |  | ||||||
|       newargv.unshift (real_path, 1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   if (real_path.iscygexec ()) |   if (real_path.iscygexec ()) | ||||||
|     newargv.dup_all (); |     newargv.dup_all (); | ||||||
| @@ -672,7 +586,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
|   cygheap->user.deimpersonate (); |   cygheap->user.deimpersonate (); | ||||||
|  |  | ||||||
|   moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec ()); |   moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec ()); | ||||||
|   child_info_spawn ciresrv (chtype); |   child_info_spawn ciresrv (chtype, newargv.iscygwin); | ||||||
|   ciresrv.moreinfo = moreinfo; |   ciresrv.moreinfo = moreinfo; | ||||||
|  |  | ||||||
|   si.lpReserved2 = (LPBYTE) &ciresrv; |   si.lpReserved2 = (LPBYTE) &ciresrv; | ||||||
| @@ -763,7 +677,6 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
|  |  | ||||||
|   /* FIXME: There is a small race here */ |   /* FIXME: There is a small race here */ | ||||||
|  |  | ||||||
|   int res; |  | ||||||
|   pthread_cleanup cleanup; |   pthread_cleanup cleanup; | ||||||
|   if (mode == _P_SYSTEM) |   if (mode == _P_SYSTEM) | ||||||
|     { |     { | ||||||
| @@ -794,6 +707,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
|   ProtectHandle1 (pi.hProcess, childhProc); |   ProtectHandle1 (pi.hProcess, childhProc); | ||||||
|  |  | ||||||
|   bool synced; |   bool synced; | ||||||
|  |   pid_t pid; | ||||||
|   if (mode == _P_OVERLAY) |   if (mode == _P_OVERLAY) | ||||||
|     { |     { | ||||||
|       myself->dwProcessId = dwExeced = pi.dwProcessId; |       myself->dwProcessId = dwExeced = pi.dwProcessId; | ||||||
| @@ -813,7 +727,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
| 	 on this fact when we exit.  dup_proc_pipe will close our end of the pipe. | 	 on this fact when we exit.  dup_proc_pipe will close our end of the pipe. | ||||||
| 	 Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE.  That will make | 	 Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE.  That will make | ||||||
| 	 dup_proc_pipe essentially a no-op.  */ | 	 dup_proc_pipe essentially a no-op.  */ | ||||||
|       if (!win16_exe && myself->wr_proc_pipe) |       if (!newargv.win16_exe && myself->wr_proc_pipe) | ||||||
| 	{ | 	{ | ||||||
| 	  myself->sync_proc_pipe ();	/* Make sure that we own wr_proc_pipe | 	  myself->sync_proc_pipe ();	/* Make sure that we own wr_proc_pipe | ||||||
| 					   just in case we've been previously | 					   just in case we've been previously | ||||||
| @@ -821,6 +735,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
| 	  myself.zap_cwd (); | 	  myself.zap_cwd (); | ||||||
| 	  myself->dup_proc_pipe (pi.hProcess); | 	  myself->dup_proc_pipe (pi.hProcess); | ||||||
| 	} | 	} | ||||||
|  |       pid = myself->pid; | ||||||
|     } |     } | ||||||
|   else |   else | ||||||
|     { |     { | ||||||
| @@ -856,6 +771,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
| 	  res = -1; | 	  res = -1; | ||||||
| 	  goto out; | 	  goto out; | ||||||
| 	} | 	} | ||||||
|  |       pid = child->pid; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   /* Start the child running */ |   /* Start the child running */ | ||||||
| @@ -865,7 +781,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, | |||||||
|  |  | ||||||
|   sigproc_printf ("spawned windows pid %d", pi.dwProcessId); |   sigproc_printf ("spawned windows pid %d", pi.dwProcessId); | ||||||
|  |  | ||||||
|   synced = ciresrv.sync (myself, INFINITE); |   synced = ciresrv.sync (pid, pi.hProcess, INFINITE); | ||||||
|  |  | ||||||
|   switch (mode) |   switch (mode) | ||||||
|     { |     { | ||||||
| @@ -1075,3 +991,104 @@ spawnvpe (int mode, const char *file, const char * const *argv, | |||||||
|   path_conv buf; |   path_conv buf; | ||||||
|   return spawnve (mode, find_exec (file, buf), argv, envp); |   return spawnve (mode, find_exec (file, buf), argv, envp); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | av::fixup (child_info_types chtype, const char *prog_arg, path_conv& real_path, const char *ext) | ||||||
|  | { | ||||||
|  |   /* If the file name ends in either .exe, .com, .bat, or .cmd we assume | ||||||
|  |      that it is NOT a script file */ | ||||||
|  |   while (*ext == '\0' || chtype == PROC_SPAWN || (wincap.detect_win16_exe () && strcasematch (ext, ".exe"))) | ||||||
|  |     { | ||||||
|  |       HANDLE h = CreateFile (real_path, GENERIC_READ, | ||||||
|  | 			       FILE_SHARE_READ | FILE_SHARE_WRITE, | ||||||
|  | 			       &sec_none_nih, OPEN_EXISTING, | ||||||
|  | 			       FILE_ATTRIBUTE_NORMAL, 0); | ||||||
|  |       if (h == INVALID_HANDLE_VALUE) | ||||||
|  | 	goto err; | ||||||
|  |  | ||||||
|  |       HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL); | ||||||
|  |       CloseHandle (h); | ||||||
|  |       if (!hm) | ||||||
|  | 	goto err; | ||||||
|  |       char *buf = (char *) MapViewOfFile(hm, FILE_MAP_READ, 0, 0, 0); | ||||||
|  |       CloseHandle (hm); | ||||||
|  |       if (!buf) | ||||||
|  | 	goto err; | ||||||
|  |  | ||||||
|  |       if (buf[0] == 'M' && buf[1] == 'Z') | ||||||
|  | 	{ | ||||||
|  | 	  unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8); | ||||||
|  | 	  win16_exe = off < sizeof (IMAGE_DOS_HEADER); | ||||||
|  | 	  if (!win16_exe) | ||||||
|  | 	    iscygwin = hook_or_detect_cygwin (buf, NULL); | ||||||
|  | 	  UnmapViewOfFile (buf); | ||||||
|  | 	  break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |       debug_printf ("%s is a script", (char *) real_path); | ||||||
|  |  | ||||||
|  |       if (real_path.has_acls () && allow_ntsec | ||||||
|  | 	  && check_file_access (real_path, X_OK)) | ||||||
|  | 	{ | ||||||
|  | 	  debug_printf ("... but not executable"); | ||||||
|  | 	  break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |       char *pgm = NULL; | ||||||
|  |       char *arg1 = NULL; | ||||||
|  |       char *ptr = buf; | ||||||
|  |       if (*ptr++ == '#' && *ptr++ == '!') | ||||||
|  | 	{ | ||||||
|  | 	  ptr += strspn (ptr, " \t"); | ||||||
|  | 	  size_t len = strcspn (ptr, "\r\n"); | ||||||
|  | 	  if (len) | ||||||
|  | 	    { | ||||||
|  | 	      char *namebuf = (char *) alloca (len + 1); | ||||||
|  | 	      memcpy (namebuf, ptr, len); | ||||||
|  | 	      namebuf[len] = '\0'; | ||||||
|  | 	      for (ptr = pgm = namebuf; *ptr; ptr++) | ||||||
|  | 		if (!arg1 && (*ptr == ' ' || *ptr == '\t')) | ||||||
|  | 		  { | ||||||
|  | 		    /* Null terminate the initial command and step over any additional white | ||||||
|  | 		       space.  If we've hit the end of the line, exit the loop.  Otherwise, | ||||||
|  | 		       we've found the first argument. Position the current pointer on the | ||||||
|  | 		       last known white space. */ | ||||||
|  | 		    *ptr = '\0'; | ||||||
|  | 		    char *newptr = ptr + 1; | ||||||
|  | 		    newptr += strspn (newptr, " \t"); | ||||||
|  | 		    if (!*newptr) | ||||||
|  | 		      break; | ||||||
|  | 		    arg1 = newptr; | ||||||
|  | 		    ptr = newptr - 1; | ||||||
|  | 		  } | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  |       UnmapViewOfFile (buf); | ||||||
|  |       if (!pgm) | ||||||
|  | 	{ | ||||||
|  | 	  pgm = (char *) "/bin/sh"; | ||||||
|  | 	  arg1 = NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |       /* Replace argv[0] with the full path to the script if this is the | ||||||
|  | 	 first time through the loop. */ | ||||||
|  |       replace0_maybe (prog_arg); | ||||||
|  |  | ||||||
|  |       /* pointers: | ||||||
|  |        * pgm	interpreter name | ||||||
|  |        * arg1	optional string | ||||||
|  |        */ | ||||||
|  |       if (arg1) | ||||||
|  | 	unshift (arg1); | ||||||
|  |  | ||||||
|  |       /* FIXME: This should not be using FE_NATIVE.  It should be putting | ||||||
|  | 	 the posix path on the argv list. */ | ||||||
|  |       find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext); | ||||||
|  |       unshift (real_path, 1); | ||||||
|  |     } | ||||||
|  |   return 0; | ||||||
|  |  | ||||||
|  | err: | ||||||
|  |   __seterrno (); | ||||||
|  |   return -1; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -255,6 +255,8 @@ extern "C" int __stdcall strcasematch (const char *s1, const char *s2) __attribu | |||||||
| extern "C" int __stdcall strncasematch (const char *s1, const char *s2, size_t n) __attribute__ ((regparm(3))); | extern "C" int __stdcall strncasematch (const char *s1, const char *s2, size_t n) __attribute__ ((regparm(3))); | ||||||
| extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor) __attribute__ ((regparm(2))); | extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor) __attribute__ ((regparm(2))); | ||||||
|  |  | ||||||
|  | void *hook_or_detect_cygwin (const char *, const void *) __attribute__ ((regparm (2))); | ||||||
|  |  | ||||||
| /* Time related */ | /* Time related */ | ||||||
| void __stdcall totimeval (struct timeval *, FILETIME *, int, int); | void __stdcall totimeval (struct timeval *, FILETIME *, int, int); | ||||||
| long __stdcall to_time_t (FILETIME *); | long __stdcall to_time_t (FILETIME *); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user