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 long pex_win32_exec_child (struct pex_obj *, int, const char *,
+static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
char * const *, char * const *,
int, int, int, int,
const char **, int *);
static int pex_win32_close (struct pex_obj *, int);
-static int pex_win32_wait (struct pex_obj *, long, int *,
+static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
struct pex_time *, int, const char **, int *);
static int pex_win32_pipe (struct pex_obj *, int *, int);
static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
if (!namebuf || !foundbuf)
{
RegCloseKey (hKey);
- if (namebuf)
- free (namebuf);
- if (foundbuf)
- free (foundbuf);
+ free (namebuf);
+ free (foundbuf);
return executable;
}
return tack_on_executable (buf, executable);
/* failed */
- if (buf)
- free (buf);
+ free (buf);
return executable;
}
#endif
+/* Return the number of arguments in an argv array, not including the null
+ terminating argument. */
+
+static int
+argv_to_argc (char *const *argv)
+{
+ char *const *i = argv;
+ while (*i)
+ i++;
+ return i - argv;
+}
+
/* Return a Windows command-line from ARGV. It is the caller's
responsibility to free the string returned. */
return c1 - c2;
}
-static long
+/* Execute a Windows executable as a child process. This will fail if the
+ * target is not actually an executable, such as if it is a shell script. */
+
+static pid_t
win32_spawn (const char *executable,
BOOL search,
char *const *argv,
si,
pi))
{
- if (env_block)
- free (env_block);
+ free (env_block);
free (full_executable);
- return -1;
+ return (pid_t) -1;
}
/* Clean up. */
CloseHandle (pi->hThread);
free (full_executable);
- if (env_block)
- free (env_block);
+ free (env_block);
- return (long) pi->hProcess;
+ return (pid_t) pi->hProcess;
error:
- if (env_block)
- free (env_block);
- if (cmdline)
- free (cmdline);
- if (full_executable)
- free (full_executable);
-
- return -1;
+ free (env_block);
+ free (cmdline);
+ free (full_executable);
+
+ return (pid_t) -1;
}
-static long
+/* Spawn a script. This simulates the Unix script execution mechanism.
+ This function is called as a fallback if win32_spawn fails. */
+
+static pid_t
spawn_script (const char *executable, char *const *argv,
char* const *env,
DWORD dwCreationFlags,
LPSTARTUPINFO si,
LPPROCESS_INFORMATION pi)
{
- int pid = -1;
+ pid_t pid = (pid_t) -1;
int save_errno = errno;
int fd = _open (executable, _O_RDONLY);
+ /* Try to open script, check header format, extract interpreter path,
+ and spawn script using that interpretter. */
if (fd >= 0)
{
char buf[MAX_PATH + 5];
eol = strchr (buf, '\n');
if (eol && strncmp (buf, "#!", 2) == 0)
{
+
+ /* Header format is OK. */
char *executable1;
- const char ** avhere = (const char **) --argv;
+ int new_argc;
+ const char **avhere;
+
+ /* Extract interpreter path. */
do
*eol = '\0';
while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
continue;
-
backslashify (executable1);
+
+ /* Duplicate argv, prepending the interpreter path. */
+ new_argc = argv_to_argc (argv) + 1;
+ avhere = XNEWVEC (const char *, new_argc + 1);
*avhere = executable1;
+ memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
+ argv = (char *const *)avhere;
+
+ /* Spawn the child. */
#ifndef USE_MINGW_MSYS
executable = strrchr (executable1, '\\') + 1;
if (!executable)
dwCreationFlags, si, pi);
if (executable1 != newex)
free ((char *) newex);
- if (pid < 0)
+ if (pid == (pid_t) -1)
{
newex = msys_rootify (executable1);
if (newex != executable1)
}
}
#endif
+ free (avhere);
}
}
}
- if (pid < 0)
+ if (pid == (pid_t) -1)
errno = save_errno;
return pid;
}
/* Execute a child. */
-static long
+static pid_t
pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
const char *executable, char * const * argv,
char* const* env,
const char **errmsg,
int *err)
{
- long pid;
+ pid_t pid;
HANDLE stdin_handle;
HANDLE stdout_handle;
HANDLE stderr_handle;
OSVERSIONINFO version_info;
STARTUPINFO si;
PROCESS_INFORMATION pi;
+ int orig_out, orig_in, orig_err;
+ BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
+
+ /* Ensure we have inheritable descriptors to pass to the child. */
+ orig_in = in;
+ in = _dup (orig_in);
+
+ orig_out = out;
+ out = _dup (orig_out);
+
+ if (separate_stderr)
+ {
+ orig_err = errdes;
+ errdes = _dup (orig_err);
+ }
stdin_handle = INVALID_HANDLE_VALUE;
stdout_handle = INVALID_HANDLE_VALUE;
stdin_handle = (HANDLE) _get_osfhandle (in);
stdout_handle = (HANDLE) _get_osfhandle (out);
- if (!(flags & PEX_STDERR_TO_STDOUT))
+ if (separate_stderr)
stderr_handle = (HANDLE) _get_osfhandle (errdes);
else
stderr_handle = stdout_handle;
/* Create the child process. */
pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
argv, env, dwCreationFlags, &si, &pi);
- if (pid == -1)
+ if (pid == (pid_t) -1)
pid = spawn_script (executable, argv, env, dwCreationFlags,
&si, &pi);
- if (pid == -1)
+ if (pid == (pid_t) -1)
{
*err = ENOENT;
*errmsg = "CreateProcess";
}
- /* Close the standard output and standard error handles in the
- parent. */
- if (out != STDOUT_FILENO)
- obj->funcs->close (obj, out);
- if (errdes != STDERR_FILENO)
- obj->funcs->close (obj, errdes);
+ /* If the child was created successfully, close the original file
+ descriptors. If the process creation fails, these are closed by
+ pex_run_in_environment instead. We must not close them twice as
+ that seems to cause a Windows exception. */
+
+ if (pid != (pid_t) -1)
+ {
+ if (orig_in != STDIN_FILENO)
+ _close (orig_in);
+ if (orig_out != STDOUT_FILENO)
+ _close (orig_out);
+ if (separate_stderr
+ && orig_err != STDERR_FILENO)
+ _close (orig_err);
+ }
+
+ /* Close the standard input, standard output and standard error handles
+ in the parent. */
+
+ _close (in);
+ _close (out);
+ if (separate_stderr)
+ _close (errdes);
return pid;
}
status == 3. We fix the status code to conform to the usual WIF*
macros. Note that WIFSIGNALED will never be true under CRTDLL. */
-static int
-pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid,
+static pid_t
+pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
const char **errmsg, int *err)
{
pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
int binary)
{
- return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
+ return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
}
/* Get a FILE pointer to read from a file descriptor. */
pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
int binary)
{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
+ return NULL;
return fdopen (fd, binary ? "rb" : "r");
}
char const *errmsg;
int err;
argv++;
- printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
+ printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
exit (0);
}
#endif