* 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:
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user