aboutsummaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2005-07-17 00:51:03 +0000
committerChristopher Faylor <me@cgf.cx>2005-07-17 00:51:03 +0000
commite8454a340033a287a9245e049a6f23eb68ec7f95 (patch)
treee235728e012c817a8bc813232961e972d49f4ac1 /winsup
parentcd929277d69996a60f29d17bb4d612063926a5f7 (diff)
downloadnewlib-e8454a340033a287a9245e049a6f23eb68ec7f95.zip
newlib-e8454a340033a287a9245e049a6f23eb68ec7f95.tar.gz
newlib-e8454a340033a287a9245e049a6f23eb68ec7f95.tar.bz2
* 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.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog34
-rw-r--r--winsup/cygwin/child_info.h8
-rw-r--r--winsup/cygwin/cygheap.cc9
-rw-r--r--winsup/cygwin/exceptions.cc7
-rw-r--r--winsup/cygwin/external.cc3
-rw-r--r--winsup/cygwin/fork.cc4
-rw-r--r--winsup/cygwin/hookapi.cc23
-rw-r--r--winsup/cygwin/sigproc.cc18
-rw-r--r--winsup/cygwin/spawn.cc223
-rw-r--r--winsup/cygwin/winsup.h2
10 files changed, 195 insertions, 136 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index edcad89..b0f0635 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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.
diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h
index 5e2bc05..c079fe2 100644
--- a/winsup/cygwin/child_info.h
+++ b/winsup/cygwin/child_info.h
@@ -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);
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index 633df7f..9f2f7d4 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -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)
{
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 4f9a55e..1d3d8de 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -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 ());
diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc
index a40ef1e..5e81536 100644
--- a/winsup/cygwin/external.cc
+++ b/winsup/cygwin/external.cc
@@ -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:
{
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index e3b6066..649baa3 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -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;
diff --git a/winsup/cygwin/hookapi.cc b/winsup/cygwin/hookapi.cc
index 6542a6e..97e3330 100644
--- a/winsup/cygwin/hookapi.cc
+++ b/winsup/cygwin/hookapi.cc
@@ -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)))
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index d85064b..2bb9d4e 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -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;
}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index cf6d3e4..8261a45 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -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;
+}
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 2178d27..3c28968 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -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 *);