OSDN Git Service

* child_info.h (child_info::sync): Pass pid and HANDLE rather than using pinfo.
authorcgf <cgf>
Sun, 17 Jul 2005 00:51:02 +0000 (00:51 +0000)
committercgf <cgf>
Sun, 17 Jul 2005 00:51:02 +0000 (00:51 +0000)
(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.

winsup/cygwin/ChangeLog
winsup/cygwin/child_info.h
winsup/cygwin/cygheap.cc
winsup/cygwin/exceptions.cc
winsup/cygwin/external.cc
winsup/cygwin/fork.cc
winsup/cygwin/hookapi.cc
winsup/cygwin/sigproc.cc
winsup/cygwin/spawn.cc
winsup/cygwin/winsup.h

index edcad89..b0f0635 100644 (file)
@@ -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>
 
        * path.cc (mount): Only check win32_path when we know we need it.
@@ -47,6 +76,7 @@
        (handler_dev_raw::close): Ditto.
        (fhandler_dev_clipboard::fixup_after_exec): New method.
        * 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_clipboard.cc (fhandler_dev_clipboard::close): Don't go to
        extra effort when execing.
@@ -55,8 +85,8 @@
        when we know we're execing.
        * fhandler_disk_file.cc (fhandler_disk_file::close): Ditto.
        * fhandler_dsp.cc (fhandler_dev_dsp::close): Ditto.
-       * fhandler_fifo.cc (fhandler_fifo.cc::close): Ditto.
-       function in favor of base function.
+       * fhandler_fifo.cc (fhandler_fifo.cc::close): Ditto.  function in favor
+       of base function.
        * fhandler_random.cc (fhandler_dev_random::close): Ditto.
        * fhandler_registry.cc (fhandler_registry::close): Ditto.
        * fhandler_tty.cc (fhandler_tty_slave::close): Ditto.
index 5e2bc05..c079fe2 100644 (file)
@@ -29,7 +29,7 @@ enum child_info_types
 
 #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
    below class.  The layout is checksummed to determine compatibility between
@@ -50,10 +50,10 @@ public:
   DWORD cygheap_reserve_sz;
   DWORD dwProcessId;
   unsigned fhandler_union_cb;
-  child_info (unsigned, child_info_types);
+  child_info (unsigned, child_info_types, bool);
   ~child_info ();
   void ready (bool);
-  bool sync (pinfo&, DWORD);
+  bool sync (int, HANDLE, DWORD) __attribute__ ((regparm (3)));
 };
 
 class mount_info;
@@ -104,7 +104,7 @@ public:
        cfree (moreinfo);
       }
   }
-  child_info_spawn (child_info_types);
+  child_info_spawn (child_info_types, bool);
 };
 
 void __stdcall init_child_info (DWORD, child_info *, HANDLE);
index 633df7f..9f2f7d4 100644 (file)
@@ -51,7 +51,7 @@ extern "C" {
 static void __stdcall _cfree (void *) __attribute__((regparm(1)));
 static void *__stdcall _csbrk (int);
 }
-
 /* Called by fork or spawn to reallocate cygwin heap */
 void __stdcall
 cygheap_fixup_in_child (bool execed)
@@ -60,13 +60,16 @@ cygheap_fixup_in_child (bool execed)
   cygheap = (init_cygheap *) cygheap_max;
   _csbrk ((char *) child_proc_info->cygheap_max - (char *) cygheap);
   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)
     {
       CloseHandle (child_proc_info->parent);
       child_proc_info->parent = NULL;
     }
