16ca2c52aSchristos /* Utilities to execute a program in a subprocess (possibly linked by pipes
26ca2c52aSchristos    with other subprocesses), and wait for it.  Generic Win32 specialization.
3*184b2d41Schristos    Copyright (C) 1996-2020 Free Software Foundation, Inc.
46ca2c52aSchristos 
56ca2c52aSchristos This file is part of the libiberty library.
66ca2c52aSchristos Libiberty is free software; you can redistribute it and/or
76ca2c52aSchristos modify it under the terms of the GNU Library General Public
86ca2c52aSchristos License as published by the Free Software Foundation; either
96ca2c52aSchristos version 2 of the License, or (at your option) any later version.
106ca2c52aSchristos 
116ca2c52aSchristos Libiberty is distributed in the hope that it will be useful,
126ca2c52aSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
136ca2c52aSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146ca2c52aSchristos Library General Public License for more details.
156ca2c52aSchristos 
166ca2c52aSchristos You should have received a copy of the GNU Library General Public
176ca2c52aSchristos License along with libiberty; see the file COPYING.LIB.  If not,
186ca2c52aSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
196ca2c52aSchristos Boston, MA 02110-1301, USA.  */
206ca2c52aSchristos 
216ca2c52aSchristos #include "pex-common.h"
226ca2c52aSchristos 
236ca2c52aSchristos #include <windows.h>
246ca2c52aSchristos 
256ca2c52aSchristos #ifdef HAVE_STDLIB_H
266ca2c52aSchristos #include <stdlib.h>
276ca2c52aSchristos #endif
286ca2c52aSchristos #ifdef HAVE_STRING_H
296ca2c52aSchristos #include <string.h>
306ca2c52aSchristos #endif
316ca2c52aSchristos #ifdef HAVE_UNISTD_H
326ca2c52aSchristos #include <unistd.h>
336ca2c52aSchristos #endif
346ca2c52aSchristos #ifdef HAVE_SYS_WAIT_H
356ca2c52aSchristos #include <sys/wait.h>
366ca2c52aSchristos #endif
376ca2c52aSchristos 
386ca2c52aSchristos #include <assert.h>
396ca2c52aSchristos #include <process.h>
406ca2c52aSchristos #include <io.h>
416ca2c52aSchristos #include <fcntl.h>
426ca2c52aSchristos #include <signal.h>
436ca2c52aSchristos #include <sys/stat.h>
446ca2c52aSchristos #include <errno.h>
456ca2c52aSchristos #include <ctype.h>
466ca2c52aSchristos 
476ca2c52aSchristos /* mingw32 headers may not define the following.  */
486ca2c52aSchristos 
496ca2c52aSchristos #ifndef _P_WAIT
506ca2c52aSchristos #  define _P_WAIT	0
516ca2c52aSchristos #  define _P_NOWAIT	1
526ca2c52aSchristos #  define _P_OVERLAY	2
536ca2c52aSchristos #  define _P_NOWAITO	3
546ca2c52aSchristos #  define _P_DETACH	4
556ca2c52aSchristos 
566ca2c52aSchristos #  define WAIT_CHILD		0
576ca2c52aSchristos #  define WAIT_GRANDCHILD	1
586ca2c52aSchristos #endif
596ca2c52aSchristos 
606ca2c52aSchristos #define MINGW_NAME "Minimalist GNU for Windows"
616ca2c52aSchristos #define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
626ca2c52aSchristos 
636ca2c52aSchristos extern char *stpcpy (char *dst, const char *src);
646ca2c52aSchristos 
656ca2c52aSchristos /* Ensure that the executable pathname uses Win32 backslashes. This
666ca2c52aSchristos    is not necessary on NT, but on W9x, forward slashes causes
676ca2c52aSchristos    failure of spawn* and exec* functions (and probably any function
686ca2c52aSchristos    that calls CreateProcess) *iff* the executable pathname (argv[0])
696ca2c52aSchristos    is a quoted string.  And quoting is necessary in case a pathname
706ca2c52aSchristos    contains embedded white space.  You can't win.  */
716ca2c52aSchristos static void
backslashify(char * s)726ca2c52aSchristos backslashify (char *s)
736ca2c52aSchristos {
746ca2c52aSchristos   while ((s = strchr (s, '/')) != NULL)
756ca2c52aSchristos     *s = '\\';
766ca2c52aSchristos   return;
776ca2c52aSchristos }
786ca2c52aSchristos 
796ca2c52aSchristos static int pex_win32_open_read (struct pex_obj *, const char *, int);
806ca2c52aSchristos static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
816ca2c52aSchristos static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
826ca2c52aSchristos 				  char * const *, char * const *,
836ca2c52aSchristos                                   int, int, int, int,
846ca2c52aSchristos 				  const char **, int *);
856ca2c52aSchristos static int pex_win32_close (struct pex_obj *, int);
866ca2c52aSchristos static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
876ca2c52aSchristos 			   struct pex_time *, int, const char **, int *);
886ca2c52aSchristos static int pex_win32_pipe (struct pex_obj *, int *, int);
896ca2c52aSchristos static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
906ca2c52aSchristos static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
916ca2c52aSchristos 
926ca2c52aSchristos /* The list of functions we pass to the common routines.  */
936ca2c52aSchristos 
946ca2c52aSchristos const struct pex_funcs funcs =
956ca2c52aSchristos {
966ca2c52aSchristos   pex_win32_open_read,
976ca2c52aSchristos   pex_win32_open_write,
986ca2c52aSchristos   pex_win32_exec_child,
996ca2c52aSchristos   pex_win32_close,
1006ca2c52aSchristos   pex_win32_wait,
1016ca2c52aSchristos   pex_win32_pipe,
1026ca2c52aSchristos   pex_win32_fdopenr,
1036ca2c52aSchristos   pex_win32_fdopenw,
1046ca2c52aSchristos   NULL /* cleanup */
1056ca2c52aSchristos };
1066ca2c52aSchristos 
1076ca2c52aSchristos /* Return a newly initialized pex_obj structure.  */
1086ca2c52aSchristos 
1096ca2c52aSchristos struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)1106ca2c52aSchristos pex_init (int flags, const char *pname, const char *tempbase)
1116ca2c52aSchristos {
1126ca2c52aSchristos   return pex_init_common (flags, pname, tempbase, &funcs);
1136ca2c52aSchristos }
1146ca2c52aSchristos 
1156ca2c52aSchristos /* Open a file for reading.  */
1166ca2c52aSchristos 
1176ca2c52aSchristos static int
pex_win32_open_read(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary)1186ca2c52aSchristos pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
1196ca2c52aSchristos 		     int binary)
1206ca2c52aSchristos {
1216ca2c52aSchristos   return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
1226ca2c52aSchristos }
1236ca2c52aSchristos 
1246ca2c52aSchristos /* Open a file for writing.  */
1256ca2c52aSchristos 
1266ca2c52aSchristos static int
pex_win32_open_write(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary,int append)1276ca2c52aSchristos pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
1286ca2c52aSchristos 		      int binary, int append)
1296ca2c52aSchristos {
1306ca2c52aSchristos   /* Note that we can't use O_EXCL here because gcc may have already
1316ca2c52aSchristos      created the temporary file via make_temp_file.  */
1326ca2c52aSchristos   if (append)
1336ca2c52aSchristos     return -1;
1346ca2c52aSchristos   return _open (name,
1356ca2c52aSchristos 		(_O_WRONLY | _O_CREAT | _O_TRUNC
1366ca2c52aSchristos 		 | (binary ? _O_BINARY : _O_TEXT)),
1376ca2c52aSchristos 		_S_IREAD | _S_IWRITE);
1386ca2c52aSchristos }
1396ca2c52aSchristos 
1406ca2c52aSchristos /* Close a file.  */
1416ca2c52aSchristos 
1426ca2c52aSchristos static int
pex_win32_close(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd)1436ca2c52aSchristos pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
1446ca2c52aSchristos {
1456ca2c52aSchristos   return _close (fd);
1466ca2c52aSchristos }
1476ca2c52aSchristos 
1486ca2c52aSchristos #ifdef USE_MINGW_MSYS
1496ca2c52aSchristos static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
1506ca2c52aSchristos 
1516ca2c52aSchristos /* Tack the executable on the end of a (possibly slash terminated) buffer
1526ca2c52aSchristos    and convert everything to \. */
1536ca2c52aSchristos static const char *
tack_on_executable(char * buf,const char * executable)1546ca2c52aSchristos tack_on_executable (char *buf, const char *executable)
1556ca2c52aSchristos {
1566ca2c52aSchristos   char *p = strchr (buf, '\0');
1576ca2c52aSchristos   if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
1586ca2c52aSchristos     p[-1] = '\0';
1596ca2c52aSchristos   backslashify (strcat (buf, executable));
1606ca2c52aSchristos   return buf;
1616ca2c52aSchristos }
1626ca2c52aSchristos 
1636ca2c52aSchristos /* Walk down a registry hierarchy until the end.  Return the key. */
1646ca2c52aSchristos static HKEY
openkey(HKEY hStart,const char * keys[])1656ca2c52aSchristos openkey (HKEY hStart, const char *keys[])
1666ca2c52aSchristos {
1676ca2c52aSchristos   HKEY hKey, hTmp;
1686ca2c52aSchristos   for (hKey = hStart; *keys; keys++)
1696ca2c52aSchristos     {
1706ca2c52aSchristos       LONG res;
1716ca2c52aSchristos       hTmp = hKey;
1726ca2c52aSchristos       res = RegOpenKey (hTmp, *keys, &hKey);
1736ca2c52aSchristos 
1746ca2c52aSchristos       if (hTmp != HKEY_LOCAL_MACHINE)
1756ca2c52aSchristos 	RegCloseKey (hTmp);
1766ca2c52aSchristos 
1776ca2c52aSchristos       if (res != ERROR_SUCCESS)
1786ca2c52aSchristos 	return NULL;
1796ca2c52aSchristos     }
1806ca2c52aSchristos   return hKey;
1816ca2c52aSchristos }
1826ca2c52aSchristos 
1836ca2c52aSchristos /* Return the "mingw root" as derived from the mingw uninstall information. */
1846ca2c52aSchristos static const char *
mingw_rootify(const char * executable)1856ca2c52aSchristos mingw_rootify (const char *executable)
1866ca2c52aSchristos {
1876ca2c52aSchristos   HKEY hKey, hTmp;
1886ca2c52aSchristos   DWORD maxlen;
1896ca2c52aSchristos   char *namebuf, *foundbuf;
1906ca2c52aSchristos   DWORD i;
1916ca2c52aSchristos   LONG res;
1926ca2c52aSchristos 
1936ca2c52aSchristos   /* Open the uninstall "directory". */
1946ca2c52aSchristos   hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
1956ca2c52aSchristos 
1966ca2c52aSchristos   /* Not found. */
1976ca2c52aSchristos   if (!hKey)
1986ca2c52aSchristos     return executable;
1996ca2c52aSchristos 
2006ca2c52aSchristos   /* Need to enumerate all of the keys here looking for one the most recent
2016ca2c52aSchristos      one for MinGW. */
2026ca2c52aSchristos   if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
2036ca2c52aSchristos 		       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
2046ca2c52aSchristos     {
2056ca2c52aSchristos       RegCloseKey (hKey);
2066ca2c52aSchristos       return executable;
2076ca2c52aSchristos     }
2086ca2c52aSchristos   namebuf = XNEWVEC (char, ++maxlen);
2096ca2c52aSchristos   foundbuf = XNEWVEC (char, maxlen);
2106ca2c52aSchristos   foundbuf[0] = '\0';
2116ca2c52aSchristos   if (!namebuf || !foundbuf)
2126ca2c52aSchristos     {
2136ca2c52aSchristos       RegCloseKey (hKey);
2146ca2c52aSchristos       free (namebuf);
2156ca2c52aSchristos       free (foundbuf);
2166ca2c52aSchristos       return executable;
2176ca2c52aSchristos     }
2186ca2c52aSchristos 
2196ca2c52aSchristos   /* Look through all of the keys for one that begins with Minimal GNU...
2206ca2c52aSchristos      Try to get the latest version by doing a string compare although that
2216ca2c52aSchristos      string never really works with version number sorting. */
2226ca2c52aSchristos   for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
2236ca2c52aSchristos     {
2246ca2c52aSchristos       int match = strcasecmp (namebuf, MINGW_NAME);
2256ca2c52aSchristos       if (match < 0)
2266ca2c52aSchristos 	continue;
2276ca2c52aSchristos       if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
2286ca2c52aSchristos 	continue;
2296ca2c52aSchristos       if (strcasecmp (namebuf, foundbuf) > 0)
2306ca2c52aSchristos 	strcpy (foundbuf, namebuf);
2316ca2c52aSchristos     }
2326ca2c52aSchristos   free (namebuf);
2336ca2c52aSchristos 
2346ca2c52aSchristos   /* If foundbuf is empty, we didn't find anything.  Punt. */
2356ca2c52aSchristos   if (!foundbuf[0])
2366ca2c52aSchristos     {
2376ca2c52aSchristos       free (foundbuf);
2386ca2c52aSchristos       RegCloseKey (hKey);
2396ca2c52aSchristos       return executable;
2406ca2c52aSchristos     }
2416ca2c52aSchristos 
2426ca2c52aSchristos   /* Open the key that we wanted */
2436ca2c52aSchristos   res = RegOpenKey (hKey, foundbuf, &hTmp);
2446ca2c52aSchristos   RegCloseKey (hKey);
2456ca2c52aSchristos   free (foundbuf);
2466ca2c52aSchristos 
2476ca2c52aSchristos   /* Don't know why this would fail, but you gotta check */
2486ca2c52aSchristos   if (res != ERROR_SUCCESS)
2496ca2c52aSchristos     return executable;
2506ca2c52aSchristos 
2516ca2c52aSchristos   maxlen = 0;
2526ca2c52aSchristos   /* Get the length of the value pointed to by InstallLocation */
2536ca2c52aSchristos   if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
2546ca2c52aSchristos 		       &maxlen) != ERROR_SUCCESS || maxlen == 0)
2556ca2c52aSchristos     {
2566ca2c52aSchristos       RegCloseKey (hTmp);
2576ca2c52aSchristos       return executable;
2586ca2c52aSchristos     }
2596ca2c52aSchristos 
2606ca2c52aSchristos   /* Allocate space for the install location */
2616ca2c52aSchristos   foundbuf = XNEWVEC (char, maxlen + strlen (executable));
2626ca2c52aSchristos   if (!foundbuf)
2636ca2c52aSchristos     {
2646ca2c52aSchristos       free (foundbuf);
2656ca2c52aSchristos       RegCloseKey (hTmp);
2666ca2c52aSchristos     }
2676ca2c52aSchristos 
2686ca2c52aSchristos   /* Read the install location into the buffer */
2696ca2c52aSchristos   res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
2706ca2c52aSchristos 			 &maxlen);
2716ca2c52aSchristos   RegCloseKey (hTmp);
2726ca2c52aSchristos   if (res != ERROR_SUCCESS)
2736ca2c52aSchristos     {
2746ca2c52aSchristos       free (foundbuf);
2756ca2c52aSchristos       return executable;
2766ca2c52aSchristos     }
2776ca2c52aSchristos 
2786ca2c52aSchristos   /* Concatenate the install location and the executable, turn all slashes
2796ca2c52aSchristos      to backslashes, and return that. */
2806ca2c52aSchristos   return tack_on_executable (foundbuf, executable);
2816ca2c52aSchristos }
2826ca2c52aSchristos 
2836ca2c52aSchristos /* Read the install location of msys from it's installation file and
2846ca2c52aSchristos    rootify the executable based on that. */
2856ca2c52aSchristos static const char *
msys_rootify(const char * executable)2866ca2c52aSchristos msys_rootify (const char *executable)
2876ca2c52aSchristos {
2886ca2c52aSchristos   size_t bufsize = 64;
2896ca2c52aSchristos   size_t execlen = strlen (executable) + 1;
2906ca2c52aSchristos   char *buf;
2916ca2c52aSchristos   DWORD res = 0;
2926ca2c52aSchristos   for (;;)
2936ca2c52aSchristos     {
2946ca2c52aSchristos       buf = XNEWVEC (char, bufsize + execlen);
2956ca2c52aSchristos       if (!buf)
2966ca2c52aSchristos 	break;
2976ca2c52aSchristos       res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
2986ca2c52aSchristos 				     buf, bufsize, "msys.ini");
2996ca2c52aSchristos       if (!res)
3006ca2c52aSchristos 	break;
3016ca2c52aSchristos       if (strlen (buf) < bufsize)
3026ca2c52aSchristos 	break;
3036ca2c52aSchristos       res = 0;
3046ca2c52aSchristos       free (buf);
3056ca2c52aSchristos       bufsize *= 2;
3066ca2c52aSchristos       if (bufsize > 65536)
3076ca2c52aSchristos 	{
3086ca2c52aSchristos 	  buf = NULL;
3096ca2c52aSchristos 	  break;
3106ca2c52aSchristos 	}
3116ca2c52aSchristos     }
3126ca2c52aSchristos 
3136ca2c52aSchristos   if (res)
3146ca2c52aSchristos     return tack_on_executable (buf, executable);
3156ca2c52aSchristos 
3166ca2c52aSchristos   /* failed */
3176ca2c52aSchristos   free (buf);
3186ca2c52aSchristos   return executable;
3196ca2c52aSchristos }
3206ca2c52aSchristos #endif
3216ca2c52aSchristos 
3226ca2c52aSchristos /* Return the number of arguments in an argv array, not including the null
3236ca2c52aSchristos    terminating argument. */
3246ca2c52aSchristos 
3256ca2c52aSchristos static int
argv_to_argc(char * const * argv)3266ca2c52aSchristos argv_to_argc (char *const *argv)
3276ca2c52aSchristos {
3286ca2c52aSchristos   char *const *i = argv;
3296ca2c52aSchristos   while (*i)
3306ca2c52aSchristos     i++;
3316ca2c52aSchristos   return i - argv;
3326ca2c52aSchristos }
3336ca2c52aSchristos 
3346ca2c52aSchristos /* Return a Windows command-line from ARGV.  It is the caller's
3356ca2c52aSchristos    responsibility to free the string returned.  */
3366ca2c52aSchristos 
3376ca2c52aSchristos static char *
argv_to_cmdline(char * const * argv)3386ca2c52aSchristos argv_to_cmdline (char *const *argv)
3396ca2c52aSchristos {
3406ca2c52aSchristos   char *cmdline;
3416ca2c52aSchristos   char *p;
3426ca2c52aSchristos   size_t cmdline_len;
3436ca2c52aSchristos   int i, j, k;
3446ca2c52aSchristos   int needs_quotes;
3456ca2c52aSchristos 
3466ca2c52aSchristos   cmdline_len = 0;
3476ca2c52aSchristos   for (i = 0; argv[i]; i++)
3486ca2c52aSchristos     {
3496ca2c52aSchristos       /* We only quote arguments that contain spaces, \t or " characters to
3506ca2c52aSchristos 	 prevent wasting 2 chars per argument of the CreateProcess 32k char
3516ca2c52aSchristos 	 limit.  We need only escape embedded double-quotes and immediately
3526ca2c52aSchristos 	 preceeding backslash characters.  A sequence of backslach characters
3536ca2c52aSchristos 	 that is not follwed by a double quote character will not be
3546ca2c52aSchristos 	 escaped.  */
3556ca2c52aSchristos       needs_quotes = 0;
3566ca2c52aSchristos       for (j = 0; argv[i][j]; j++)
3576ca2c52aSchristos 	{
3586ca2c52aSchristos 	  if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
3596ca2c52aSchristos 	    {
3606ca2c52aSchristos 	      needs_quotes = 1;
3616ca2c52aSchristos 	    }
3626ca2c52aSchristos 
3636ca2c52aSchristos 	  if (argv[i][j] == '"')
3646ca2c52aSchristos 	    {
3656ca2c52aSchristos 	      /* Escape preceeding backslashes.  */
3666ca2c52aSchristos 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
3676ca2c52aSchristos 		cmdline_len++;
3686ca2c52aSchristos 	      /* Escape the qote character.  */
3696ca2c52aSchristos 	      cmdline_len++;
3706ca2c52aSchristos 	    }
3716ca2c52aSchristos 	}
37215d8e94aSchristos       if (j == 0)
37315d8e94aSchristos 	needs_quotes = 1;
3746ca2c52aSchristos       /* Trailing backslashes also need to be escaped because they will be
3756ca2c52aSchristos          followed by the terminating quote.  */
3766ca2c52aSchristos       if (needs_quotes)
3776ca2c52aSchristos         {
3786ca2c52aSchristos           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
3796ca2c52aSchristos             cmdline_len++;
3806ca2c52aSchristos         }
3816ca2c52aSchristos       cmdline_len += j;
3826ca2c52aSchristos       /* for leading and trailing quotes and space */
3836ca2c52aSchristos       cmdline_len += needs_quotes * 2 + 1;
3846ca2c52aSchristos     }
3856ca2c52aSchristos   cmdline = XNEWVEC (char, cmdline_len);
3866ca2c52aSchristos   p = cmdline;
3876ca2c52aSchristos   for (i = 0; argv[i]; i++)
3886ca2c52aSchristos     {
3896ca2c52aSchristos       needs_quotes = 0;
3906ca2c52aSchristos       for (j = 0; argv[i][j]; j++)
3916ca2c52aSchristos         {
3926ca2c52aSchristos           if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
3936ca2c52aSchristos             {
3946ca2c52aSchristos               needs_quotes = 1;
3956ca2c52aSchristos               break;
3966ca2c52aSchristos             }
3976ca2c52aSchristos         }
39815d8e94aSchristos       if (j == 0)
39915d8e94aSchristos 	needs_quotes = 1;
4006ca2c52aSchristos 
4016ca2c52aSchristos       if (needs_quotes)
4026ca2c52aSchristos         {
4036ca2c52aSchristos           *p++ = '"';
4046ca2c52aSchristos         }
4056ca2c52aSchristos       for (j = 0; argv[i][j]; j++)
4066ca2c52aSchristos 	{
4076ca2c52aSchristos 	  if (argv[i][j] == '"')
4086ca2c52aSchristos 	    {
4096ca2c52aSchristos 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
4106ca2c52aSchristos 		*p++ = '\\';
4116ca2c52aSchristos 	      *p++ = '\\';
4126ca2c52aSchristos 	    }
4136ca2c52aSchristos 	  *p++ = argv[i][j];
4146ca2c52aSchristos 	}
4156ca2c52aSchristos       if (needs_quotes)
4166ca2c52aSchristos         {
4176ca2c52aSchristos           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
4186ca2c52aSchristos             *p++ = '\\';
4196ca2c52aSchristos           *p++ = '"';
4206ca2c52aSchristos         }
4216ca2c52aSchristos       *p++ = ' ';
4226ca2c52aSchristos     }
4236ca2c52aSchristos   p[-1] = '\0';
4246ca2c52aSchristos   return cmdline;
4256ca2c52aSchristos }
4266ca2c52aSchristos 
4276ca2c52aSchristos /* We'll try the passed filename with all the known standard
4286ca2c52aSchristos    extensions, and then without extension.  We try no extension
4296ca2c52aSchristos    last so that we don't try to run some random extension-less
4306ca2c52aSchristos    file that might be hanging around.  We try both extension
4316ca2c52aSchristos    and no extension so that we don't need any fancy logic
4326ca2c52aSchristos    to determine if a file has extension.  */
4336ca2c52aSchristos static const char *const
4346ca2c52aSchristos std_suffixes[] = {
4356ca2c52aSchristos   ".com",
4366ca2c52aSchristos   ".exe",
4376ca2c52aSchristos   ".bat",
4386ca2c52aSchristos   ".cmd",
4396ca2c52aSchristos   "",
4406ca2c52aSchristos   0
4416ca2c52aSchristos };
4426ca2c52aSchristos 
4436ca2c52aSchristos /* Returns the full path to PROGRAM.  If SEARCH is true, look for
4446ca2c52aSchristos    PROGRAM in each directory in PATH.  */
4456ca2c52aSchristos 
4466ca2c52aSchristos static char *
find_executable(const char * program,BOOL search)4476ca2c52aSchristos find_executable (const char *program, BOOL search)
4486ca2c52aSchristos {
4496ca2c52aSchristos   char *full_executable;
4506ca2c52aSchristos   char *e;
4516ca2c52aSchristos   size_t fe_len;
4526ca2c52aSchristos   const char *path = 0;
4536ca2c52aSchristos   const char *const *ext;
4546ca2c52aSchristos   const char *p, *q;
4556ca2c52aSchristos   size_t proglen = strlen (program);
4566ca2c52aSchristos   int has_slash = (strchr (program, '/') || strchr (program, '\\'));
4576ca2c52aSchristos   HANDLE h;
4586ca2c52aSchristos 
4596ca2c52aSchristos   if (has_slash)
4606ca2c52aSchristos     search = FALSE;
4616ca2c52aSchristos 
4626ca2c52aSchristos   if (search)
4636ca2c52aSchristos     path = getenv ("PATH");
4646ca2c52aSchristos   if (!path)
4656ca2c52aSchristos     path = "";
4666ca2c52aSchristos 
4676ca2c52aSchristos   fe_len = 0;
4686ca2c52aSchristos   for (p = path; *p; p = q)
4696ca2c52aSchristos     {
4706ca2c52aSchristos       q = p;
4716ca2c52aSchristos       while (*q != ';' && *q != '\0')
4726ca2c52aSchristos 	q++;
4736ca2c52aSchristos       if ((size_t)(q - p) > fe_len)
4746ca2c52aSchristos 	fe_len = q - p;
4756ca2c52aSchristos       if (*q == ';')
4766ca2c52aSchristos 	q++;
4776ca2c52aSchristos     }
4786ca2c52aSchristos   fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
4796ca2c52aSchristos   full_executable = XNEWVEC (char, fe_len);
4806ca2c52aSchristos 
4816ca2c52aSchristos   p = path;
4826ca2c52aSchristos   do
4836ca2c52aSchristos     {
4846ca2c52aSchristos       q = p;
4856ca2c52aSchristos       while (*q != ';' && *q != '\0')
4866ca2c52aSchristos 	q++;
4876ca2c52aSchristos 
4886ca2c52aSchristos       e = full_executable;
4896ca2c52aSchristos       memcpy (e, p, q - p);
4906ca2c52aSchristos       e += (q - p);
4916ca2c52aSchristos       if (q - p)
4926ca2c52aSchristos 	*e++ = '\\';
4936ca2c52aSchristos       strcpy (e, program);
4946ca2c52aSchristos 
4956ca2c52aSchristos       if (*q == ';')
4966ca2c52aSchristos 	q++;
4976ca2c52aSchristos 
4986ca2c52aSchristos       for (e = full_executable; *e; e++)
4996ca2c52aSchristos 	if (*e == '/')
5006ca2c52aSchristos 	  *e = '\\';
5016ca2c52aSchristos 
5026ca2c52aSchristos       /* At this point, e points to the terminating NUL character for
5036ca2c52aSchristos          full_executable.  */
5046ca2c52aSchristos       for (ext = std_suffixes; *ext; ext++)
5056ca2c52aSchristos 	{
5066ca2c52aSchristos 	  /* Remove any current extension.  */
5076ca2c52aSchristos 	  *e = '\0';
5086ca2c52aSchristos 	  /* Add the new one.  */
5096ca2c52aSchristos 	  strcat (full_executable, *ext);
5106ca2c52aSchristos 
5116ca2c52aSchristos 	  /* Attempt to open this file.  */
5126ca2c52aSchristos 	  h = CreateFile (full_executable, GENERIC_READ,
5136ca2c52aSchristos 			  FILE_SHARE_READ | FILE_SHARE_WRITE,
5146ca2c52aSchristos 			  0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
5156ca2c52aSchristos 	  if (h != INVALID_HANDLE_VALUE)
5166ca2c52aSchristos 	    goto found;
5176ca2c52aSchristos 	}
5186ca2c52aSchristos       p = q;
5196ca2c52aSchristos     }
5206ca2c52aSchristos   while (*p);
5216ca2c52aSchristos   free (full_executable);
5226ca2c52aSchristos   return 0;
5236ca2c52aSchristos 
5246ca2c52aSchristos  found:
5256ca2c52aSchristos   CloseHandle (h);
5266ca2c52aSchristos   return full_executable;
5276ca2c52aSchristos }
5286ca2c52aSchristos 
5296ca2c52aSchristos /* Low-level process creation function and helper.  */
5306ca2c52aSchristos 
5316ca2c52aSchristos static int
env_compare(const void * a_ptr,const void * b_ptr)5326ca2c52aSchristos env_compare (const void *a_ptr, const void *b_ptr)
5336ca2c52aSchristos {
5346ca2c52aSchristos   const char *a;
5356ca2c52aSchristos   const char *b;
5366ca2c52aSchristos   unsigned char c1;
5376ca2c52aSchristos   unsigned char c2;
5386ca2c52aSchristos 
5396ca2c52aSchristos   a = *(const char **) a_ptr;
5406ca2c52aSchristos   b = *(const char **) b_ptr;
5416ca2c52aSchristos 
5426ca2c52aSchristos   /* a and b will be of the form: VAR=VALUE
5436ca2c52aSchristos      We compare only the variable name part here using a case-insensitive
5446ca2c52aSchristos      comparison algorithm.  It might appear that in fact strcasecmp () can
5456ca2c52aSchristos      take the place of this whole function, and indeed it could, save for
5466ca2c52aSchristos      the fact that it would fail in cases such as comparing A1=foo and
5476ca2c52aSchristos      A=bar (because 1 is less than = in the ASCII character set).
5486ca2c52aSchristos      (Environment variables containing no numbers would work in such a
5496ca2c52aSchristos      scenario.)  */
5506ca2c52aSchristos 
5516ca2c52aSchristos   do
5526ca2c52aSchristos     {
5536ca2c52aSchristos       c1 = (unsigned char) tolower (*a++);
5546ca2c52aSchristos       c2 = (unsigned char) tolower (*b++);
5556ca2c52aSchristos 
5566ca2c52aSchristos       if (c1 == '=')
5576ca2c52aSchristos         c1 = '\0';
5586ca2c52aSchristos 
5596ca2c52aSchristos       if (c2 == '=')
5606ca2c52aSchristos         c2 = '\0';
5616ca2c52aSchristos     }
5626ca2c52aSchristos   while (c1 == c2 && c1 != '\0');
5636ca2c52aSchristos 
5646ca2c52aSchristos   return c1 - c2;
5656ca2c52aSchristos }
5666ca2c52aSchristos 
5676ca2c52aSchristos /* Execute a Windows executable as a child process.  This will fail if the
5686ca2c52aSchristos  * target is not actually an executable, such as if it is a shell script. */
5696ca2c52aSchristos 
5706ca2c52aSchristos static pid_t
win32_spawn(const char * executable,BOOL search,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)5716ca2c52aSchristos win32_spawn (const char *executable,
5726ca2c52aSchristos 	     BOOL search,
5736ca2c52aSchristos 	     char *const *argv,
5746ca2c52aSchristos              char *const *env, /* array of strings of the form: VAR=VALUE */
5756ca2c52aSchristos 	     DWORD dwCreationFlags,
5766ca2c52aSchristos 	     LPSTARTUPINFO si,
5776ca2c52aSchristos 	     LPPROCESS_INFORMATION pi)
5786ca2c52aSchristos {
5796ca2c52aSchristos   char *full_executable;
5806ca2c52aSchristos   char *cmdline;
5816ca2c52aSchristos   char **env_copy;
5826ca2c52aSchristos   char *env_block = NULL;
5836ca2c52aSchristos 
5846ca2c52aSchristos   full_executable = NULL;
5856ca2c52aSchristos   cmdline = NULL;
5866ca2c52aSchristos 
5876ca2c52aSchristos   if (env)
5886ca2c52aSchristos     {
5896ca2c52aSchristos       int env_size;
5906ca2c52aSchristos 
5916ca2c52aSchristos       /* Count the number of environment bindings supplied.  */
5926ca2c52aSchristos       for (env_size = 0; env[env_size]; env_size++)
5936ca2c52aSchristos         continue;
5946ca2c52aSchristos 
5956ca2c52aSchristos       /* Assemble an environment block, if required.  This consists of
5966ca2c52aSchristos          VAR=VALUE strings juxtaposed (with one null character between each
5976ca2c52aSchristos          pair) and an additional null at the end.  */
5986ca2c52aSchristos       if (env_size > 0)
5996ca2c52aSchristos         {
6006ca2c52aSchristos           int var;
6016ca2c52aSchristos           int total_size = 1; /* 1 is for the final null.  */
6026ca2c52aSchristos           char *bufptr;
6036ca2c52aSchristos 
6046ca2c52aSchristos           /* Windows needs the members of the block to be sorted by variable
6056ca2c52aSchristos              name.  */
6066ca2c52aSchristos           env_copy = (char **) alloca (sizeof (char *) * env_size);
6076ca2c52aSchristos           memcpy (env_copy, env, sizeof (char *) * env_size);
6086ca2c52aSchristos           qsort (env_copy, env_size, sizeof (char *), env_compare);
6096ca2c52aSchristos 
6106ca2c52aSchristos           for (var = 0; var < env_size; var++)
6116ca2c52aSchristos             total_size += strlen (env[var]) + 1;
6126ca2c52aSchristos 
6136ca2c52aSchristos           env_block = XNEWVEC (char, total_size);
6146ca2c52aSchristos           bufptr = env_block;
6156ca2c52aSchristos           for (var = 0; var < env_size; var++)
6166ca2c52aSchristos             bufptr = stpcpy (bufptr, env_copy[var]) + 1;
6176ca2c52aSchristos 
6186ca2c52aSchristos           *bufptr = '\0';
6196ca2c52aSchristos         }
6206ca2c52aSchristos     }
6216ca2c52aSchristos 
6226ca2c52aSchristos   full_executable = find_executable (executable, search);
6236ca2c52aSchristos   if (!full_executable)
6246ca2c52aSchristos     goto error;
6256ca2c52aSchristos   cmdline = argv_to_cmdline (argv);
6266ca2c52aSchristos   if (!cmdline)
6276ca2c52aSchristos     goto error;
6286ca2c52aSchristos 
6296ca2c52aSchristos   /* Create the child process.  */
6306ca2c52aSchristos   if (!CreateProcess (full_executable, cmdline,
6316ca2c52aSchristos 		      /*lpProcessAttributes=*/NULL,
6326ca2c52aSchristos 		      /*lpThreadAttributes=*/NULL,
6336ca2c52aSchristos 		      /*bInheritHandles=*/TRUE,
6346ca2c52aSchristos 		      dwCreationFlags,
6356ca2c52aSchristos 		      (LPVOID) env_block,
6366ca2c52aSchristos 		      /*lpCurrentDirectory=*/NULL,
6376ca2c52aSchristos 		      si,
6386ca2c52aSchristos 		      pi))
6396ca2c52aSchristos     {
6406ca2c52aSchristos       free (env_block);
6416ca2c52aSchristos 
6426ca2c52aSchristos       free (full_executable);
6436ca2c52aSchristos 
6446ca2c52aSchristos       return (pid_t) -1;
6456ca2c52aSchristos     }
6466ca2c52aSchristos 
6476ca2c52aSchristos   /* Clean up.  */
6486ca2c52aSchristos   CloseHandle (pi->hThread);
6496ca2c52aSchristos   free (full_executable);
6506ca2c52aSchristos   free (env_block);
6516ca2c52aSchristos 
6526ca2c52aSchristos   return (pid_t) pi->hProcess;
6536ca2c52aSchristos 
6546ca2c52aSchristos  error:
6556ca2c52aSchristos   free (env_block);
6566ca2c52aSchristos   free (cmdline);
6576ca2c52aSchristos   free (full_executable);
6586ca2c52aSchristos 
6596ca2c52aSchristos   return (pid_t) -1;
6606ca2c52aSchristos }
6616ca2c52aSchristos 
6626ca2c52aSchristos /* Spawn a script.  This simulates the Unix script execution mechanism.
6636ca2c52aSchristos    This function is called as a fallback if win32_spawn fails. */
6646ca2c52aSchristos 
6656ca2c52aSchristos static pid_t
spawn_script(const char * executable,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)6666ca2c52aSchristos spawn_script (const char *executable, char *const *argv,
6676ca2c52aSchristos               char* const *env,
6686ca2c52aSchristos 	      DWORD dwCreationFlags,
6696ca2c52aSchristos 	      LPSTARTUPINFO si,
6706ca2c52aSchristos 	      LPPROCESS_INFORMATION pi)
6716ca2c52aSchristos {
6726ca2c52aSchristos   pid_t pid = (pid_t) -1;
6736ca2c52aSchristos   int save_errno = errno;
6746ca2c52aSchristos   int fd = _open (executable, _O_RDONLY);
6756ca2c52aSchristos 
6766ca2c52aSchristos   /* Try to open script, check header format, extract interpreter path,
6776ca2c52aSchristos      and spawn script using that interpretter. */
6786ca2c52aSchristos   if (fd >= 0)
6796ca2c52aSchristos     {
6806ca2c52aSchristos       char buf[MAX_PATH + 5];
6816ca2c52aSchristos       int len = _read (fd, buf, sizeof (buf) - 1);
6826ca2c52aSchristos       _close (fd);
6836ca2c52aSchristos       if (len > 3)
6846ca2c52aSchristos 	{
6856ca2c52aSchristos 	  char *eol;
6866ca2c52aSchristos 	  buf[len] = '\0';
6876ca2c52aSchristos 	  eol = strchr (buf, '\n');
6886ca2c52aSchristos 	  if (eol && strncmp (buf, "#!", 2) == 0)
6896ca2c52aSchristos 	    {
6906ca2c52aSchristos 
6916ca2c52aSchristos 	      /* Header format is OK. */
6926ca2c52aSchristos 	      char *executable1;
6936ca2c52aSchristos               int new_argc;
6946ca2c52aSchristos               const char **avhere;
6956ca2c52aSchristos 
6966ca2c52aSchristos 	      /* Extract interpreter path. */
6976ca2c52aSchristos 	      do
6986ca2c52aSchristos 		*eol = '\0';
6996ca2c52aSchristos 	      while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
7006ca2c52aSchristos 	      for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
7016ca2c52aSchristos 		continue;
7026ca2c52aSchristos 	      backslashify (executable1);
7036ca2c52aSchristos 
7046ca2c52aSchristos 	      /* Duplicate argv, prepending the interpreter path. */
7056ca2c52aSchristos 	      new_argc = argv_to_argc (argv) + 1;
7066ca2c52aSchristos 	      avhere = XNEWVEC (const char *, new_argc + 1);
7076ca2c52aSchristos 	      *avhere = executable1;
7086ca2c52aSchristos 	      memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
7096ca2c52aSchristos 	      argv = (char *const *)avhere;
7106ca2c52aSchristos 
7116ca2c52aSchristos 	      /* Spawn the child. */
7126ca2c52aSchristos #ifndef USE_MINGW_MSYS
7136ca2c52aSchristos 	      executable = strrchr (executable1, '\\') + 1;
7146ca2c52aSchristos 	      if (!executable)
7156ca2c52aSchristos 		executable = executable1;
7166ca2c52aSchristos 	      pid = win32_spawn (executable, TRUE, argv, env,
7176ca2c52aSchristos 				 dwCreationFlags, si, pi);
7186ca2c52aSchristos #else
7196ca2c52aSchristos 	      if (strchr (executable1, '\\') == NULL)
7206ca2c52aSchristos 		pid = win32_spawn (executable1, TRUE, argv, env,
7216ca2c52aSchristos 				   dwCreationFlags, si, pi);
7226ca2c52aSchristos 	      else if (executable1[0] != '\\')
7236ca2c52aSchristos 		pid = win32_spawn (executable1, FALSE, argv, env,
7246ca2c52aSchristos 				   dwCreationFlags, si, pi);
7256ca2c52aSchristos 	      else
7266ca2c52aSchristos 		{
7276ca2c52aSchristos 		  const char *newex = mingw_rootify (executable1);
7286ca2c52aSchristos 		  *avhere = newex;
7296ca2c52aSchristos 		  pid = win32_spawn (newex, FALSE, argv, env,
7306ca2c52aSchristos 				     dwCreationFlags, si, pi);
7316ca2c52aSchristos 		  if (executable1 != newex)
7326ca2c52aSchristos 		    free ((char *) newex);
7336ca2c52aSchristos 		  if (pid == (pid_t) -1)
7346ca2c52aSchristos 		    {
7356ca2c52aSchristos 		      newex = msys_rootify (executable1);
7366ca2c52aSchristos 		      if (newex != executable1)
7376ca2c52aSchristos 			{
7386ca2c52aSchristos 			  *avhere = newex;
7396ca2c52aSchristos 			  pid = win32_spawn (newex, FALSE, argv, env,
7406ca2c52aSchristos 					     dwCreationFlags, si, pi);
7416ca2c52aSchristos 			  free ((char *) newex);
7426ca2c52aSchristos 			}
7436ca2c52aSchristos 		    }
7446ca2c52aSchristos 		}
7456ca2c52aSchristos #endif
7466ca2c52aSchristos 	      free (avhere);
7476ca2c52aSchristos 	    }
7486ca2c52aSchristos 	}
7496ca2c52aSchristos     }
7506ca2c52aSchristos   if (pid == (pid_t) -1)
7516ca2c52aSchristos     errno = save_errno;
7526ca2c52aSchristos   return pid;
7536ca2c52aSchristos }
7546ca2c52aSchristos 
7556ca2c52aSchristos /* Execute a child.  */
7566ca2c52aSchristos 
7576ca2c52aSchristos static pid_t
pex_win32_exec_child(struct pex_obj * obj ATTRIBUTE_UNUSED,int flags,const char * executable,char * const * argv,char * const * env,int in,int out,int errdes,int toclose ATTRIBUTE_UNUSED,const char ** errmsg,int * err)7586ca2c52aSchristos pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
7596ca2c52aSchristos 		      const char *executable, char * const * argv,
7606ca2c52aSchristos                       char* const* env,
7616ca2c52aSchristos 		      int in, int out, int errdes,
7626ca2c52aSchristos 		      int toclose ATTRIBUTE_UNUSED,
7636ca2c52aSchristos 		      const char **errmsg,
7646ca2c52aSchristos 		      int *err)
7656ca2c52aSchristos {
7666ca2c52aSchristos   pid_t pid;
7676ca2c52aSchristos   HANDLE stdin_handle;
7686ca2c52aSchristos   HANDLE stdout_handle;
7696ca2c52aSchristos   HANDLE stderr_handle;
7706ca2c52aSchristos   DWORD dwCreationFlags;
7716ca2c52aSchristos   OSVERSIONINFO version_info;
7726ca2c52aSchristos   STARTUPINFO si;
7736ca2c52aSchristos   PROCESS_INFORMATION pi;
7746ca2c52aSchristos   int orig_out, orig_in, orig_err;
7756ca2c52aSchristos   BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
7766ca2c52aSchristos 
7776ca2c52aSchristos   /* Ensure we have inheritable descriptors to pass to the child.  */
7786ca2c52aSchristos   orig_in = in;
7796ca2c52aSchristos   in = _dup (orig_in);
7806ca2c52aSchristos 
7816ca2c52aSchristos   orig_out = out;
7826ca2c52aSchristos   out = _dup (orig_out);
7836ca2c52aSchristos 
7846ca2c52aSchristos   if (separate_stderr)
7856ca2c52aSchristos     {
7866ca2c52aSchristos       orig_err = errdes;
7876ca2c52aSchristos       errdes = _dup (orig_err);
7886ca2c52aSchristos     }
7896ca2c52aSchristos 
7906ca2c52aSchristos   stdin_handle = INVALID_HANDLE_VALUE;
7916ca2c52aSchristos   stdout_handle = INVALID_HANDLE_VALUE;
7926ca2c52aSchristos   stderr_handle = INVALID_HANDLE_VALUE;
7936ca2c52aSchristos 
7946ca2c52aSchristos   stdin_handle = (HANDLE) _get_osfhandle (in);
7956ca2c52aSchristos   stdout_handle = (HANDLE) _get_osfhandle (out);
7966ca2c52aSchristos   if (separate_stderr)
7976ca2c52aSchristos     stderr_handle = (HANDLE) _get_osfhandle (errdes);
7986ca2c52aSchristos   else
7996ca2c52aSchristos     stderr_handle = stdout_handle;
8006ca2c52aSchristos 
8016ca2c52aSchristos   /* Determine the version of Windows we are running on.  */
8026ca2c52aSchristos   version_info.dwOSVersionInfoSize = sizeof (version_info);
8036ca2c52aSchristos   GetVersionEx (&version_info);
8046ca2c52aSchristos   if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
8056ca2c52aSchristos     /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
8066ca2c52aSchristos        supported, so we cannot avoid creating a console window.  */
8076ca2c52aSchristos     dwCreationFlags = 0;
8086ca2c52aSchristos   else
8096ca2c52aSchristos     {
8106ca2c52aSchristos       HANDLE conout_handle;
8116ca2c52aSchristos 
8126ca2c52aSchristos       /* Determine whether or not we have an associated console.  */
8136ca2c52aSchristos       conout_handle = CreateFile("CONOUT$",
8146ca2c52aSchristos 				 GENERIC_WRITE,
8156ca2c52aSchristos 				 FILE_SHARE_WRITE,
8166ca2c52aSchristos 				 /*lpSecurityAttributes=*/NULL,
8176ca2c52aSchristos 				 OPEN_EXISTING,
8186ca2c52aSchristos 				 FILE_ATTRIBUTE_NORMAL,
8196ca2c52aSchristos 				 /*hTemplateFile=*/NULL);
8206ca2c52aSchristos       if (conout_handle == INVALID_HANDLE_VALUE)
8216ca2c52aSchristos 	/* There is no console associated with this process.  Since
8226ca2c52aSchristos 	   the child is a console process, the OS would normally
8236ca2c52aSchristos 	   create a new console Window for the child.  Since we'll be
8246ca2c52aSchristos 	   redirecting the child's standard streams, we do not need
8256ca2c52aSchristos 	   the console window.  */
8266ca2c52aSchristos 	dwCreationFlags = CREATE_NO_WINDOW;
8276ca2c52aSchristos       else
8286ca2c52aSchristos 	{
8296ca2c52aSchristos 	  /* There is a console associated with the process, so the OS
8306ca2c52aSchristos 	     will not create a new console.  And, if we use
8316ca2c52aSchristos 	     CREATE_NO_WINDOW in this situation, the child will have
8326ca2c52aSchristos 	     no associated console.  Therefore, if the child's
8336ca2c52aSchristos 	     standard streams are connected to the console, the output
8346ca2c52aSchristos 	     will be discarded.  */
8356ca2c52aSchristos 	  CloseHandle(conout_handle);
8366ca2c52aSchristos 	  dwCreationFlags = 0;
8376ca2c52aSchristos 	}
8386ca2c52aSchristos     }
8396ca2c52aSchristos 
8406ca2c52aSchristos   /* Since the child will be a console process, it will, by default,
8416ca2c52aSchristos      connect standard input/output to its console.  However, we want
8426ca2c52aSchristos      the child to use the handles specifically designated above.  In
8436ca2c52aSchristos      addition, if there is no console (such as when we are running in
8446ca2c52aSchristos      a Cygwin X window), then we must redirect the child's
8456ca2c52aSchristos      input/output, as there is no console for the child to use.  */
8466ca2c52aSchristos   memset (&si, 0, sizeof (si));
8476ca2c52aSchristos   si.cb = sizeof (si);
8486ca2c52aSchristos   si.dwFlags = STARTF_USESTDHANDLES;
8496ca2c52aSchristos   si.hStdInput = stdin_handle;
8506ca2c52aSchristos   si.hStdOutput = stdout_handle;
8516ca2c52aSchristos   si.hStdError = stderr_handle;
8526ca2c52aSchristos 
8536ca2c52aSchristos   /* Create the child process.  */
8546ca2c52aSchristos   pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
8556ca2c52aSchristos 		     argv, env, dwCreationFlags, &si, &pi);
8566ca2c52aSchristos   if (pid == (pid_t) -1)
8576ca2c52aSchristos     pid = spawn_script (executable, argv, env, dwCreationFlags,
8586ca2c52aSchristos                         &si, &pi);
8596ca2c52aSchristos   if (pid == (pid_t) -1)
8606ca2c52aSchristos     {
8616ca2c52aSchristos       *err = ENOENT;
8626ca2c52aSchristos       *errmsg = "CreateProcess";
8636ca2c52aSchristos     }
8646ca2c52aSchristos 
8656ca2c52aSchristos   /* If the child was created successfully, close the original file
8666ca2c52aSchristos      descriptors.  If the process creation fails, these are closed by
8676ca2c52aSchristos      pex_run_in_environment instead.  We must not close them twice as
8686ca2c52aSchristos      that seems to cause a Windows exception.  */
8696ca2c52aSchristos 
8706ca2c52aSchristos   if (pid != (pid_t) -1)
8716ca2c52aSchristos     {
8726ca2c52aSchristos       if (orig_in != STDIN_FILENO)
8736ca2c52aSchristos 	_close (orig_in);
8746ca2c52aSchristos       if (orig_out != STDOUT_FILENO)
8756ca2c52aSchristos 	_close (orig_out);
8766ca2c52aSchristos       if (separate_stderr
8776ca2c52aSchristos 	  && orig_err != STDERR_FILENO)
8786ca2c52aSchristos 	_close (orig_err);
8796ca2c52aSchristos     }
8806ca2c52aSchristos 
8816ca2c52aSchristos   /* Close the standard input, standard output and standard error handles
8826ca2c52aSchristos      in the parent.  */
8836ca2c52aSchristos 
8846ca2c52aSchristos   _close (in);
8856ca2c52aSchristos   _close (out);
8866ca2c52aSchristos   if (separate_stderr)
8876ca2c52aSchristos     _close (errdes);
8886ca2c52aSchristos 
8896ca2c52aSchristos   return pid;
8906ca2c52aSchristos }
8916ca2c52aSchristos 
8926ca2c52aSchristos /* Wait for a child process to complete.  MS CRTDLL doesn't return
8936ca2c52aSchristos    enough information in status to decide if the child exited due to a
8946ca2c52aSchristos    signal or not, rather it simply returns an integer with the exit
8956ca2c52aSchristos    code of the child; eg., if the child exited with an abort() call
8966ca2c52aSchristos    and didn't have a handler for SIGABRT, it simply returns with
8976ca2c52aSchristos    status == 3.  We fix the status code to conform to the usual WIF*
8986ca2c52aSchristos    macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
8996ca2c52aSchristos 
9006ca2c52aSchristos 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)9016ca2c52aSchristos pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
9026ca2c52aSchristos 		int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
9036ca2c52aSchristos 		const char **errmsg, int *err)
9046ca2c52aSchristos {
9056ca2c52aSchristos   DWORD termstat;
9066ca2c52aSchristos   HANDLE h;
9076ca2c52aSchristos 
9086ca2c52aSchristos   if (time != NULL)
9096ca2c52aSchristos     memset (time, 0, sizeof *time);
9106ca2c52aSchristos 
9116ca2c52aSchristos   h = (HANDLE) pid;
9126ca2c52aSchristos 
9136ca2c52aSchristos   /* FIXME: If done is non-zero, we should probably try to kill the
9146ca2c52aSchristos      process.  */
9156ca2c52aSchristos   if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
9166ca2c52aSchristos     {
9176ca2c52aSchristos       CloseHandle (h);
9186ca2c52aSchristos       *err = ECHILD;
9196ca2c52aSchristos       *errmsg = "WaitForSingleObject";
9206ca2c52aSchristos       return -1;
9216ca2c52aSchristos     }
9226ca2c52aSchristos 
9236ca2c52aSchristos   GetExitCodeProcess (h, &termstat);
9246ca2c52aSchristos   CloseHandle (h);
9256ca2c52aSchristos 
9266ca2c52aSchristos   /* A value of 3 indicates that the child caught a signal, but not
9276ca2c52aSchristos      which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
9286ca2c52aSchristos      report SIGABRT.  */
9296ca2c52aSchristos   if (termstat == 3)
9306ca2c52aSchristos     *status = SIGABRT;
9316ca2c52aSchristos   else
9326ca2c52aSchristos     *status = (termstat & 0xff) << 8;
9336ca2c52aSchristos 
9346ca2c52aSchristos   return 0;
9356ca2c52aSchristos }
9366ca2c52aSchristos 
9376ca2c52aSchristos /* Create a pipe.  */
9386ca2c52aSchristos 
9396ca2c52aSchristos static int
pex_win32_pipe(struct pex_obj * obj ATTRIBUTE_UNUSED,int * p,int binary)9406ca2c52aSchristos pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
9416ca2c52aSchristos 		int binary)
9426ca2c52aSchristos {
9436ca2c52aSchristos   return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
9446ca2c52aSchristos }
9456ca2c52aSchristos 
9466ca2c52aSchristos /* Get a FILE pointer to read from a file descriptor.  */
9476ca2c52aSchristos 
9486ca2c52aSchristos static FILE *
pex_win32_fdopenr(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)9496ca2c52aSchristos pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9506ca2c52aSchristos 		   int binary)
9516ca2c52aSchristos {
9526ca2c52aSchristos   HANDLE h = (HANDLE) _get_osfhandle (fd);
9536ca2c52aSchristos   if (h == INVALID_HANDLE_VALUE)
9546ca2c52aSchristos     return NULL;
9556ca2c52aSchristos   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
9566ca2c52aSchristos     return NULL;
9576ca2c52aSchristos   return fdopen (fd, binary ? "rb" : "r");
9586ca2c52aSchristos }
9596ca2c52aSchristos 
9606ca2c52aSchristos static FILE *
pex_win32_fdopenw(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)9616ca2c52aSchristos pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9626ca2c52aSchristos 		   int binary)
9636ca2c52aSchristos {
9646ca2c52aSchristos   HANDLE h = (HANDLE) _get_osfhandle (fd);
9656ca2c52aSchristos   if (h == INVALID_HANDLE_VALUE)
9666ca2c52aSchristos     return NULL;
9676ca2c52aSchristos   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
9686ca2c52aSchristos     return NULL;
9696ca2c52aSchristos   return fdopen (fd, binary ? "wb" : "w");
9706ca2c52aSchristos }
9716ca2c52aSchristos 
9726ca2c52aSchristos #ifdef MAIN
9736ca2c52aSchristos #include <stdio.h>
9746ca2c52aSchristos 
9756ca2c52aSchristos int
main(int argc ATTRIBUTE_UNUSED,char ** argv)9766ca2c52aSchristos main (int argc ATTRIBUTE_UNUSED, char **argv)
9776ca2c52aSchristos {
9786ca2c52aSchristos   char const *errmsg;
9796ca2c52aSchristos   int err;
9806ca2c52aSchristos   argv++;
9816ca2c52aSchristos   printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
9826ca2c52aSchristos   exit (0);
9836ca2c52aSchristos }
9846ca2c52aSchristos #endif
985