* 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>
|
||||
|
||||
* 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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 ());
|
||||
|
||||
|
|
|
@ -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:
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 *);
|
||||
|
|
Loading…
Reference in New Issue