-  cygheap_init ();
-  debug_fixup_after_fork_exec ();
 
   if (execed)
     {
index 4f9a55e..1d3d8de 100644 (file)
@@ -320,8 +320,13 @@ extern "C" int
 try_to_debug (bool waitloop)
 {
   debug_printf ("debugger_command '%s'", debugger_command);
-  if (*debugger_command == '\0' || being_debugged ())
+  if (*debugger_command == '\0')
     return 0;
+  if (being_debugged ())
+    {
+      DebugBreak ();
+      return 0;
+    }
 
   __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());
 
index a40ef1e..5e81536 100644 (file)
@@ -29,7 +29,6 @@ details. */
 #include "cygtls.h"
 #include "child_info.h"
 
-void *hook_cygwin (const char *, const void *);
 child_info *get_cygwin_startup_info ();
 
 static winpids pids;
@@ -295,7 +294,7 @@ cygwin_internal (cygwin_getinfo_types t, ...)
        {
          const char *name = va_arg (arg, const char *);
          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:
        {
index e3b6066..649baa3 100644 (file)
@@ -414,7 +414,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
 #endif
 
   /* 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);
       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.  */
   if (!resume_child (forker_finished))
     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);
       goto cleanup;
index 6542a6e..97e3330 100644 (file)
@@ -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
 void *
-hook_cygwin (const char *name, const void *fn)
+hook_or_detect_cygwin (const char *name, const void *fn)
 {
   HMODULE hm = GetModuleHandle (NULL);
   PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
@@ -170,16 +170,19 @@ hook_cygwin (const char *name, const void *fn)
   fh.origfn = NULL;
   fh.hookfn = fn;
   char *buf = (char *) alloca (strlen (name) + strlen ("64") + sizeof ("_"));
-  int i = -1;
-  while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
+  int i;
+  // Iterate through each import descriptor, and redirect if appropriate
+  for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
     {
-      // Iterate through each import descriptor, and redirect if appropriate
-      for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
-       {
-         PSTR modname = rva (PSTR, hm, pd->Name);
-         if (strcasematch (modname, "cygwin1.dll"))
-           RedirectIAT (fh, pd, hm);
-       }
+      if (!strcasematch (rva (PSTR, hm, pd->Name), "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);
+      if (fh.origfn)
+       break;
     }
 
   while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))
index d85064b..2bb9d4e 100644 (file)
@@ -721,7 +721,7 @@ out:
 /* Initialize some of the memory block passed to child processes
    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);
   cb = in_cb;
@@ -730,7 +730,7 @@ child_info::child_info (unsigned in_cb, child_info_types chtype)
   type = chtype;
   fhandler_union_cb = sizeof (fhandler_union);
   user_h = cygwin_user_h;
-  if (chtype != PROC_SPAWN)
+  if (need_subproc_ready)
     subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
   sigproc_printf ("subproc_ready %p", subproc_ready);
   cygheap = ::cygheap;
@@ -753,12 +753,12 @@ child_info::~child_info ()
 }
 
 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 (sizeof *this, chtype)
+child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_ready) :
+  child_info (sizeof *this, chtype, need_subproc_ready)
 {
 }
 
@@ -786,7 +786,7 @@ child_info::ready (bool execed)
 }
 
 bool
-child_info::sync (pinfo& vchild, DWORD howlong)
+child_info::sync (pid_t pid, HANDLE hProcess, DWORD howlong)
 {
   if (!subproc_ready)
     {
@@ -796,14 +796,14 @@ child_info::sync (pinfo& vchild, DWORD howlong)
 
   HANDLE w4[2];
   w4[0] = subproc_ready;
-  w4[1] = vchild.hProcess;
+  w4[1] = hProcess;
 
   bool res;
   sigproc_printf ("waiting for subproc_ready(%p) and child process(%p)", w4[0], w4[1]);
   switch (WaitForMultipleObjects (2, w4, FALSE, howlong))
     {
     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;
       break;
     case WAIT_OBJECT_0 + 1:
@@ -813,7 +813,7 @@ child_info::sync (pinfo& vchild, DWORD howlong)
       res = false;
       break;
     default:
-      system_printf ("wait failed, pid %d, %E", vchild->pid);
+      system_printf ("wait failed, pid %d, %E", pid);
       res = false;
       break;
     }
index cf6d3e4..8261a45 100644 (file)
@@ -32,7 +32,7 @@ details. */
 #include "pinfo.h"
 #include "registry.h"
 #include "environ.h"
-#include "cygthread.h"
+#include "cygtls.h"
 
 #define LINE_BUF_CHUNK (CYG_MAX_PATH * 2)
 
@@ -264,7 +264,9 @@ class av
  public:
   int error;
   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 *));
     memcpy (argv, av, (argc + 1) * sizeof (char *));
@@ -303,6 +305,7 @@ class av
       if (!(argv[i] = cstrdup1 (argv[i])))
        error = errno;
   }
+  int fixup (child_info_types, const char *, path_conv&, const char *);
 };
 
 int
@@ -360,8 +363,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
   bool rc;
   pid_t cygpid;
 
-  MALLOC_CHECK;
-
   if (prog_arg == 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++)
     /* nothing */;
 
+  myfault efault;
+  if (efault.faulted (EFAULT))
+    return -1;         // FIXME: Could be very leaky
+
   av newargv (ac, argv);
 
-  bool win16_exe = false;
   int null_app_name = 0;
   if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' &&
       (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;
-
-  /* If the file name ends in either .exe, .com, .bat, or .cmd we assume
-     that it is NOT a script file */
-  while (*ext == '\0' || (wincap.detect_win16_exe () && strcasematch (ext, ".exe")))
-    {
-      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);
-    }
+  int res;
+  res = newargv.fixup (chtype, prog_arg, real_path, ext);
+  if (res)
+    return res;
 
   if (real_path.iscygexec ())
     newargv.dup_all ();
@@ -672,7 +586,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
   cygheap->user.deimpersonate ();
 
   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;
 
   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 */
 
-  int res;
   pthread_cleanup cleanup;
   if (mode == _P_SYSTEM)
     {
@@ -794,6 +707,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
   ProtectHandle1 (pi.hProcess, childhProc);
 
   bool synced;
+  pid_t pid;
   if (mode == _P_OVERLAY)
     {
       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.
         Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE.  That will make
         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
                                           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->dup_proc_pipe (pi.hProcess);
        }
+      pid = myself->pid;
     }
   else
     {
@@ -856,6 +771,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
          res = -1;
          goto out;
        }
+      pid = child->pid;
     }
 
   /* 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);
 
-  synced = ciresrv.sync (myself, INFINITE);
+  synced = ciresrv.sync (pid, pi.hProcess, INFINITE);
 
   switch (mode)
     {
@@ -1075,3 +991,104 @@ spawnvpe (int mode, const char *file, const char * const *argv,
   path_conv buf;
   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;
+}
index 2178d27..3c28968 100644 (file)
@@ -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" 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 */
 void __stdcall totimeval (struct timeval *, FILETIME *, int, int);
 long __stdcall to_time_t (FILETIME *);