mirror of git://gcc.gnu.org/git/gcc.git
pex-win32.c (<errno.h>): Include.
* pex-win32.c (<errno.h>): Include. (fix_argv): Remove. (argv_to_cmdline): New function. (std_suffixes): New variable. (no_suffixes): Likewise. (find_executable): New function. (win32_spawn): Likewise. (spawn_script): Use win32_spawn instead of _spawnv[p]. (pex_win32_exec_child): Replace MSVCRT calls with Win32 API calls. (pex_win32_wait): Likewise. From-SVN: r112592
This commit is contained in:
parent
16659fcf33
commit
bd9e7c5cd5
|
@ -1,3 +1,16 @@
|
||||||
|
2006-03-31 Mark Mitchell <mark@codesourcery.com>
|
||||||
|
|
||||||
|
* pex-win32.c (<errno.h>): Include.
|
||||||
|
(fix_argv): Remove.
|
||||||
|
(argv_to_cmdline): New function.
|
||||||
|
(std_suffixes): New variable.
|
||||||
|
(no_suffixes): Likewise.
|
||||||
|
(find_executable): New function.
|
||||||
|
(win32_spawn): Likewise.
|
||||||
|
(spawn_script): Use win32_spawn instead of _spawnv[p].
|
||||||
|
(pex_win32_exec_child): Replace MSVCRT calls with Win32 API calls.
|
||||||
|
(pex_win32_wait): Likewise.
|
||||||
|
|
||||||
2006-03-24 Jim Blandy <jimb@codesourcery.com>
|
2006-03-24 Jim Blandy <jimb@codesourcery.com>
|
||||||
|
|
||||||
* pex-common.c (pex_run): Simplify output name handling.
|
* pex-common.c (pex_run): Simplify output name handling.
|
||||||
|
|
|
@ -41,6 +41,7 @@ Boston, MA 02110-1301, USA. */
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
/* mingw32 headers may not define the following. */
|
/* mingw32 headers may not define the following. */
|
||||||
|
|
||||||
|
@ -72,115 +73,6 @@ backslashify (char *s)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a kludge to get around the Microsoft C spawn functions' propensity
|
|
||||||
to remove the outermost set of double quotes from all arguments. */
|
|
||||||
|
|
||||||
static const char * const *
|
|
||||||
fix_argv (char * const *argvec)
|
|
||||||
{
|
|
||||||
char **argv;
|
|
||||||
int i;
|
|
||||||
char *command0;
|
|
||||||
|
|
||||||
/* See whether we need to change anything. */
|
|
||||||
for (command0 = argvec[0]; *command0 != '\0'; command0++)
|
|
||||||
if (*command0 == '/')
|
|
||||||
break;
|
|
||||||
if (*command0 == '\0')
|
|
||||||
{
|
|
||||||
for (i = 1; argvec[i] != NULL; i++)
|
|
||||||
if (strpbrk (argvec[i], "\" \t") != NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (argvec[i] == NULL)
|
|
||||||
return (const char * const *) argvec;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; argvec[i] != NULL; i++)
|
|
||||||
;
|
|
||||||
argv = XNEWVEC (char *, i + 2);
|
|
||||||
|
|
||||||
argv++; /* Leave space at the beginning of argv
|
|
||||||
for potential #! handling */
|
|
||||||
|
|
||||||
for (i = 0; argvec[i] != NULL; i++)
|
|
||||||
argv[i] = xstrdup (argvec[i]);
|
|
||||||
argv[i] = NULL;
|
|
||||||
|
|
||||||
backslashify (argv[0]);
|
|
||||||
|
|
||||||
for (i = 1; argv[i] != 0; i++)
|
|
||||||
{
|
|
||||||
int len, j;
|
|
||||||
char *temp, *newtemp;
|
|
||||||
|
|
||||||
temp = argv[i];
|
|
||||||
len = strlen (temp);
|
|
||||||
for (j = 0; j < len; j++)
|
|
||||||
{
|
|
||||||
if (temp[j] == '"')
|
|
||||||
{
|
|
||||||
newtemp = XNEWVEC (char, len + 2);
|
|
||||||
strncpy (newtemp, temp, j);
|
|
||||||
newtemp [j] = '\\';
|
|
||||||
strncpy (&newtemp [j+1], &temp [j], len-j);
|
|
||||||
newtemp [len+1] = 0;
|
|
||||||
temp = newtemp;
|
|
||||||
len++;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argv[i] != temp)
|
|
||||||
{
|
|
||||||
free (argv[i]);
|
|
||||||
argv[i] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; argv[i] != 0; i++)
|
|
||||||
{
|
|
||||||
if (strpbrk (argv[i], " \t"))
|
|
||||||
{
|
|
||||||
int len, trailing_backslash;
|
|
||||||
char *temp;
|
|
||||||
|
|
||||||
len = strlen (argv[i]);
|
|
||||||
trailing_backslash = 0;
|
|
||||||
|
|
||||||
/* There is an added complication when an arg with embedded white
|
|
||||||
space ends in a backslash (such as in the case of -iprefix arg
|
|
||||||
passed to cpp). The resulting quoted strings gets misinterpreted
|
|
||||||
by the command interpreter -- it thinks that the ending quote
|
|
||||||
is escaped by the trailing backslash and things get confused.
|
|
||||||
We handle this case by escaping the trailing backslash, provided
|
|
||||||
it was not escaped in the first place. */
|
|
||||||
if (len > 1
|
|
||||||
&& argv[i][len-1] == '\\'
|
|
||||||
&& argv[i][len-2] != '\\')
|
|
||||||
{
|
|
||||||
trailing_backslash = 1;
|
|
||||||
++len; /* to escape the final backslash. */
|
|
||||||
}
|
|
||||||
|
|
||||||
len += 2; /* and for the enclosing quotes. */
|
|
||||||
|
|
||||||
temp = XNEWVEC (char, len + 1);
|
|
||||||
temp[0] = '"';
|
|
||||||
strcpy (temp + 1, argv[i]);
|
|
||||||
if (trailing_backslash)
|
|
||||||
temp[len - 2] = '\\';
|
|
||||||
temp[len - 1] = '"';
|
|
||||||
temp[len] = '\0';
|
|
||||||
|
|
||||||
free (argv[i]);
|
|
||||||
argv[i] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (const char * const *) argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pex_win32_open_read (struct pex_obj *, const char *, int);
|
static int pex_win32_open_read (struct pex_obj *, const char *, int);
|
||||||
static int pex_win32_open_write (struct pex_obj *, const char *, int);
|
static int pex_win32_open_write (struct pex_obj *, const char *, int);
|
||||||
static long pex_win32_exec_child (struct pex_obj *, int, const char *,
|
static long pex_win32_exec_child (struct pex_obj *, int, const char *,
|
||||||
|
@ -422,8 +314,225 @@ msys_rootify (const char *executable)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Return a Windows command-line from ARGV. It is the caller's
|
||||||
|
responsibility to free the string returned. */
|
||||||
|
|
||||||
|
static char *
|
||||||
|
argv_to_cmdline (char *const *argv)
|
||||||
|
{
|
||||||
|
char *cmdline;
|
||||||
|
char *p;
|
||||||
|
size_t cmdline_len;
|
||||||
|
int i, j, k;
|
||||||
|
|
||||||
|
cmdline_len = 0;
|
||||||
|
for (i = 0; argv[i]; i++)
|
||||||
|
{
|
||||||
|
/* We quote every last argument. This simplifies the problem;
|
||||||
|
we need only escape embedded double-quotes and immediately
|
||||||
|
preceeding backslash characters. A sequence of backslach characters
|
||||||
|
that is not follwed by a double quote character will not be
|
||||||
|
escaped. */
|
||||||
|
for (j = 0; argv[i][j]; j++)
|
||||||
|
{
|
||||||
|
if (argv[i][j] == '"')
|
||||||
|
{
|
||||||
|
/* Escape preceeding backslashes. */
|
||||||
|
for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
|
||||||
|
cmdline_len++;
|
||||||
|
/* Escape the qote character. */
|
||||||
|
cmdline_len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Trailing backslashes also need to be escaped because they will be
|
||||||
|
followed by the terminating quote. */
|
||||||
|
for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
|
||||||
|
cmdline_len++;
|
||||||
|
cmdline_len += j;
|
||||||
|
cmdline_len += 3; /* for leading and trailing quotes and space */
|
||||||
|
}
|
||||||
|
cmdline = xmalloc (cmdline_len);
|
||||||
|
p = cmdline;
|
||||||
|
for (i = 0; argv[i]; i++)
|
||||||
|
{
|
||||||
|
*p++ = '"';
|
||||||
|
for (j = 0; argv[i][j]; j++)
|
||||||
|
{
|
||||||
|
if (argv[i][j] == '"')
|
||||||
|
{
|
||||||
|
for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = '\\';
|
||||||
|
}
|
||||||
|
*p++ = argv[i][j];
|
||||||
|
}
|
||||||
|
for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = '"';
|
||||||
|
*p++ = ' ';
|
||||||
|
}
|
||||||
|
p[-1] = '\0';
|
||||||
|
return cmdline;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *const
|
||||||
|
std_suffixes[] = {
|
||||||
|
".com",
|
||||||
|
".exe",
|
||||||
|
".bat",
|
||||||
|
".cmd",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
static const char *const
|
||||||
|
no_suffixes[] = {
|
||||||
|
"",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Returns the full path to PROGRAM. If SEARCH is true, look for
|
||||||
|
PROGRAM in each directory in PATH. */
|
||||||
|
|
||||||
|
static char *
|
||||||
|
find_executable (const char *program, BOOL search)
|
||||||
|
{
|
||||||
|
char *full_executable;
|
||||||
|
char *e;
|
||||||
|
size_t fe_len;
|
||||||
|
const char *path = 0;
|
||||||
|
const char *const *ext;
|
||||||
|
const char *p, *q;
|
||||||
|
size_t proglen = strlen (program);
|
||||||
|
int has_extension = !!strchr (program, '.');
|
||||||
|
int has_slash = (strchr (program, '/') || strchr (program, '\\'));
|
||||||
|
HANDLE h;
|
||||||
|
|
||||||
|
if (has_slash)
|
||||||
|
search = FALSE;
|
||||||
|
|
||||||
|
if (search)
|
||||||
|
path = getenv ("PATH");
|
||||||
|
if (!path)
|
||||||
|
path = "";
|
||||||
|
|
||||||
|
fe_len = 0;
|
||||||
|
for (p = path; *p; p = q)
|
||||||
|
{
|
||||||
|
q = p;
|
||||||
|
while (*q != ';' && *q != '\0')
|
||||||
|
q++;
|
||||||
|
if ((size_t)(q - p) > fe_len)
|
||||||
|
fe_len = q - p;
|
||||||
|
if (*q == ';')
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
fe_len = fe_len + 1 + proglen + (has_extension ? 1 : 5);
|
||||||
|
full_executable = xmalloc (fe_len);
|
||||||
|
|
||||||
|
p = path;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
q = p;
|
||||||
|
while (*q != ';' && *q != '\0')
|
||||||
|
q++;
|
||||||
|
|
||||||
|
e = full_executable;
|
||||||
|
memcpy (e, p, q - p);
|
||||||
|
e += (q - p);
|
||||||
|
if (q - p)
|
||||||
|
*e++ = '\\';
|
||||||
|
strcpy (e, program);
|
||||||
|
|
||||||
|
if (*q == ';')
|
||||||
|
q++;
|
||||||
|
|
||||||
|
for (e = full_executable; *e; e++)
|
||||||
|
if (*e == '/')
|
||||||
|
*e = '\\';
|
||||||
|
|
||||||
|
/* At this point, e points to the terminating NUL character for
|
||||||
|
full_executable. */
|
||||||
|
for (ext = has_extension ? no_suffixes : std_suffixes; *ext; ext++)
|
||||||
|
{
|
||||||
|
/* Remove any current extension. */
|
||||||
|
*e = '\0';
|
||||||
|
/* Add the new one. */
|
||||||
|
strcat (full_executable, *ext);
|
||||||
|
|
||||||
|
/* Attempt to open this file. */
|
||||||
|
h = CreateFile (full_executable, GENERIC_READ,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
}
|
||||||
|
while (*p);
|
||||||
|
free (full_executable);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
found:
|
||||||
|
CloseHandle (h);
|
||||||
|
return full_executable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Low-level process creation function. */
|
||||||
|
|
||||||
static long
|
static long
|
||||||
spawn_script (const char *executable, const char * const * argv)
|
win32_spawn (const char *executable,
|
||||||
|
BOOL search,
|
||||||
|
char *const *argv,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPSTARTUPINFO si,
|
||||||
|
LPPROCESS_INFORMATION pi)
|
||||||
|
{
|
||||||
|
char *full_executable;
|
||||||
|
char *cmdline;
|
||||||
|
|
||||||
|
full_executable = NULL;
|
||||||
|
cmdline = NULL;
|
||||||
|
|
||||||
|
full_executable = find_executable (executable, search);
|
||||||
|
if (!full_executable)
|
||||||
|
goto error;
|
||||||
|
cmdline = argv_to_cmdline (argv);
|
||||||
|
if (!cmdline)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Create the child process. */
|
||||||
|
if (!CreateProcess (full_executable, cmdline,
|
||||||
|
/*lpProcessAttributes=*/NULL,
|
||||||
|
/*lpThreadAttributes=*/NULL,
|
||||||
|
/*bInheritHandles=*/TRUE,
|
||||||
|
dwCreationFlags,
|
||||||
|
/*lpEnvironment=*/NULL,
|
||||||
|
/*lpCurrentDirectory=*/NULL,
|
||||||
|
si,
|
||||||
|
pi))
|
||||||
|
{
|
||||||
|
free (full_executable);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up. */
|
||||||
|
CloseHandle (pi->hThread);
|
||||||
|
free (full_executable);
|
||||||
|
|
||||||
|
return (long) pi->hProcess;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (cmdline)
|
||||||
|
free (cmdline);
|
||||||
|
if (full_executable)
|
||||||
|
free (full_executable);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
spawn_script (const char *executable, char *const *argv,
|
||||||
|
DWORD dwCreationFlags,
|
||||||
|
LPSTARTUPINFO si,
|
||||||
|
LPPROCESS_INFORMATION pi)
|
||||||
{
|
{
|
||||||
int pid = -1;
|
int pid = -1;
|
||||||
int save_errno = errno;
|
int save_errno = errno;
|
||||||
|
@ -455,17 +564,21 @@ spawn_script (const char *executable, const char * const * argv)
|
||||||
executable = strrchr (executable1, '\\') + 1;
|
executable = strrchr (executable1, '\\') + 1;
|
||||||
if (!executable)
|
if (!executable)
|
||||||
executable = executable1;
|
executable = executable1;
|
||||||
pid = _spawnvp (_P_NOWAIT, executable, argv);
|
pid = win32_spawn (executable, TRUE, argv,
|
||||||
|
dwCreationFlags, si, pi);
|
||||||
#else
|
#else
|
||||||
if (strchr (executable1, '\\') == NULL)
|
if (strchr (executable1, '\\') == NULL)
|
||||||
pid = _spawnvp (_P_NOWAIT, executable1, argv);
|
pid = win32_spawn (executable1, TRUE, argv,
|
||||||
|
dwCreationFlags, si, pi);
|
||||||
else if (executable1[0] != '\\')
|
else if (executable1[0] != '\\')
|
||||||
pid = _spawnv (_P_NOWAIT, executable1, argv);
|
pid = win32_spawn (executable1, FALSE, argv,
|
||||||
|
dwCreationFlags, si, pi);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char *newex = mingw_rootify (executable1);
|
const char *newex = mingw_rootify (executable1);
|
||||||
*avhere = newex;
|
*avhere = newex;
|
||||||
pid = _spawnv (_P_NOWAIT, newex, argv);
|
pid = win32_spawn (newex, FALSE, argv,
|
||||||
|
dwCreationFlags, si, pi);
|
||||||
if (executable1 != newex)
|
if (executable1 != newex)
|
||||||
free ((char *) newex);
|
free ((char *) newex);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
|
@ -474,7 +587,8 @@ spawn_script (const char *executable, const char * const * argv)
|
||||||
if (newex != executable1)
|
if (newex != executable1)
|
||||||
{
|
{
|
||||||
*avhere = newex;
|
*avhere = newex;
|
||||||
pid = _spawnv (_P_NOWAIT, newex, argv);
|
pid = win32_spawn (newex, FALSE, argv,
|
||||||
|
dwCreationFlags, si, pi);
|
||||||
free ((char *) newex);
|
free ((char *) newex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,149 +610,95 @@ pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
|
||||||
int in, int out, int errdes, const char **errmsg,
|
int in, int out, int errdes, const char **errmsg,
|
||||||
int *err)
|
int *err)
|
||||||
{
|
{
|
||||||
int org_in, org_out, org_errdes;
|
|
||||||
long pid;
|
long pid;
|
||||||
const char * const * newargv;
|
HANDLE stdin_handle;
|
||||||
|
HANDLE stdout_handle;
|
||||||
|
HANDLE stderr_handle;
|
||||||
|
DWORD dwCreationFlags;
|
||||||
|
OSVERSIONINFO version_info;
|
||||||
|
STARTUPINFO si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
|
||||||
org_in = -1;
|
stdin_handle = INVALID_HANDLE_VALUE;
|
||||||
org_out = -1;
|
stdout_handle = INVALID_HANDLE_VALUE;
|
||||||
org_errdes = -1;
|
stderr_handle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
if (in != STDIN_FILE_NO)
|
stdin_handle = (HANDLE) _get_osfhandle (in);
|
||||||
|
stdout_handle = (HANDLE) _get_osfhandle (out);
|
||||||
|
if (!(flags & PEX_STDERR_TO_STDOUT))
|
||||||
|
stderr_handle = (HANDLE) _get_osfhandle (errdes);
|
||||||
|
else
|
||||||
|
stderr_handle = stdout_handle;
|
||||||
|
|
||||||
|
/* Determine the version of Windows we are running on. */
|
||||||
|
version_info.dwOSVersionInfoSize = sizeof (version_info);
|
||||||
|
GetVersionEx (&version_info);
|
||||||
|
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
||||||
|
/* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
|
||||||
|
supported, so we cannot avoid creating a console window. */
|
||||||
|
dwCreationFlags = 0;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
org_in = _dup (STDIN_FILE_NO);
|
HANDLE conout_handle;
|
||||||
if (org_in < 0)
|
|
||||||
|
/* Determine whether or not we have an associated console. */
|
||||||
|
conout_handle = CreateFile("CONOUT$",
|
||||||
|
GENERIC_WRITE,
|
||||||
|
FILE_SHARE_WRITE,
|
||||||
|
/*lpSecurityAttributes=*/NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
/*hTemplateFile=*/NULL);
|
||||||
|
if (conout_handle == INVALID_HANDLE_VALUE)
|
||||||
|
/* There is no console associated with this process. Since
|
||||||
|
the child is a console process, the OS would normally
|
||||||
|
create a new console Window for the child. Since we'll be
|
||||||
|
redirecting the child's standard streams, we do not need
|
||||||
|
the console window. */
|
||||||
|
dwCreationFlags = CREATE_NO_WINDOW;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
*err = errno;
|
/* There is a console associated with the process, so the OS
|
||||||
*errmsg = "_dup";
|
will not create a new console. And, if we use
|
||||||
return -1;
|
CREATE_NO_WINDOW in this situation, the child will have
|
||||||
}
|
no associated console. Therefore, if the child's
|
||||||
if (_dup2 (in, STDIN_FILE_NO) < 0)
|
standard streams are connected to the console, the output
|
||||||
{
|
will be discarded. */
|
||||||
*err = errno;
|
CloseHandle(conout_handle);
|
||||||
*errmsg = "_dup2";
|
dwCreationFlags = 0;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (_close (in) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_close";
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out != STDOUT_FILE_NO)
|
/* Since the child will be a console process, it will, by default,
|
||||||
{
|
connect standard input/output to its console. However, we want
|
||||||
org_out = _dup (STDOUT_FILE_NO);
|
the child to use the handles specifically designated above. In
|
||||||
if (org_out < 0)
|
addition, if there is no console (such as when we are running in
|
||||||
{
|
a Cygwin X window), then we must redirect the child's
|
||||||
*err = errno;
|
input/output, as there is no console for the child to use. */
|
||||||
*errmsg = "_dup";
|
memset (&si, 0, sizeof (si));
|
||||||
return -1;
|
si.cb = sizeof (si);
|
||||||
}
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
if (_dup2 (out, STDOUT_FILE_NO) < 0)
|
si.hStdInput = stdin_handle;
|
||||||
{
|
si.hStdOutput = stdout_handle;
|
||||||
*err = errno;
|
si.hStdError = stderr_handle;
|
||||||
*errmsg = "_dup2";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (_close (out) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_close";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errdes != STDERR_FILE_NO
|
|
||||||
|| (flags & PEX_STDERR_TO_STDOUT) != 0)
|
|
||||||
{
|
|
||||||
org_errdes = _dup (STDERR_FILE_NO);
|
|
||||||
if (org_errdes < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_dup";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (_dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
|
|
||||||
STDERR_FILE_NO) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_dup2";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (errdes != STDERR_FILE_NO)
|
|
||||||
{
|
|
||||||
if (_close (errdes) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_close";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newargv = fix_argv (argv);
|
|
||||||
pid = (((flags & PEX_SEARCH) != 0 ? _spawnvp : _spawnv)
|
|
||||||
(_P_NOWAIT, executable, newargv));
|
|
||||||
|
|
||||||
|
/* Create the child process. */
|
||||||
|
pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
|
||||||
|
argv, dwCreationFlags, &si, &pi);
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
pid = spawn_script (executable, newargv);
|
pid = spawn_script (executable, argv, dwCreationFlags, &si, &pi);
|
||||||
|
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
{
|
{
|
||||||
*err = errno;
|
*err = ENOENT;
|
||||||
*errmsg = ((flags & PEX_SEARCH) != 0) ? "_spawnvp" : "_spawnv";
|
*errmsg = "CreateProcess";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in != STDIN_FILE_NO)
|
/* Close the standard output and standard error handles in the
|
||||||
{
|
parent. */
|
||||||
if (_dup2 (org_in, STDIN_FILE_NO) < 0)
|
if (out != STDOUT_FILENO)
|
||||||
{
|
obj->funcs->close (obj, out);
|
||||||
*err = errno;
|
if (errdes != STDERR_FILENO)
|
||||||
*errmsg = "_dup2";
|
obj->funcs->close (obj, errdes);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (_close (org_in) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_close";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out != STDOUT_FILE_NO)
|
|
||||||
{
|
|
||||||
if (_dup2 (org_out, STDOUT_FILE_NO) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_dup2";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (_close (org_out) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_close";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errdes != STDERR_FILE_NO
|
|
||||||
|| (flags & PEX_STDERR_TO_STDOUT) != 0)
|
|
||||||
{
|
|
||||||
if (_dup2 (org_errdes, STDERR_FILE_NO) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_dup2";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (_close (org_errdes) < 0)
|
|
||||||
{
|
|
||||||
*err = errno;
|
|
||||||
*errmsg = "_close";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
@ -656,30 +716,34 @@ pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid,
|
||||||
int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
|
int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
|
||||||
const char **errmsg, int *err)
|
const char **errmsg, int *err)
|
||||||
{
|
{
|
||||||
int termstat;
|
DWORD termstat;
|
||||||
|
HANDLE h;
|
||||||
|
|
||||||
if (time != NULL)
|
if (time != NULL)
|
||||||
memset (time, 0, sizeof *time);
|
memset (time, 0, sizeof *time);
|
||||||
|
|
||||||
|
h = (HANDLE) pid;
|
||||||
|
|
||||||
/* FIXME: If done is non-zero, we should probably try to kill the
|
/* FIXME: If done is non-zero, we should probably try to kill the
|
||||||
process. */
|
process. */
|
||||||
|
if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
|
||||||
if (_cwait (&termstat, pid, WAIT_CHILD) < 0)
|
|
||||||
{
|
{
|
||||||
*err = errno;
|
CloseHandle (h);
|
||||||
*errmsg = "_cwait";
|
*err = ECHILD;
|
||||||
|
*errmsg = "WaitForSingleObject";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cwait returns the child process exit code in termstat. A value
|
GetExitCodeProcess (h, &termstat);
|
||||||
of 3 indicates that the child caught a signal, but not which one.
|
CloseHandle (h);
|
||||||
Since only SIGABRT, SIGFPE and SIGINT do anything, we report
|
|
||||||
SIGABRT. */
|
/* A value of 3 indicates that the child caught a signal, but not
|
||||||
|
which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we
|
||||||
|
report SIGABRT. */
|
||||||
if (termstat == 3)
|
if (termstat == 3)
|
||||||
*status = SIGABRT;
|
*status = SIGABRT;
|
||||||
else
|
else
|
||||||
*status = ((termstat & 0xff) << 8);
|
*status = (termstat & 0xff) << 8;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue