* 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:
parent
cd929277d6
commit
e8454a3400
@ -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
|
||||||
|
for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
|
||||||
{
|
{
|
||||||
// Iterate through each import descriptor, and redirect if appropriate
|
if (!strcasematch (rva (PSTR, hm, pd->Name), "cygwin1.dll"))
|
||||||
for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
|
continue;
|
||||||
{
|
if (!fn)
|
||||||
PSTR modname = rva (PSTR, hm, pd->Name);
|
return (void *) "found it"; // just checking if executable used cygwin1.dll
|
||||||
if (strcasematch (modname, "cygwin1.dll"))
|
i = -1;
|
||||||
RedirectIAT (fh, pd, hm);
|
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)))
|
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 *);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user