12a6b7db3Sskrll /* Utilities to execute a program in a subprocess (possibly linked by pipes
22a6b7db3Sskrll    with other subprocesses), and wait for it.  Generic Win32 specialization.
3*f22f0ef4Schristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
42a6b7db3Sskrll 
52a6b7db3Sskrll This file is part of the libiberty library.
62a6b7db3Sskrll Libiberty is free software; you can redistribute it and/or
72a6b7db3Sskrll modify it under the terms of the GNU Library General Public
82a6b7db3Sskrll License as published by the Free Software Foundation; either
92a6b7db3Sskrll version 2 of the License, or (at your option) any later version.
102a6b7db3Sskrll 
112a6b7db3Sskrll Libiberty is distributed in the hope that it will be useful,
122a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
132a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
142a6b7db3Sskrll Library General Public License for more details.
152a6b7db3Sskrll 
162a6b7db3Sskrll You should have received a copy of the GNU Library General Public
172a6b7db3Sskrll License along with libiberty; see the file COPYING.LIB.  If not,
182a6b7db3Sskrll write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
192a6b7db3Sskrll Boston, MA 02110-1301, USA.  */
202a6b7db3Sskrll 
212a6b7db3Sskrll #include "pex-common.h"
222a6b7db3Sskrll 
232a6b7db3Sskrll #include <windows.h>
242a6b7db3Sskrll 
252a6b7db3Sskrll #ifdef HAVE_STDLIB_H
262a6b7db3Sskrll #include <stdlib.h>
272a6b7db3Sskrll #endif
282a6b7db3Sskrll #ifdef HAVE_STRING_H
292a6b7db3Sskrll #include <string.h>
302a6b7db3Sskrll #endif
312a6b7db3Sskrll #ifdef HAVE_UNISTD_H
322a6b7db3Sskrll #include <unistd.h>
332a6b7db3Sskrll #endif
342a6b7db3Sskrll #ifdef HAVE_SYS_WAIT_H
352a6b7db3Sskrll #include <sys/wait.h>
362a6b7db3Sskrll #endif
372a6b7db3Sskrll 
382a6b7db3Sskrll #include <assert.h>
392a6b7db3Sskrll #include <process.h>
402a6b7db3Sskrll #include <io.h>
412a6b7db3Sskrll #include <fcntl.h>
422a6b7db3Sskrll #include <signal.h>
432a6b7db3Sskrll #include <sys/stat.h>
442a6b7db3Sskrll #include <errno.h>
452a6b7db3Sskrll #include <ctype.h>
462a6b7db3Sskrll 
472a6b7db3Sskrll /* mingw32 headers may not define the following.  */
482a6b7db3Sskrll 
492a6b7db3Sskrll #ifndef _P_WAIT
502a6b7db3Sskrll #  define _P_WAIT	0
512a6b7db3Sskrll #  define _P_NOWAIT	1
522a6b7db3Sskrll #  define _P_OVERLAY	2
532a6b7db3Sskrll #  define _P_NOWAITO	3
542a6b7db3Sskrll #  define _P_DETACH	4
552a6b7db3Sskrll 
562a6b7db3Sskrll #  define WAIT_CHILD		0
572a6b7db3Sskrll #  define WAIT_GRANDCHILD	1
582a6b7db3Sskrll #endif
592a6b7db3Sskrll 
602a6b7db3Sskrll #define MINGW_NAME "Minimalist GNU for Windows"
612a6b7db3Sskrll #define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
622a6b7db3Sskrll 
632a6b7db3Sskrll extern char *stpcpy (char *dst, const char *src);
642a6b7db3Sskrll 
652a6b7db3Sskrll /* Ensure that the executable pathname uses Win32 backslashes. This
662a6b7db3Sskrll    is not necessary on NT, but on W9x, forward slashes causes
672a6b7db3Sskrll    failure of spawn* and exec* functions (and probably any function
682a6b7db3Sskrll    that calls CreateProcess) *iff* the executable pathname (argv[0])
692a6b7db3Sskrll    is a quoted string.  And quoting is necessary in case a pathname
702a6b7db3Sskrll    contains embedded white space.  You can't win.  */
712a6b7db3Sskrll static void
backslashify(char * s)722a6b7db3Sskrll backslashify (char *s)
732a6b7db3Sskrll {
742a6b7db3Sskrll   while ((s = strchr (s, '/')) != NULL)
752a6b7db3Sskrll     *s = '\\';
762a6b7db3Sskrll   return;
772a6b7db3Sskrll }
782a6b7db3Sskrll 
792a6b7db3Sskrll static int pex_win32_open_read (struct pex_obj *, const char *, int);
805ba6b03cSchristos static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
812a6b7db3Sskrll static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
822a6b7db3Sskrll 				  char * const *, char * const *,
832a6b7db3Sskrll                                   int, int, int, int,
842a6b7db3Sskrll 				  const char **, int *);
852a6b7db3Sskrll static int pex_win32_close (struct pex_obj *, int);
86b3ac4aedSchristos static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
872a6b7db3Sskrll 			   struct pex_time *, int, const char **, int *);
882a6b7db3Sskrll static int pex_win32_pipe (struct pex_obj *, int *, int);
892a6b7db3Sskrll static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
902a6b7db3Sskrll static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
912a6b7db3Sskrll 
922a6b7db3Sskrll /* The list of functions we pass to the common routines.  */
932a6b7db3Sskrll 
942a6b7db3Sskrll const struct pex_funcs funcs =
952a6b7db3Sskrll {
962a6b7db3Sskrll   pex_win32_open_read,
972a6b7db3Sskrll   pex_win32_open_write,
982a6b7db3Sskrll   pex_win32_exec_child,
992a6b7db3Sskrll   pex_win32_close,
1002a6b7db3Sskrll   pex_win32_wait,
1012a6b7db3Sskrll   pex_win32_pipe,
1022a6b7db3Sskrll   pex_win32_fdopenr,
1032a6b7db3Sskrll   pex_win32_fdopenw,
1042a6b7db3Sskrll   NULL /* cleanup */
1052a6b7db3Sskrll };
1062a6b7db3Sskrll 
1072a6b7db3Sskrll /* Return a newly initialized pex_obj structure.  */
1082a6b7db3Sskrll 
1092a6b7db3Sskrll struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)1102a6b7db3Sskrll pex_init (int flags, const char *pname, const char *tempbase)
1112a6b7db3Sskrll {
1122a6b7db3Sskrll   return pex_init_common (flags, pname, tempbase, &funcs);
1132a6b7db3Sskrll }
1142a6b7db3Sskrll 
1152a6b7db3Sskrll /* Open a file for reading.  */
1162a6b7db3Sskrll 
1172a6b7db3Sskrll static int
pex_win32_open_read(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary)1182a6b7db3Sskrll pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
1192a6b7db3Sskrll 		     int binary)
1202a6b7db3Sskrll {
1212a6b7db3Sskrll   return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
1222a6b7db3Sskrll }
1232a6b7db3Sskrll 
1242a6b7db3Sskrll /* Open a file for writing.  */
1252a6b7db3Sskrll 
1262a6b7db3Sskrll static int
pex_win32_open_write(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary,int append)1272a6b7db3Sskrll pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
1285ba6b03cSchristos 		      int binary, int append)
1292a6b7db3Sskrll {
1302a6b7db3Sskrll   /* Note that we can't use O_EXCL here because gcc may have already
1312a6b7db3Sskrll      created the temporary file via make_temp_file.  */
1325ba6b03cSchristos   if (append)
1335ba6b03cSchristos     return -1;
1342a6b7db3Sskrll   return _open (name,
1352a6b7db3Sskrll 		(_O_WRONLY | _O_CREAT | _O_TRUNC
1362a6b7db3Sskrll 		 | (binary ? _O_BINARY : _O_TEXT)),
1372a6b7db3Sskrll 		_S_IREAD | _S_IWRITE);
1382a6b7db3Sskrll }
1392a6b7db3Sskrll 
1402a6b7db3Sskrll /* Close a file.  */
1412a6b7db3Sskrll 
1422a6b7db3Sskrll static int
pex_win32_close(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd)1432a6b7db3Sskrll pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
1442a6b7db3Sskrll {
1452a6b7db3Sskrll   return _close (fd);
1462a6b7db3Sskrll }
1472a6b7db3Sskrll 
1482a6b7db3Sskrll #ifdef USE_MINGW_MSYS
1492a6b7db3Sskrll static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
1502a6b7db3Sskrll 
1512a6b7db3Sskrll /* Tack the executable on the end of a (possibly slash terminated) buffer
1522a6b7db3Sskrll    and convert everything to \. */
1532a6b7db3Sskrll static const char *
tack_on_executable(char * buf,const char * executable)1542a6b7db3Sskrll tack_on_executable (char *buf, const char *executable)
1552a6b7db3Sskrll {
1562a6b7db3Sskrll   char *p = strchr (buf, '\0');
1572a6b7db3Sskrll   if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
1582a6b7db3Sskrll     p[-1] = '\0';
1592a6b7db3Sskrll   backslashify (strcat (buf, executable));
1602a6b7db3Sskrll   return buf;
1612a6b7db3Sskrll }
1622a6b7db3Sskrll 
1632a6b7db3Sskrll /* Walk down a registry hierarchy until the end.  Return the key. */
1642a6b7db3Sskrll static HKEY
openkey(HKEY hStart,const char * keys[])1652a6b7db3Sskrll openkey (HKEY hStart, const char *keys[])
1662a6b7db3Sskrll {
1672a6b7db3Sskrll   HKEY hKey, hTmp;
1682a6b7db3Sskrll   for (hKey = hStart; *keys; keys++)
1692a6b7db3Sskrll     {
1702a6b7db3Sskrll       LONG res;
1712a6b7db3Sskrll       hTmp = hKey;
1722a6b7db3Sskrll       res = RegOpenKey (hTmp, *keys, &hKey);
1732a6b7db3Sskrll 
1742a6b7db3Sskrll       if (hTmp != HKEY_LOCAL_MACHINE)
1752a6b7db3Sskrll 	RegCloseKey (hTmp);
1762a6b7db3Sskrll 
1772a6b7db3Sskrll       if (res != ERROR_SUCCESS)
1782a6b7db3Sskrll 	return NULL;
1792a6b7db3Sskrll     }
1802a6b7db3Sskrll   return hKey;
1812a6b7db3Sskrll }
1822a6b7db3Sskrll 
1832a6b7db3Sskrll /* Return the "mingw root" as derived from the mingw uninstall information. */
1842a6b7db3Sskrll static const char *
mingw_rootify(const char * executable)1852a6b7db3Sskrll mingw_rootify (const char *executable)
1862a6b7db3Sskrll {
1872a6b7db3Sskrll   HKEY hKey, hTmp;
1882a6b7db3Sskrll   DWORD maxlen;
1892a6b7db3Sskrll   char *namebuf, *foundbuf;
1902a6b7db3Sskrll   DWORD i;
1912a6b7db3Sskrll   LONG res;
1922a6b7db3Sskrll 
1932a6b7db3Sskrll   /* Open the uninstall "directory". */
1942a6b7db3Sskrll   hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
1952a6b7db3Sskrll 
1962a6b7db3Sskrll   /* Not found. */
1972a6b7db3Sskrll   if (!hKey)
1982a6b7db3Sskrll     return executable;
1992a6b7db3Sskrll 
2002a6b7db3Sskrll   /* Need to enumerate all of the keys here looking for one the most recent
2012a6b7db3Sskrll      one for MinGW. */
2022a6b7db3Sskrll   if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
2032a6b7db3Sskrll 		       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
2042a6b7db3Sskrll     {
2052a6b7db3Sskrll       RegCloseKey (hKey);
2062a6b7db3Sskrll       return executable;
2072a6b7db3Sskrll     }
2082a6b7db3Sskrll   namebuf = XNEWVEC (char, ++maxlen);
2092a6b7db3Sskrll   foundbuf = XNEWVEC (char, maxlen);
2102a6b7db3Sskrll   foundbuf[0] = '\0';
2112a6b7db3Sskrll   if (!namebuf || !foundbuf)
2122a6b7db3Sskrll     {
2132a6b7db3Sskrll       RegCloseKey (hKey);
2142a6b7db3Sskrll       free (namebuf);
2152a6b7db3Sskrll       free (foundbuf);
2162a6b7db3Sskrll       return executable;
2172a6b7db3Sskrll     }
2182a6b7db3Sskrll 
2192a6b7db3Sskrll   /* Look through all of the keys for one that begins with Minimal GNU...
2202a6b7db3Sskrll      Try to get the latest version by doing a string compare although that
2212a6b7db3Sskrll      string never really works with version number sorting. */
2222a6b7db3Sskrll   for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
2232a6b7db3Sskrll     {
2242a6b7db3Sskrll       int match = strcasecmp (namebuf, MINGW_NAME);
2252a6b7db3Sskrll       if (match < 0)
2262a6b7db3Sskrll 	continue;
2272a6b7db3Sskrll       if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
2282a6b7db3Sskrll 	continue;
2292a6b7db3Sskrll       if (strcasecmp (namebuf, foundbuf) > 0)
2302a6b7db3Sskrll 	strcpy (foundbuf, namebuf);
2312a6b7db3Sskrll     }
2322a6b7db3Sskrll   free (namebuf);
2332a6b7db3Sskrll 
2342a6b7db3Sskrll   /* If foundbuf is empty, we didn't find anything.  Punt. */
2352a6b7db3Sskrll   if (!foundbuf[0])
2362a6b7db3Sskrll     {
2372a6b7db3Sskrll       free (foundbuf);
2382a6b7db3Sskrll       RegCloseKey (hKey);
2392a6b7db3Sskrll       return executable;
2402a6b7db3Sskrll     }
2412a6b7db3Sskrll 
2422a6b7db3Sskrll   /* Open the key that we wanted */
2432a6b7db3Sskrll   res = RegOpenKey (hKey, foundbuf, &hTmp);
2442a6b7db3Sskrll   RegCloseKey (hKey);
2452a6b7db3Sskrll   free (foundbuf);
2462a6b7db3Sskrll 
2472a6b7db3Sskrll   /* Don't know why this would fail, but you gotta check */
2482a6b7db3Sskrll   if (res != ERROR_SUCCESS)
2492a6b7db3Sskrll     return executable;
2502a6b7db3Sskrll 
2512a6b7db3Sskrll   maxlen = 0;
2522a6b7db3Sskrll   /* Get the length of the value pointed to by InstallLocation */
2532a6b7db3Sskrll   if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
2542a6b7db3Sskrll 		       &maxlen) != ERROR_SUCCESS || maxlen == 0)
2552a6b7db3Sskrll     {
2562a6b7db3Sskrll       RegCloseKey (hTmp);
2572a6b7db3Sskrll       return executable;
2582a6b7db3Sskrll     }
2592a6b7db3Sskrll 
2602a6b7db3Sskrll   /* Allocate space for the install location */
2612a6b7db3Sskrll   foundbuf = XNEWVEC (char, maxlen + strlen (executable));
2622a6b7db3Sskrll   if (!foundbuf)
2632a6b7db3Sskrll     {
2642a6b7db3Sskrll       free (foundbuf);
2652a6b7db3Sskrll       RegCloseKey (hTmp);
2662a6b7db3Sskrll     }
2672a6b7db3Sskrll 
2682a6b7db3Sskrll   /* Read the install location into the buffer */
2692a6b7db3Sskrll   res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
2702a6b7db3Sskrll 			 &maxlen);
2712a6b7db3Sskrll   RegCloseKey (hTmp);
2722a6b7db3Sskrll   if (res != ERROR_SUCCESS)
2732a6b7db3Sskrll     {
2742a6b7db3Sskrll       free (foundbuf);
2752a6b7db3Sskrll       return executable;
2762a6b7db3Sskrll     }
2772a6b7db3Sskrll 
2782a6b7db3Sskrll   /* Concatenate the install location and the executable, turn all slashes
2792a6b7db3Sskrll      to backslashes, and return that. */
2802a6b7db3Sskrll   return tack_on_executable (foundbuf, executable);
2812a6b7db3Sskrll }
2822a6b7db3Sskrll 
2832a6b7db3Sskrll /* Read the install location of msys from it's installation file and
2842a6b7db3Sskrll    rootify the executable based on that. */
2852a6b7db3Sskrll static const char *
msys_rootify(const char * executable)2862a6b7db3Sskrll msys_rootify (const char *executable)
2872a6b7db3Sskrll {
2882a6b7db3Sskrll   size_t bufsize = 64;
2892a6b7db3Sskrll   size_t execlen = strlen (executable) + 1;
2902a6b7db3Sskrll   char *buf;
2912a6b7db3Sskrll   DWORD res = 0;
2922a6b7db3Sskrll   for (;;)
2932a6b7db3Sskrll     {
2942a6b7db3Sskrll       buf = XNEWVEC (char, bufsize + execlen);
2952a6b7db3Sskrll       if (!buf)
2962a6b7db3Sskrll 	break;
2972a6b7db3Sskrll       res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
2982a6b7db3Sskrll 				     buf, bufsize, "msys.ini");
2992a6b7db3Sskrll       if (!res)
3002a6b7db3Sskrll 	break;
3012a6b7db3Sskrll       if (strlen (buf) < bufsize)
3022a6b7db3Sskrll 	break;
3032a6b7db3Sskrll       res = 0;
3042a6b7db3Sskrll       free (buf);
3052a6b7db3Sskrll       bufsize *= 2;
3062a6b7db3Sskrll       if (bufsize > 65536)
3072a6b7db3Sskrll 	{
3082a6b7db3Sskrll 	  buf = NULL;
3092a6b7db3Sskrll 	  break;
3102a6b7db3Sskrll 	}
3112a6b7db3Sskrll     }
3122a6b7db3Sskrll 
3132a6b7db3Sskrll   if (res)
3142a6b7db3Sskrll     return tack_on_executable (buf, executable);
3152a6b7db3Sskrll 
3162a6b7db3Sskrll   /* failed */
3172a6b7db3Sskrll   free (buf);
3182a6b7db3Sskrll   return executable;
3192a6b7db3Sskrll }
3202a6b7db3Sskrll #endif
3212a6b7db3Sskrll 
3222a6b7db3Sskrll /* Return the number of arguments in an argv array, not including the null
3232a6b7db3Sskrll    terminating argument. */
3242a6b7db3Sskrll 
3252a6b7db3Sskrll static int
argv_to_argc(char * const * argv)3262a6b7db3Sskrll argv_to_argc (char *const *argv)
3272a6b7db3Sskrll {
3282a6b7db3Sskrll   char *const *i = argv;
3292a6b7db3Sskrll   while (*i)
3302a6b7db3Sskrll     i++;
3312a6b7db3Sskrll   return i - argv;
3322a6b7db3Sskrll }
3332a6b7db3Sskrll 
3342a6b7db3Sskrll /* Return a Windows command-line from ARGV.  It is the caller's
3352a6b7db3Sskrll    responsibility to free the string returned.  */
3362a6b7db3Sskrll 
3372a6b7db3Sskrll static char *
argv_to_cmdline(char * const * argv)3382a6b7db3Sskrll argv_to_cmdline (char *const *argv)
3392a6b7db3Sskrll {
3402a6b7db3Sskrll   char *cmdline;
3412a6b7db3Sskrll   char *p;
3422a6b7db3Sskrll   size_t cmdline_len;
3432a6b7db3Sskrll   int i, j, k;
3445ba6b03cSchristos   int needs_quotes;
3452a6b7db3Sskrll 
3462a6b7db3Sskrll   cmdline_len = 0;
3472a6b7db3Sskrll   for (i = 0; argv[i]; i++)
3482a6b7db3Sskrll     {
3495ba6b03cSchristos       /* We only quote arguments that contain spaces, \t or " characters to
3505ba6b03cSchristos 	 prevent wasting 2 chars per argument of the CreateProcess 32k char
3515ba6b03cSchristos 	 limit.  We need only escape embedded double-quotes and immediately
3522a6b7db3Sskrll 	 preceeding backslash characters.  A sequence of backslach characters
3532a6b7db3Sskrll 	 that is not follwed by a double quote character will not be
3542a6b7db3Sskrll 	 escaped.  */
3555ba6b03cSchristos       needs_quotes = 0;
3562a6b7db3Sskrll       for (j = 0; argv[i][j]; j++)
3572a6b7db3Sskrll 	{
3585ba6b03cSchristos 	  if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
3595ba6b03cSchristos 	    {
3605ba6b03cSchristos 	      needs_quotes = 1;
3615ba6b03cSchristos 	    }
3625ba6b03cSchristos 
3632a6b7db3Sskrll 	  if (argv[i][j] == '"')
3642a6b7db3Sskrll 	    {
3652a6b7db3Sskrll 	      /* Escape preceeding backslashes.  */
3662a6b7db3Sskrll 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
3672a6b7db3Sskrll 		cmdline_len++;
3682a6b7db3Sskrll 	      /* Escape the qote character.  */
3692a6b7db3Sskrll 	      cmdline_len++;
3702a6b7db3Sskrll 	    }
3712a6b7db3Sskrll 	}
37298f124a6Schristos       if (j == 0)
37398f124a6Schristos 	needs_quotes = 1;
3742a6b7db3Sskrll       /* Trailing backslashes also need to be escaped because they will be
3752a6b7db3Sskrll          followed by the terminating quote.  */
3765ba6b03cSchristos       if (needs_quotes)
3775ba6b03cSchristos         {
3782a6b7db3Sskrll           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
3792a6b7db3Sskrll             cmdline_len++;
3805ba6b03cSchristos         }
3812a6b7db3Sskrll       cmdline_len += j;
3825ba6b03cSchristos       /* for leading and trailing quotes and space */
3835ba6b03cSchristos       cmdline_len += needs_quotes * 2 + 1;
3842a6b7db3Sskrll     }
3852a6b7db3Sskrll   cmdline = XNEWVEC (char, cmdline_len);
3862a6b7db3Sskrll   p = cmdline;
3872a6b7db3Sskrll   for (i = 0; argv[i]; i++)
3882a6b7db3Sskrll     {
3895ba6b03cSchristos       needs_quotes = 0;
3905ba6b03cSchristos       for (j = 0; argv[i][j]; j++)
3915ba6b03cSchristos         {
3925ba6b03cSchristos           if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
3935ba6b03cSchristos             {
3945ba6b03cSchristos               needs_quotes = 1;
3955ba6b03cSchristos               break;
3965ba6b03cSchristos             }
3975ba6b03cSchristos         }
39898f124a6Schristos       if (j == 0)
39998f124a6Schristos 	needs_quotes = 1;
4005ba6b03cSchristos 
4015ba6b03cSchristos       if (needs_quotes)
4025ba6b03cSchristos         {
4032a6b7db3Sskrll           *p++ = '"';
4045ba6b03cSchristos         }
4052a6b7db3Sskrll       for (j = 0; argv[i][j]; j++)
4062a6b7db3Sskrll 	{
4072a6b7db3Sskrll 	  if (argv[i][j] == '"')
4082a6b7db3Sskrll 	    {
4092a6b7db3Sskrll 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
4102a6b7db3Sskrll 		*p++ = '\\';
4112a6b7db3Sskrll 	      *p++ = '\\';
4122a6b7db3Sskrll 	    }
4132a6b7db3Sskrll 	  *p++ = argv[i][j];
4142a6b7db3Sskrll 	}
4155ba6b03cSchristos       if (needs_quotes)
4165ba6b03cSchristos         {
4172a6b7db3Sskrll           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
4182a6b7db3Sskrll             *p++ = '\\';
4192a6b7db3Sskrll           *p++ = '"';
4205ba6b03cSchristos         }
4212a6b7db3Sskrll       *p++ = ' ';
4222a6b7db3Sskrll     }
4232a6b7db3Sskrll   p[-1] = '\0';
4242a6b7db3Sskrll   return cmdline;
4252a6b7db3Sskrll }
4262a6b7db3Sskrll 
4272a6b7db3Sskrll /* We'll try the passed filename with all the known standard
4282a6b7db3Sskrll    extensions, and then without extension.  We try no extension
4292a6b7db3Sskrll    last so that we don't try to run some random extension-less
4302a6b7db3Sskrll    file that might be hanging around.  We try both extension
4312a6b7db3Sskrll    and no extension so that we don't need any fancy logic
4322a6b7db3Sskrll    to determine if a file has extension.  */
4332a6b7db3Sskrll static const char *const
4342a6b7db3Sskrll std_suffixes[] = {
4352a6b7db3Sskrll   ".com",
4362a6b7db3Sskrll   ".exe",
4372a6b7db3Sskrll   ".bat",
4382a6b7db3Sskrll   ".cmd",
4392a6b7db3Sskrll   "",
4402a6b7db3Sskrll   0
4412a6b7db3Sskrll };
4422a6b7db3Sskrll 
4432a6b7db3Sskrll /* Returns the full path to PROGRAM.  If SEARCH is true, look for
4442a6b7db3Sskrll    PROGRAM in each directory in PATH.  */
4452a6b7db3Sskrll 
4462a6b7db3Sskrll static char *
find_executable(const char * program,BOOL search)4472a6b7db3Sskrll find_executable (const char *program, BOOL search)
4482a6b7db3Sskrll {
4492a6b7db3Sskrll   char *full_executable;
4502a6b7db3Sskrll   char *e;
4512a6b7db3Sskrll   size_t fe_len;
4522a6b7db3Sskrll   const char *path = 0;
4532a6b7db3Sskrll   const char *const *ext;
4542a6b7db3Sskrll   const char *p, *q;
4552a6b7db3Sskrll   size_t proglen = strlen (program);
4562a6b7db3Sskrll   int has_slash = (strchr (program, '/') || strchr (program, '\\'));
4572a6b7db3Sskrll   HANDLE h;
4582a6b7db3Sskrll 
4592a6b7db3Sskrll   if (has_slash)
4602a6b7db3Sskrll     search = FALSE;
4612a6b7db3Sskrll 
4622a6b7db3Sskrll   if (search)
4632a6b7db3Sskrll     path = getenv ("PATH");
4642a6b7db3Sskrll   if (!path)
4652a6b7db3Sskrll     path = "";
4662a6b7db3Sskrll 
4672a6b7db3Sskrll   fe_len = 0;
4682a6b7db3Sskrll   for (p = path; *p; p = q)
4692a6b7db3Sskrll     {
4702a6b7db3Sskrll       q = p;
4712a6b7db3Sskrll       while (*q != ';' && *q != '\0')
4722a6b7db3Sskrll 	q++;
4732a6b7db3Sskrll       if ((size_t)(q - p) > fe_len)
4742a6b7db3Sskrll 	fe_len = q - p;
4752a6b7db3Sskrll       if (*q == ';')
4762a6b7db3Sskrll 	q++;
4772a6b7db3Sskrll     }
4782a6b7db3Sskrll   fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
4792a6b7db3Sskrll   full_executable = XNEWVEC (char, fe_len);
4802a6b7db3Sskrll 
4812a6b7db3Sskrll   p = path;
4822a6b7db3Sskrll   do
4832a6b7db3Sskrll     {
4842a6b7db3Sskrll       q = p;
4852a6b7db3Sskrll       while (*q != ';' && *q != '\0')
4862a6b7db3Sskrll 	q++;
4872a6b7db3Sskrll 
4882a6b7db3Sskrll       e = full_executable;
4892a6b7db3Sskrll       memcpy (e, p, q - p);
4902a6b7db3Sskrll       e += (q - p);
4912a6b7db3Sskrll       if (q - p)
4922a6b7db3Sskrll 	*e++ = '\\';
4932a6b7db3Sskrll       strcpy (e, program);
4942a6b7db3Sskrll 
4952a6b7db3Sskrll       if (*q == ';')
4962a6b7db3Sskrll 	q++;
4972a6b7db3Sskrll 
4982a6b7db3Sskrll       for (e = full_executable; *e; e++)
4992a6b7db3Sskrll 	if (*e == '/')
5002a6b7db3Sskrll 	  *e = '\\';
5012a6b7db3Sskrll 
5022a6b7db3Sskrll       /* At this point, e points to the terminating NUL character for
5032a6b7db3Sskrll          full_executable.  */
5042a6b7db3Sskrll       for (ext = std_suffixes; *ext; ext++)
5052a6b7db3Sskrll 	{
5062a6b7db3Sskrll 	  /* Remove any current extension.  */
5072a6b7db3Sskrll 	  *e = '\0';
5082a6b7db3Sskrll 	  /* Add the new one.  */
5092a6b7db3Sskrll 	  strcat (full_executable, *ext);
5102a6b7db3Sskrll 
5112a6b7db3Sskrll 	  /* Attempt to open this file.  */
5122a6b7db3Sskrll 	  h = CreateFile (full_executable, GENERIC_READ,
5132a6b7db3Sskrll 			  FILE_SHARE_READ | FILE_SHARE_WRITE,
5142a6b7db3Sskrll 			  0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
5152a6b7db3Sskrll 	  if (h != INVALID_HANDLE_VALUE)
5162a6b7db3Sskrll 	    goto found;
5172a6b7db3Sskrll 	}
5182a6b7db3Sskrll       p = q;
5192a6b7db3Sskrll     }
5202a6b7db3Sskrll   while (*p);
5212a6b7db3Sskrll   free (full_executable);
5222a6b7db3Sskrll   return 0;
5232a6b7db3Sskrll 
5242a6b7db3Sskrll  found:
5252a6b7db3Sskrll   CloseHandle (h);
5262a6b7db3Sskrll   return full_executable;
5272a6b7db3Sskrll }
5282a6b7db3Sskrll 
5292a6b7db3Sskrll /* Low-level process creation function and helper.  */
5302a6b7db3Sskrll 
5312a6b7db3Sskrll static int
env_compare(const void * a_ptr,const void * b_ptr)5322a6b7db3Sskrll env_compare (const void *a_ptr, const void *b_ptr)
5332a6b7db3Sskrll {
5342a6b7db3Sskrll   const char *a;
5352a6b7db3Sskrll   const char *b;
5362a6b7db3Sskrll   unsigned char c1;
5372a6b7db3Sskrll   unsigned char c2;
5382a6b7db3Sskrll 
5392a6b7db3Sskrll   a = *(const char **) a_ptr;
5402a6b7db3Sskrll   b = *(const char **) b_ptr;
5412a6b7db3Sskrll 
5422a6b7db3Sskrll   /* a and b will be of the form: VAR=VALUE
5432a6b7db3Sskrll      We compare only the variable name part here using a case-insensitive
5442a6b7db3Sskrll      comparison algorithm.  It might appear that in fact strcasecmp () can
5452a6b7db3Sskrll      take the place of this whole function, and indeed it could, save for
5462a6b7db3Sskrll      the fact that it would fail in cases such as comparing A1=foo and
5472a6b7db3Sskrll      A=bar (because 1 is less than = in the ASCII character set).
5482a6b7db3Sskrll      (Environment variables containing no numbers would work in such a
5492a6b7db3Sskrll      scenario.)  */
5502a6b7db3Sskrll 
5512a6b7db3Sskrll   do
5522a6b7db3Sskrll     {
5532a6b7db3Sskrll       c1 = (unsigned char) tolower (*a++);
5542a6b7db3Sskrll       c2 = (unsigned char) tolower (*b++);
5552a6b7db3Sskrll 
5562a6b7db3Sskrll       if (c1 == '=')
5572a6b7db3Sskrll         c1 = '\0';
5582a6b7db3Sskrll 
5592a6b7db3Sskrll       if (c2 == '=')
5602a6b7db3Sskrll         c2 = '\0';
5612a6b7db3Sskrll     }
5622a6b7db3Sskrll   while (c1 == c2 && c1 != '\0');
5632a6b7db3Sskrll 
5642a6b7db3Sskrll   return c1 - c2;
5652a6b7db3Sskrll }
5662a6b7db3Sskrll 
5672a6b7db3Sskrll /* Execute a Windows executable as a child process.  This will fail if the
5682a6b7db3Sskrll  * target is not actually an executable, such as if it is a shell script. */
5692a6b7db3Sskrll 
5702a6b7db3Sskrll static pid_t
win32_spawn(const char * executable,BOOL search,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)5712a6b7db3Sskrll win32_spawn (const char *executable,
5722a6b7db3Sskrll 	     BOOL search,
5732a6b7db3Sskrll 	     char *const *argv,
5742a6b7db3Sskrll              char *const *env, /* array of strings of the form: VAR=VALUE */
5752a6b7db3Sskrll 	     DWORD dwCreationFlags,
5762a6b7db3Sskrll 	     LPSTARTUPINFO si,
5772a6b7db3Sskrll 	     LPPROCESS_INFORMATION pi)
5782a6b7db3Sskrll {
5792a6b7db3Sskrll   char *full_executable;
5802a6b7db3Sskrll   char *cmdline;
5812a6b7db3Sskrll   char **env_copy;
5822a6b7db3Sskrll   char *env_block = NULL;
5832a6b7db3Sskrll 
5842a6b7db3Sskrll   full_executable = NULL;
5852a6b7db3Sskrll   cmdline = NULL;
5862a6b7db3Sskrll 
5872a6b7db3Sskrll   if (env)
5882a6b7db3Sskrll     {
5892a6b7db3Sskrll       int env_size;
5902a6b7db3Sskrll 
5912a6b7db3Sskrll       /* Count the number of environment bindings supplied.  */
5922a6b7db3Sskrll       for (env_size = 0; env[env_size]; env_size++)
5932a6b7db3Sskrll         continue;
5942a6b7db3Sskrll 
5952a6b7db3Sskrll       /* Assemble an environment block, if required.  This consists of
5962a6b7db3Sskrll          VAR=VALUE strings juxtaposed (with one null character between each
5972a6b7db3Sskrll          pair) and an additional null at the end.  */
5982a6b7db3Sskrll       if (env_size > 0)
5992a6b7db3Sskrll         {
6002a6b7db3Sskrll           int var;
6012a6b7db3Sskrll           int total_size = 1; /* 1 is for the final null.  */
6022a6b7db3Sskrll           char *bufptr;
6032a6b7db3Sskrll 
6042a6b7db3Sskrll           /* Windows needs the members of the block to be sorted by variable
6052a6b7db3Sskrll              name.  */
6062a6b7db3Sskrll           env_copy = (char **) alloca (sizeof (char *) * env_size);
6072a6b7db3Sskrll           memcpy (env_copy, env, sizeof (char *) * env_size);
6082a6b7db3Sskrll           qsort (env_copy, env_size, sizeof (char *), env_compare);
6092a6b7db3Sskrll 
6102a6b7db3Sskrll           for (var = 0; var < env_size; var++)
6112a6b7db3Sskrll             total_size += strlen (env[var]) + 1;
6122a6b7db3Sskrll 
6132a6b7db3Sskrll           env_block = XNEWVEC (char, total_size);
6142a6b7db3Sskrll           bufptr = env_block;
6152a6b7db3Sskrll           for (var = 0; var < env_size; var++)
6162a6b7db3Sskrll             bufptr = stpcpy (bufptr, env_copy[var]) + 1;
6172a6b7db3Sskrll 
6182a6b7db3Sskrll           *bufptr = '\0';
6192a6b7db3Sskrll         }
6202a6b7db3Sskrll     }
6212a6b7db3Sskrll 
6222a6b7db3Sskrll   full_executable = find_executable (executable, search);
6232a6b7db3Sskrll   if (!full_executable)
6242a6b7db3Sskrll     goto error;
6252a6b7db3Sskrll   cmdline = argv_to_cmdline (argv);
6262a6b7db3Sskrll   if (!cmdline)
6272a6b7db3Sskrll     goto error;
6282a6b7db3Sskrll 
6292a6b7db3Sskrll   /* Create the child process.  */
6302a6b7db3Sskrll   if (!CreateProcess (full_executable, cmdline,
6312a6b7db3Sskrll 		      /*lpProcessAttributes=*/NULL,
6322a6b7db3Sskrll 		      /*lpThreadAttributes=*/NULL,
6332a6b7db3Sskrll 		      /*bInheritHandles=*/TRUE,
6342a6b7db3Sskrll 		      dwCreationFlags,
6352a6b7db3Sskrll 		      (LPVOID) env_block,
6362a6b7db3Sskrll 		      /*lpCurrentDirectory=*/NULL,
6372a6b7db3Sskrll 		      si,
6382a6b7db3Sskrll 		      pi))
6392a6b7db3Sskrll     {
6402a6b7db3Sskrll       free (env_block);
6412a6b7db3Sskrll 
6422a6b7db3Sskrll       free (full_executable);
6432a6b7db3Sskrll 
6442a6b7db3Sskrll       return (pid_t) -1;
6452a6b7db3Sskrll     }
6462a6b7db3Sskrll 
6472a6b7db3Sskrll   /* Clean up.  */
6482a6b7db3Sskrll   CloseHandle (pi->hThread);
6492a6b7db3Sskrll   free (full_executable);
6502a6b7db3Sskrll   free (env_block);
6512a6b7db3Sskrll 
6522a6b7db3Sskrll   return (pid_t) pi->hProcess;
6532a6b7db3Sskrll 
6542a6b7db3Sskrll  error:
6552a6b7db3Sskrll   free (env_block);
6562a6b7db3Sskrll   free (cmdline);
6572a6b7db3Sskrll   free (full_executable);
6582a6b7db3Sskrll 
6592a6b7db3Sskrll   return (pid_t) -1;
6602a6b7db3Sskrll }
6612a6b7db3Sskrll 
6622a6b7db3Sskrll /* Spawn a script.  This simulates the Unix script execution mechanism.
6632a6b7db3Sskrll    This function is called as a fallback if win32_spawn fails. */
6642a6b7db3Sskrll 
6652a6b7db3Sskrll static pid_t
spawn_script(const char * executable,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)6662a6b7db3Sskrll spawn_script (const char *executable, char *const *argv,
6672a6b7db3Sskrll               char* const *env,
6682a6b7db3Sskrll 	      DWORD dwCreationFlags,
6692a6b7db3Sskrll 	      LPSTARTUPINFO si,
6702a6b7db3Sskrll 	      LPPROCESS_INFORMATION pi)
6712a6b7db3Sskrll {
6722a6b7db3Sskrll   pid_t pid = (pid_t) -1;
6732a6b7db3Sskrll   int save_errno = errno;
6742a6b7db3Sskrll   int fd = _open (executable, _O_RDONLY);
6752a6b7db3Sskrll 
6762a6b7db3Sskrll   /* Try to open script, check header format, extract interpreter path,
6772a6b7db3Sskrll      and spawn script using that interpretter. */
6782a6b7db3Sskrll   if (fd >= 0)
6792a6b7db3Sskrll     {
6802a6b7db3Sskrll       char buf[MAX_PATH + 5];
6812a6b7db3Sskrll       int len = _read (fd, buf, sizeof (buf) - 1);
6822a6b7db3Sskrll       _close (fd);
6832a6b7db3Sskrll       if (len > 3)
6842a6b7db3Sskrll 	{
6852a6b7db3Sskrll 	  char *eol;
6862a6b7db3Sskrll 	  buf[len] = '\0';
6872a6b7db3Sskrll 	  eol = strchr (buf, '\n');
6882a6b7db3Sskrll 	  if (eol && strncmp (buf, "#!", 2) == 0)
6892a6b7db3Sskrll 	    {
6902a6b7db3Sskrll 
6912a6b7db3Sskrll 	      /* Header format is OK. */
6922a6b7db3Sskrll 	      char *executable1;
6932a6b7db3Sskrll               int new_argc;
6942a6b7db3Sskrll               const char **avhere;
6952a6b7db3Sskrll 
6962a6b7db3Sskrll 	      /* Extract interpreter path. */
6972a6b7db3Sskrll 	      do
6982a6b7db3Sskrll 		*eol = '\0';
6992a6b7db3Sskrll 	      while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
7002a6b7db3Sskrll 	      for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
7012a6b7db3Sskrll 		continue;
7022a6b7db3Sskrll 	      backslashify (executable1);
7032a6b7db3Sskrll 
7042a6b7db3Sskrll 	      /* Duplicate argv, prepending the interpreter path. */
7052a6b7db3Sskrll 	      new_argc = argv_to_argc (argv) + 1;
7062a6b7db3Sskrll 	      avhere = XNEWVEC (const char *, new_argc + 1);
7072a6b7db3Sskrll 	      *avhere = executable1;
7082a6b7db3Sskrll 	      memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
7092a6b7db3Sskrll 	      argv = (char *const *)avhere;
7102a6b7db3Sskrll 
7112a6b7db3Sskrll 	      /* Spawn the child. */
7122a6b7db3Sskrll #ifndef USE_MINGW_MSYS
7132a6b7db3Sskrll 	      executable = strrchr (executable1, '\\') + 1;
7142a6b7db3Sskrll 	      if (!executable)
7152a6b7db3Sskrll 		executable = executable1;
7162a6b7db3Sskrll 	      pid = win32_spawn (executable, TRUE, argv, env,
7172a6b7db3Sskrll 				 dwCreationFlags, si, pi);
7182a6b7db3Sskrll #else
7192a6b7db3Sskrll 	      if (strchr (executable1, '\\') == NULL)
7202a6b7db3Sskrll 		pid = win32_spawn (executable1, TRUE, argv, env,
7212a6b7db3Sskrll 				   dwCreationFlags, si, pi);
7222a6b7db3Sskrll 	      else if (executable1[0] != '\\')
7232a6b7db3Sskrll 		pid = win32_spawn (executable1, FALSE, argv, env,
7242a6b7db3Sskrll 				   dwCreationFlags, si, pi);
7252a6b7db3Sskrll 	      else
7262a6b7db3Sskrll 		{
7272a6b7db3Sskrll 		  const char *newex = mingw_rootify (executable1);
7282a6b7db3Sskrll 		  *avhere = newex;
7292a6b7db3Sskrll 		  pid = win32_spawn (newex, FALSE, argv, env,
7302a6b7db3Sskrll 				     dwCreationFlags, si, pi);
7312a6b7db3Sskrll 		  if (executable1 != newex)
7322a6b7db3Sskrll 		    free ((char *) newex);
733b3ac4aedSchristos 		  if (pid == (pid_t) -1)
7342a6b7db3Sskrll 		    {
7352a6b7db3Sskrll 		      newex = msys_rootify (executable1);
7362a6b7db3Sskrll 		      if (newex != executable1)
7372a6b7db3Sskrll 			{
7382a6b7db3Sskrll 			  *avhere = newex;
7392a6b7db3Sskrll 			  pid = win32_spawn (newex, FALSE, argv, env,
7402a6b7db3Sskrll 					     dwCreationFlags, si, pi);
7412a6b7db3Sskrll 			  free ((char *) newex);
7422a6b7db3Sskrll 			}
7432a6b7db3Sskrll 		    }
7442a6b7db3Sskrll 		}
7452a6b7db3Sskrll #endif
7462a6b7db3Sskrll 	      free (avhere);
7472a6b7db3Sskrll 	    }
7482a6b7db3Sskrll 	}
7492a6b7db3Sskrll     }
750b3ac4aedSchristos   if (pid == (pid_t) -1)
7512a6b7db3Sskrll     errno = save_errno;
7522a6b7db3Sskrll   return pid;
7532a6b7db3Sskrll }
7542a6b7db3Sskrll 
7552a6b7db3Sskrll /* Execute a child.  */
7562a6b7db3Sskrll 
7572a6b7db3Sskrll 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)7582a6b7db3Sskrll pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
7592a6b7db3Sskrll 		      const char *executable, char * const * argv,
7602a6b7db3Sskrll                       char* const* env,
7612a6b7db3Sskrll 		      int in, int out, int errdes,
7622a6b7db3Sskrll 		      int toclose ATTRIBUTE_UNUSED,
7632a6b7db3Sskrll 		      const char **errmsg,
7642a6b7db3Sskrll 		      int *err)
7652a6b7db3Sskrll {
7662a6b7db3Sskrll   pid_t pid;
7672a6b7db3Sskrll   HANDLE stdin_handle;
7682a6b7db3Sskrll   HANDLE stdout_handle;
7692a6b7db3Sskrll   HANDLE stderr_handle;
7702a6b7db3Sskrll   DWORD dwCreationFlags;
7712a6b7db3Sskrll   OSVERSIONINFO version_info;
7722a6b7db3Sskrll   STARTUPINFO si;
7732a6b7db3Sskrll   PROCESS_INFORMATION pi;
774*f22f0ef4Schristos   int orig_out, orig_in, orig_err = 0;
775b3ac4aedSchristos   BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
776b3ac4aedSchristos 
77705caefcfSchristos   /* Ensure we have inheritable descriptors to pass to the child.  */
778b3ac4aedSchristos   orig_in = in;
779b3ac4aedSchristos   in = _dup (orig_in);
780b3ac4aedSchristos 
781b3ac4aedSchristos   orig_out = out;
782b3ac4aedSchristos   out = _dup (orig_out);
783b3ac4aedSchristos 
784b3ac4aedSchristos   if (separate_stderr)
785b3ac4aedSchristos     {
786b3ac4aedSchristos       orig_err = errdes;
787b3ac4aedSchristos       errdes = _dup (orig_err);
788b3ac4aedSchristos     }
7892a6b7db3Sskrll 
7902a6b7db3Sskrll   stdin_handle = INVALID_HANDLE_VALUE;
7912a6b7db3Sskrll   stdout_handle = INVALID_HANDLE_VALUE;
7922a6b7db3Sskrll   stderr_handle = INVALID_HANDLE_VALUE;
7932a6b7db3Sskrll 
7942a6b7db3Sskrll   stdin_handle = (HANDLE) _get_osfhandle (in);
7952a6b7db3Sskrll   stdout_handle = (HANDLE) _get_osfhandle (out);
796b3ac4aedSchristos   if (separate_stderr)
7972a6b7db3Sskrll     stderr_handle = (HANDLE) _get_osfhandle (errdes);
7982a6b7db3Sskrll   else
7992a6b7db3Sskrll     stderr_handle = stdout_handle;
8002a6b7db3Sskrll 
8012a6b7db3Sskrll   /* Determine the version of Windows we are running on.  */
8022a6b7db3Sskrll   version_info.dwOSVersionInfoSize = sizeof (version_info);
8032a6b7db3Sskrll   GetVersionEx (&version_info);
8042a6b7db3Sskrll   if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
8052a6b7db3Sskrll     /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
8062a6b7db3Sskrll        supported, so we cannot avoid creating a console window.  */
8072a6b7db3Sskrll     dwCreationFlags = 0;
8082a6b7db3Sskrll   else
8092a6b7db3Sskrll     {
8102a6b7db3Sskrll       HANDLE conout_handle;
8112a6b7db3Sskrll 
8122a6b7db3Sskrll       /* Determine whether or not we have an associated console.  */
8132a6b7db3Sskrll       conout_handle = CreateFile("CONOUT$",
8142a6b7db3Sskrll 				 GENERIC_WRITE,
8152a6b7db3Sskrll 				 FILE_SHARE_WRITE,
8162a6b7db3Sskrll 				 /*lpSecurityAttributes=*/NULL,
8172a6b7db3Sskrll 				 OPEN_EXISTING,
8182a6b7db3Sskrll 				 FILE_ATTRIBUTE_NORMAL,
8192a6b7db3Sskrll 				 /*hTemplateFile=*/NULL);
8202a6b7db3Sskrll       if (conout_handle == INVALID_HANDLE_VALUE)
8212a6b7db3Sskrll 	/* There is no console associated with this process.  Since
8222a6b7db3Sskrll 	   the child is a console process, the OS would normally
8232a6b7db3Sskrll 	   create a new console Window for the child.  Since we'll be
8242a6b7db3Sskrll 	   redirecting the child's standard streams, we do not need
8252a6b7db3Sskrll 	   the console window.  */
8262a6b7db3Sskrll 	dwCreationFlags = CREATE_NO_WINDOW;
8272a6b7db3Sskrll       else
8282a6b7db3Sskrll 	{
8292a6b7db3Sskrll 	  /* There is a console associated with the process, so the OS
8302a6b7db3Sskrll 	     will not create a new console.  And, if we use
8312a6b7db3Sskrll 	     CREATE_NO_WINDOW in this situation, the child will have
8322a6b7db3Sskrll 	     no associated console.  Therefore, if the child's
8332a6b7db3Sskrll 	     standard streams are connected to the console, the output
8342a6b7db3Sskrll 	     will be discarded.  */
8352a6b7db3Sskrll 	  CloseHandle(conout_handle);
8362a6b7db3Sskrll 	  dwCreationFlags = 0;
8372a6b7db3Sskrll 	}
8382a6b7db3Sskrll     }
8392a6b7db3Sskrll 
8402a6b7db3Sskrll   /* Since the child will be a console process, it will, by default,
8412a6b7db3Sskrll      connect standard input/output to its console.  However, we want
8422a6b7db3Sskrll      the child to use the handles specifically designated above.  In
8432a6b7db3Sskrll      addition, if there is no console (such as when we are running in
8442a6b7db3Sskrll      a Cygwin X window), then we must redirect the child's
8452a6b7db3Sskrll      input/output, as there is no console for the child to use.  */
8462a6b7db3Sskrll   memset (&si, 0, sizeof (si));
8472a6b7db3Sskrll   si.cb = sizeof (si);
8482a6b7db3Sskrll   si.dwFlags = STARTF_USESTDHANDLES;
8492a6b7db3Sskrll   si.hStdInput = stdin_handle;
8502a6b7db3Sskrll   si.hStdOutput = stdout_handle;
8512a6b7db3Sskrll   si.hStdError = stderr_handle;
8522a6b7db3Sskrll 
8532a6b7db3Sskrll   /* Create the child process.  */
8542a6b7db3Sskrll   pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
8552a6b7db3Sskrll 		     argv, env, dwCreationFlags, &si, &pi);
8562a6b7db3Sskrll   if (pid == (pid_t) -1)
8572a6b7db3Sskrll     pid = spawn_script (executable, argv, env, dwCreationFlags,
8582a6b7db3Sskrll                         &si, &pi);
8592a6b7db3Sskrll   if (pid == (pid_t) -1)
8602a6b7db3Sskrll     {
8612a6b7db3Sskrll       *err = ENOENT;
8622a6b7db3Sskrll       *errmsg = "CreateProcess";
8632a6b7db3Sskrll     }
8642a6b7db3Sskrll 
86505caefcfSchristos   /* If the child was created successfully, close the original file
86605caefcfSchristos      descriptors.  If the process creation fails, these are closed by
86705caefcfSchristos      pex_run_in_environment instead.  We must not close them twice as
86805caefcfSchristos      that seems to cause a Windows exception.  */
86905caefcfSchristos 
87005caefcfSchristos   if (pid != (pid_t) -1)
87105caefcfSchristos     {
87205caefcfSchristos       if (orig_in != STDIN_FILENO)
87305caefcfSchristos 	_close (orig_in);
87405caefcfSchristos       if (orig_out != STDOUT_FILENO)
87505caefcfSchristos 	_close (orig_out);
87605caefcfSchristos       if (separate_stderr
87705caefcfSchristos 	  && orig_err != STDERR_FILENO)
87805caefcfSchristos 	_close (orig_err);
87905caefcfSchristos     }
88005caefcfSchristos 
881b3ac4aedSchristos   /* Close the standard input, standard output and standard error handles
882b3ac4aedSchristos      in the parent.  */
883b3ac4aedSchristos 
884b3ac4aedSchristos   _close (in);
885b3ac4aedSchristos   _close (out);
886b3ac4aedSchristos   if (separate_stderr)
887b3ac4aedSchristos     _close (errdes);
8882a6b7db3Sskrll 
8892a6b7db3Sskrll   return pid;
8902a6b7db3Sskrll }
8912a6b7db3Sskrll 
8922a6b7db3Sskrll /* Wait for a child process to complete.  MS CRTDLL doesn't return
8932a6b7db3Sskrll    enough information in status to decide if the child exited due to a
8942a6b7db3Sskrll    signal or not, rather it simply returns an integer with the exit
8952a6b7db3Sskrll    code of the child; eg., if the child exited with an abort() call
8962a6b7db3Sskrll    and didn't have a handler for SIGABRT, it simply returns with
8972a6b7db3Sskrll    status == 3.  We fix the status code to conform to the usual WIF*
8982a6b7db3Sskrll    macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
8992a6b7db3Sskrll 
900b3ac4aedSchristos 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)9012a6b7db3Sskrll pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
9022a6b7db3Sskrll 		int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
9032a6b7db3Sskrll 		const char **errmsg, int *err)
9042a6b7db3Sskrll {
9052a6b7db3Sskrll   DWORD termstat;
9062a6b7db3Sskrll   HANDLE h;
9072a6b7db3Sskrll 
9082a6b7db3Sskrll   if (time != NULL)
9092a6b7db3Sskrll     memset (time, 0, sizeof *time);
9102a6b7db3Sskrll 
9112a6b7db3Sskrll   h = (HANDLE) pid;
9122a6b7db3Sskrll 
9132a6b7db3Sskrll   /* FIXME: If done is non-zero, we should probably try to kill the
9142a6b7db3Sskrll      process.  */
9152a6b7db3Sskrll   if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
9162a6b7db3Sskrll     {
9172a6b7db3Sskrll       CloseHandle (h);
9182a6b7db3Sskrll       *err = ECHILD;
9192a6b7db3Sskrll       *errmsg = "WaitForSingleObject";
9202a6b7db3Sskrll       return -1;
9212a6b7db3Sskrll     }
9222a6b7db3Sskrll 
9232a6b7db3Sskrll   GetExitCodeProcess (h, &termstat);
9242a6b7db3Sskrll   CloseHandle (h);
9252a6b7db3Sskrll 
9262a6b7db3Sskrll   /* A value of 3 indicates that the child caught a signal, but not
9272a6b7db3Sskrll      which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
9282a6b7db3Sskrll      report SIGABRT.  */
9292a6b7db3Sskrll   if (termstat == 3)
9302a6b7db3Sskrll     *status = SIGABRT;
9312a6b7db3Sskrll   else
9322a6b7db3Sskrll     *status = (termstat & 0xff) << 8;
9332a6b7db3Sskrll 
9342a6b7db3Sskrll   return 0;
9352a6b7db3Sskrll }
9362a6b7db3Sskrll 
9372a6b7db3Sskrll /* Create a pipe.  */
9382a6b7db3Sskrll 
9392a6b7db3Sskrll static int
pex_win32_pipe(struct pex_obj * obj ATTRIBUTE_UNUSED,int * p,int binary)9402a6b7db3Sskrll pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
9412a6b7db3Sskrll 		int binary)
9422a6b7db3Sskrll {
943b3ac4aedSchristos   return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
9442a6b7db3Sskrll }
9452a6b7db3Sskrll 
9462a6b7db3Sskrll /* Get a FILE pointer to read from a file descriptor.  */
9472a6b7db3Sskrll 
9482a6b7db3Sskrll static FILE *
pex_win32_fdopenr(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)9492a6b7db3Sskrll pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9502a6b7db3Sskrll 		   int binary)
9512a6b7db3Sskrll {
952b3ac4aedSchristos   HANDLE h = (HANDLE) _get_osfhandle (fd);
953b3ac4aedSchristos   if (h == INVALID_HANDLE_VALUE)
954b3ac4aedSchristos     return NULL;
955b3ac4aedSchristos   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
956b3ac4aedSchristos     return NULL;
9572a6b7db3Sskrll   return fdopen (fd, binary ? "rb" : "r");
9582a6b7db3Sskrll }
9592a6b7db3Sskrll 
9602a6b7db3Sskrll static FILE *
pex_win32_fdopenw(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)9612a6b7db3Sskrll pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9622a6b7db3Sskrll 		   int binary)
9632a6b7db3Sskrll {
9642a6b7db3Sskrll   HANDLE h = (HANDLE) _get_osfhandle (fd);
9652a6b7db3Sskrll   if (h == INVALID_HANDLE_VALUE)
9662a6b7db3Sskrll     return NULL;
9672a6b7db3Sskrll   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
9682a6b7db3Sskrll     return NULL;
9692a6b7db3Sskrll   return fdopen (fd, binary ? "wb" : "w");
9702a6b7db3Sskrll }
9712a6b7db3Sskrll 
9722a6b7db3Sskrll #ifdef MAIN
9732a6b7db3Sskrll #include <stdio.h>
9742a6b7db3Sskrll 
9752a6b7db3Sskrll int
main(int argc ATTRIBUTE_UNUSED,char ** argv)9762a6b7db3Sskrll main (int argc ATTRIBUTE_UNUSED, char **argv)
9772a6b7db3Sskrll {
9782a6b7db3Sskrll   char const *errmsg;
9792a6b7db3Sskrll   int err;
9802a6b7db3Sskrll   argv++;
9812a6b7db3Sskrll   printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
9822a6b7db3Sskrll   exit (0);
9832a6b7db3Sskrll }
9842a6b7db3Sskrll #endif
985