1*10d565efSmrg /* Utilities to execute a program in a subprocess (possibly linked by pipes
2*10d565efSmrg    with other subprocesses), and wait for it.  Generic Win32 specialization.
3*10d565efSmrg    Copyright (C) 1996-2017 Free Software Foundation, Inc.
4*10d565efSmrg 
5*10d565efSmrg This file is part of the libiberty library.
6*10d565efSmrg Libiberty is free software; you can redistribute it and/or
7*10d565efSmrg modify it under the terms of the GNU Library General Public
8*10d565efSmrg License as published by the Free Software Foundation; either
9*10d565efSmrg version 2 of the License, or (at your option) any later version.
10*10d565efSmrg 
11*10d565efSmrg Libiberty is distributed in the hope that it will be useful,
12*10d565efSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13*10d565efSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*10d565efSmrg Library General Public License for more details.
15*10d565efSmrg 
16*10d565efSmrg You should have received a copy of the GNU Library General Public
17*10d565efSmrg License along with libiberty; see the file COPYING.LIB.  If not,
18*10d565efSmrg write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19*10d565efSmrg Boston, MA 02110-1301, USA.  */
20*10d565efSmrg 
21*10d565efSmrg #include "pex-common.h"
22*10d565efSmrg 
23*10d565efSmrg #include <windows.h>
24*10d565efSmrg 
25*10d565efSmrg #ifdef HAVE_STDLIB_H
26*10d565efSmrg #include <stdlib.h>
27*10d565efSmrg #endif
28*10d565efSmrg #ifdef HAVE_STRING_H
29*10d565efSmrg #include <string.h>
30*10d565efSmrg #endif
31*10d565efSmrg #ifdef HAVE_UNISTD_H
32*10d565efSmrg #include <unistd.h>
33*10d565efSmrg #endif
34*10d565efSmrg #ifdef HAVE_SYS_WAIT_H
35*10d565efSmrg #include <sys/wait.h>
36*10d565efSmrg #endif
37*10d565efSmrg 
38*10d565efSmrg #include <assert.h>
39*10d565efSmrg #include <process.h>
40*10d565efSmrg #include <io.h>
41*10d565efSmrg #include <fcntl.h>
42*10d565efSmrg #include <signal.h>
43*10d565efSmrg #include <sys/stat.h>
44*10d565efSmrg #include <errno.h>
45*10d565efSmrg #include <ctype.h>
46*10d565efSmrg 
47*10d565efSmrg /* mingw32 headers may not define the following.  */
48*10d565efSmrg 
49*10d565efSmrg #ifndef _P_WAIT
50*10d565efSmrg #  define _P_WAIT	0
51*10d565efSmrg #  define _P_NOWAIT	1
52*10d565efSmrg #  define _P_OVERLAY	2
53*10d565efSmrg #  define _P_NOWAITO	3
54*10d565efSmrg #  define _P_DETACH	4
55*10d565efSmrg 
56*10d565efSmrg #  define WAIT_CHILD		0
57*10d565efSmrg #  define WAIT_GRANDCHILD	1
58*10d565efSmrg #endif
59*10d565efSmrg 
60*10d565efSmrg #define MINGW_NAME "Minimalist GNU for Windows"
61*10d565efSmrg #define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
62*10d565efSmrg 
63*10d565efSmrg extern char *stpcpy (char *dst, const char *src);
64*10d565efSmrg 
65*10d565efSmrg /* Ensure that the executable pathname uses Win32 backslashes. This
66*10d565efSmrg    is not necessary on NT, but on W9x, forward slashes causes
67*10d565efSmrg    failure of spawn* and exec* functions (and probably any function
68*10d565efSmrg    that calls CreateProcess) *iff* the executable pathname (argv[0])
69*10d565efSmrg    is a quoted string.  And quoting is necessary in case a pathname
70*10d565efSmrg    contains embedded white space.  You can't win.  */
71*10d565efSmrg static void
72*10d565efSmrg backslashify (char *s)
73*10d565efSmrg {
74*10d565efSmrg   while ((s = strchr (s, '/')) != NULL)
75*10d565efSmrg     *s = '\\';
76*10d565efSmrg   return;
77*10d565efSmrg }
78*10d565efSmrg 
79*10d565efSmrg static int pex_win32_open_read (struct pex_obj *, const char *, int);
80*10d565efSmrg static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
81*10d565efSmrg static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
82*10d565efSmrg 				  char * const *, char * const *,
83*10d565efSmrg                                   int, int, int, int,
84*10d565efSmrg 				  const char **, int *);
85*10d565efSmrg static int pex_win32_close (struct pex_obj *, int);
86*10d565efSmrg static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
87*10d565efSmrg 			   struct pex_time *, int, const char **, int *);
88*10d565efSmrg static int pex_win32_pipe (struct pex_obj *, int *, int);
89*10d565efSmrg static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
90*10d565efSmrg static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
91*10d565efSmrg 
92*10d565efSmrg /* The list of functions we pass to the common routines.  */
93*10d565efSmrg 
94*10d565efSmrg const struct pex_funcs funcs =
95*10d565efSmrg {
96*10d565efSmrg   pex_win32_open_read,
97*10d565efSmrg   pex_win32_open_write,
98*10d565efSmrg   pex_win32_exec_child,
99*10d565efSmrg   pex_win32_close,
100*10d565efSmrg   pex_win32_wait,
101*10d565efSmrg   pex_win32_pipe,
102*10d565efSmrg   pex_win32_fdopenr,
103*10d565efSmrg   pex_win32_fdopenw,
104*10d565efSmrg   NULL /* cleanup */
105*10d565efSmrg };
106*10d565efSmrg 
107*10d565efSmrg /* Return a newly initialized pex_obj structure.  */
108*10d565efSmrg 
109*10d565efSmrg struct pex_obj *
110*10d565efSmrg pex_init (int flags, const char *pname, const char *tempbase)
111*10d565efSmrg {
112*10d565efSmrg   return pex_init_common (flags, pname, tempbase, &funcs);
113*10d565efSmrg }
114*10d565efSmrg 
115*10d565efSmrg /* Open a file for reading.  */
116*10d565efSmrg 
117*10d565efSmrg static int
118*10d565efSmrg pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
119*10d565efSmrg 		     int binary)
120*10d565efSmrg {
121*10d565efSmrg   return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
122*10d565efSmrg }
123*10d565efSmrg 
124*10d565efSmrg /* Open a file for writing.  */
125*10d565efSmrg 
126*10d565efSmrg static int
127*10d565efSmrg pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
128*10d565efSmrg 		      int binary, int append)
129*10d565efSmrg {
130*10d565efSmrg   /* Note that we can't use O_EXCL here because gcc may have already
131*10d565efSmrg      created the temporary file via make_temp_file.  */
132*10d565efSmrg   if (append)
133*10d565efSmrg     return -1;
134*10d565efSmrg   return _open (name,
135*10d565efSmrg 		(_O_WRONLY | _O_CREAT | _O_TRUNC
136*10d565efSmrg 		 | (binary ? _O_BINARY : _O_TEXT)),
137*10d565efSmrg 		_S_IREAD | _S_IWRITE);
138*10d565efSmrg }
139*10d565efSmrg 
140*10d565efSmrg /* Close a file.  */
141*10d565efSmrg 
142*10d565efSmrg static int
143*10d565efSmrg pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
144*10d565efSmrg {
145*10d565efSmrg   return _close (fd);
146*10d565efSmrg }
147*10d565efSmrg 
148*10d565efSmrg #ifdef USE_MINGW_MSYS
149*10d565efSmrg static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
150*10d565efSmrg 
151*10d565efSmrg /* Tack the executable on the end of a (possibly slash terminated) buffer
152*10d565efSmrg    and convert everything to \. */
153*10d565efSmrg static const char *
154*10d565efSmrg tack_on_executable (char *buf, const char *executable)
155*10d565efSmrg {
156*10d565efSmrg   char *p = strchr (buf, '\0');
157*10d565efSmrg   if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
158*10d565efSmrg     p[-1] = '\0';
159*10d565efSmrg   backslashify (strcat (buf, executable));
160*10d565efSmrg   return buf;
161*10d565efSmrg }
162*10d565efSmrg 
163*10d565efSmrg /* Walk down a registry hierarchy until the end.  Return the key. */
164*10d565efSmrg static HKEY
165*10d565efSmrg openkey (HKEY hStart, const char *keys[])
166*10d565efSmrg {
167*10d565efSmrg   HKEY hKey, hTmp;
168*10d565efSmrg   for (hKey = hStart; *keys; keys++)
169*10d565efSmrg     {
170*10d565efSmrg       LONG res;
171*10d565efSmrg       hTmp = hKey;
172*10d565efSmrg       res = RegOpenKey (hTmp, *keys, &hKey);
173*10d565efSmrg 
174*10d565efSmrg       if (hTmp != HKEY_LOCAL_MACHINE)
175*10d565efSmrg 	RegCloseKey (hTmp);
176*10d565efSmrg 
177*10d565efSmrg       if (res != ERROR_SUCCESS)
178*10d565efSmrg 	return NULL;
179*10d565efSmrg     }
180*10d565efSmrg   return hKey;
181*10d565efSmrg }
182*10d565efSmrg 
183*10d565efSmrg /* Return the "mingw root" as derived from the mingw uninstall information. */
184*10d565efSmrg static const char *
185*10d565efSmrg mingw_rootify (const char *executable)
186*10d565efSmrg {
187*10d565efSmrg   HKEY hKey, hTmp;
188*10d565efSmrg   DWORD maxlen;
189*10d565efSmrg   char *namebuf, *foundbuf;
190*10d565efSmrg   DWORD i;
191*10d565efSmrg   LONG res;
192*10d565efSmrg 
193*10d565efSmrg   /* Open the uninstall "directory". */
194*10d565efSmrg   hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
195*10d565efSmrg 
196*10d565efSmrg   /* Not found. */
197*10d565efSmrg   if (!hKey)
198*10d565efSmrg     return executable;
199*10d565efSmrg 
200*10d565efSmrg   /* Need to enumerate all of the keys here looking for one the most recent
201*10d565efSmrg      one for MinGW. */
202*10d565efSmrg   if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
203*10d565efSmrg 		       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
204*10d565efSmrg     {
205*10d565efSmrg       RegCloseKey (hKey);
206*10d565efSmrg       return executable;
207*10d565efSmrg     }
208*10d565efSmrg   namebuf = XNEWVEC (char, ++maxlen);
209*10d565efSmrg   foundbuf = XNEWVEC (char, maxlen);
210*10d565efSmrg   foundbuf[0] = '\0';
211*10d565efSmrg   if (!namebuf || !foundbuf)
212*10d565efSmrg     {
213*10d565efSmrg       RegCloseKey (hKey);
214*10d565efSmrg       free (namebuf);
215*10d565efSmrg       free (foundbuf);
216*10d565efSmrg       return executable;
217*10d565efSmrg     }
218*10d565efSmrg 
219*10d565efSmrg   /* Look through all of the keys for one that begins with Minimal GNU...
220*10d565efSmrg      Try to get the latest version by doing a string compare although that
221*10d565efSmrg      string never really works with version number sorting. */
222*10d565efSmrg   for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
223*10d565efSmrg     {
224*10d565efSmrg       int match = strcasecmp (namebuf, MINGW_NAME);
225*10d565efSmrg       if (match < 0)
226*10d565efSmrg 	continue;
227*10d565efSmrg       if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
228*10d565efSmrg 	continue;
229*10d565efSmrg       if (strcasecmp (namebuf, foundbuf) > 0)
230*10d565efSmrg 	strcpy (foundbuf, namebuf);
231*10d565efSmrg     }
232*10d565efSmrg   free (namebuf);
233*10d565efSmrg 
234*10d565efSmrg   /* If foundbuf is empty, we didn't find anything.  Punt. */
235*10d565efSmrg   if (!foundbuf[0])
236*10d565efSmrg     {
237*10d565efSmrg       free (foundbuf);
238*10d565efSmrg       RegCloseKey (hKey);
239*10d565efSmrg       return executable;
240*10d565efSmrg     }
241*10d565efSmrg 
242*10d565efSmrg   /* Open the key that we wanted */
243*10d565efSmrg   res = RegOpenKey (hKey, foundbuf, &hTmp);
244*10d565efSmrg   RegCloseKey (hKey);
245*10d565efSmrg   free (foundbuf);
246*10d565efSmrg 
247*10d565efSmrg   /* Don't know why this would fail, but you gotta check */
248*10d565efSmrg   if (res != ERROR_SUCCESS)
249*10d565efSmrg     return executable;
250*10d565efSmrg 
251*10d565efSmrg   maxlen = 0;
252*10d565efSmrg   /* Get the length of the value pointed to by InstallLocation */
253*10d565efSmrg   if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
254*10d565efSmrg 		       &maxlen) != ERROR_SUCCESS || maxlen == 0)
255*10d565efSmrg     {
256*10d565efSmrg       RegCloseKey (hTmp);
257*10d565efSmrg       return executable;
258*10d565efSmrg     }
259*10d565efSmrg 
260*10d565efSmrg   /* Allocate space for the install location */
261*10d565efSmrg   foundbuf = XNEWVEC (char, maxlen + strlen (executable));
262*10d565efSmrg   if (!foundbuf)
263*10d565efSmrg     {
264*10d565efSmrg       free (foundbuf);
265*10d565efSmrg       RegCloseKey (hTmp);
266*10d565efSmrg     }
267*10d565efSmrg 
268*10d565efSmrg   /* Read the install location into the buffer */
269*10d565efSmrg   res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
270*10d565efSmrg 			 &maxlen);
271*10d565efSmrg   RegCloseKey (hTmp);
272*10d565efSmrg   if (res != ERROR_SUCCESS)
273*10d565efSmrg     {
274*10d565efSmrg       free (foundbuf);
275*10d565efSmrg       return executable;
276*10d565efSmrg     }
277*10d565efSmrg 
278*10d565efSmrg   /* Concatenate the install location and the executable, turn all slashes
279*10d565efSmrg      to backslashes, and return that. */
280*10d565efSmrg   return tack_on_executable (foundbuf, executable);
281*10d565efSmrg }
282*10d565efSmrg 
283*10d565efSmrg /* Read the install location of msys from it's installation file and
284*10d565efSmrg    rootify the executable based on that. */
285*10d565efSmrg static const char *
286*10d565efSmrg msys_rootify (const char *executable)
287*10d565efSmrg {
288*10d565efSmrg   size_t bufsize = 64;
289*10d565efSmrg   size_t execlen = strlen (executable) + 1;
290*10d565efSmrg   char *buf;
291*10d565efSmrg   DWORD res = 0;
292*10d565efSmrg   for (;;)
293*10d565efSmrg     {
294*10d565efSmrg       buf = XNEWVEC (char, bufsize + execlen);
295*10d565efSmrg       if (!buf)
296*10d565efSmrg 	break;
297*10d565efSmrg       res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
298*10d565efSmrg 				     buf, bufsize, "msys.ini");
299*10d565efSmrg       if (!res)
300*10d565efSmrg 	break;
301*10d565efSmrg       if (strlen (buf) < bufsize)
302*10d565efSmrg 	break;
303*10d565efSmrg       res = 0;
304*10d565efSmrg       free (buf);
305*10d565efSmrg       bufsize *= 2;
306*10d565efSmrg       if (bufsize > 65536)
307*10d565efSmrg 	{
308*10d565efSmrg 	  buf = NULL;
309*10d565efSmrg 	  break;
310*10d565efSmrg 	}
311*10d565efSmrg     }
312*10d565efSmrg 
313*10d565efSmrg   if (res)
314*10d565efSmrg     return tack_on_executable (buf, executable);
315*10d565efSmrg 
316*10d565efSmrg   /* failed */
317*10d565efSmrg   free (buf);
318*10d565efSmrg   return executable;
319*10d565efSmrg }
320*10d565efSmrg #endif
321*10d565efSmrg 
322*10d565efSmrg /* Return the number of arguments in an argv array, not including the null
323*10d565efSmrg    terminating argument. */
324*10d565efSmrg 
325*10d565efSmrg static int
326*10d565efSmrg argv_to_argc (char *const *argv)
327*10d565efSmrg {
328*10d565efSmrg   char *const *i = argv;
329*10d565efSmrg   while (*i)
330*10d565efSmrg     i++;
331*10d565efSmrg   return i - argv;
332*10d565efSmrg }
333*10d565efSmrg 
334*10d565efSmrg /* Return a Windows command-line from ARGV.  It is the caller's
335*10d565efSmrg    responsibility to free the string returned.  */
336*10d565efSmrg 
337*10d565efSmrg static char *
338*10d565efSmrg argv_to_cmdline (char *const *argv)
339*10d565efSmrg {
340*10d565efSmrg   char *cmdline;
341*10d565efSmrg   char *p;
342*10d565efSmrg   size_t cmdline_len;
343*10d565efSmrg   int i, j, k;
344*10d565efSmrg   int needs_quotes;
345*10d565efSmrg 
346*10d565efSmrg   cmdline_len = 0;
347*10d565efSmrg   for (i = 0; argv[i]; i++)
348*10d565efSmrg     {
349*10d565efSmrg       /* We only quote arguments that contain spaces, \t or " characters to
350*10d565efSmrg 	 prevent wasting 2 chars per argument of the CreateProcess 32k char
351*10d565efSmrg 	 limit.  We need only escape embedded double-quotes and immediately
352*10d565efSmrg 	 preceeding backslash characters.  A sequence of backslach characters
353*10d565efSmrg 	 that is not follwed by a double quote character will not be
354*10d565efSmrg 	 escaped.  */
355*10d565efSmrg       needs_quotes = 0;
356*10d565efSmrg       for (j = 0; argv[i][j]; j++)
357*10d565efSmrg 	{
358*10d565efSmrg 	  if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
359*10d565efSmrg 	    {
360*10d565efSmrg 	      needs_quotes = 1;
361*10d565efSmrg 	    }
362*10d565efSmrg 
363*10d565efSmrg 	  if (argv[i][j] == '"')
364*10d565efSmrg 	    {
365*10d565efSmrg 	      /* Escape preceeding backslashes.  */
366*10d565efSmrg 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
367*10d565efSmrg 		cmdline_len++;
368*10d565efSmrg 	      /* Escape the qote character.  */
369*10d565efSmrg 	      cmdline_len++;
370*10d565efSmrg 	    }
371*10d565efSmrg 	}
372*10d565efSmrg       if (j == 0)
373*10d565efSmrg 	needs_quotes = 1;
374*10d565efSmrg       /* Trailing backslashes also need to be escaped because they will be
375*10d565efSmrg          followed by the terminating quote.  */
376*10d565efSmrg       if (needs_quotes)
377*10d565efSmrg         {
378*10d565efSmrg           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
379*10d565efSmrg             cmdline_len++;
380*10d565efSmrg         }
381*10d565efSmrg       cmdline_len += j;
382*10d565efSmrg       /* for leading and trailing quotes and space */
383*10d565efSmrg       cmdline_len += needs_quotes * 2 + 1;
384*10d565efSmrg     }
385*10d565efSmrg   cmdline = XNEWVEC (char, cmdline_len);
386*10d565efSmrg   p = cmdline;
387*10d565efSmrg   for (i = 0; argv[i]; i++)
388*10d565efSmrg     {
389*10d565efSmrg       needs_quotes = 0;
390*10d565efSmrg       for (j = 0; argv[i][j]; j++)
391*10d565efSmrg         {
392*10d565efSmrg           if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
393*10d565efSmrg             {
394*10d565efSmrg               needs_quotes = 1;
395*10d565efSmrg               break;
396*10d565efSmrg             }
397*10d565efSmrg         }
398*10d565efSmrg       if (j == 0)
399*10d565efSmrg 	needs_quotes = 1;
400*10d565efSmrg 
401*10d565efSmrg       if (needs_quotes)
402*10d565efSmrg         {
403*10d565efSmrg           *p++ = '"';
404*10d565efSmrg         }
405*10d565efSmrg       for (j = 0; argv[i][j]; j++)
406*10d565efSmrg 	{
407*10d565efSmrg 	  if (argv[i][j] == '"')
408*10d565efSmrg 	    {
409*10d565efSmrg 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
410*10d565efSmrg 		*p++ = '\\';
411*10d565efSmrg 	      *p++ = '\\';
412*10d565efSmrg 	    }
413*10d565efSmrg 	  *p++ = argv[i][j];
414*10d565efSmrg 	}
415*10d565efSmrg       if (needs_quotes)
416*10d565efSmrg         {
417*10d565efSmrg           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
418*10d565efSmrg             *p++ = '\\';
419*10d565efSmrg           *p++ = '"';
420*10d565efSmrg         }
421*10d565efSmrg       *p++ = ' ';
422*10d565efSmrg     }
423*10d565efSmrg   p[-1] = '\0';
424*10d565efSmrg   return cmdline;
425*10d565efSmrg }
426*10d565efSmrg 
427*10d565efSmrg /* We'll try the passed filename with all the known standard
428*10d565efSmrg    extensions, and then without extension.  We try no extension
429*10d565efSmrg    last so that we don't try to run some random extension-less
430*10d565efSmrg    file that might be hanging around.  We try both extension
431*10d565efSmrg    and no extension so that we don't need any fancy logic
432*10d565efSmrg    to determine if a file has extension.  */
433*10d565efSmrg static const char *const
434*10d565efSmrg std_suffixes[] = {
435*10d565efSmrg   ".com",
436*10d565efSmrg   ".exe",
437*10d565efSmrg   ".bat",
438*10d565efSmrg   ".cmd",
439*10d565efSmrg   "",
440*10d565efSmrg   0
441*10d565efSmrg };
442*10d565efSmrg 
443*10d565efSmrg /* Returns the full path to PROGRAM.  If SEARCH is true, look for
444*10d565efSmrg    PROGRAM in each directory in PATH.  */
445*10d565efSmrg 
446*10d565efSmrg static char *
447*10d565efSmrg find_executable (const char *program, BOOL search)
448*10d565efSmrg {
449*10d565efSmrg   char *full_executable;
450*10d565efSmrg   char *e;
451*10d565efSmrg   size_t fe_len;
452*10d565efSmrg   const char *path = 0;
453*10d565efSmrg   const char *const *ext;
454*10d565efSmrg   const char *p, *q;
455*10d565efSmrg   size_t proglen = strlen (program);
456*10d565efSmrg   int has_slash = (strchr (program, '/') || strchr (program, '\\'));
457*10d565efSmrg   HANDLE h;
458*10d565efSmrg 
459*10d565efSmrg   if (has_slash)
460*10d565efSmrg     search = FALSE;
461*10d565efSmrg 
462*10d565efSmrg   if (search)
463*10d565efSmrg     path = getenv ("PATH");
464*10d565efSmrg   if (!path)
465*10d565efSmrg     path = "";
466*10d565efSmrg 
467*10d565efSmrg   fe_len = 0;
468*10d565efSmrg   for (p = path; *p; p = q)
469*10d565efSmrg     {
470*10d565efSmrg       q = p;
471*10d565efSmrg       while (*q != ';' && *q != '\0')
472*10d565efSmrg 	q++;
473*10d565efSmrg       if ((size_t)(q - p) > fe_len)
474*10d565efSmrg 	fe_len = q - p;
475*10d565efSmrg       if (*q == ';')
476*10d565efSmrg 	q++;
477*10d565efSmrg     }
478*10d565efSmrg   fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
479*10d565efSmrg   full_executable = XNEWVEC (char, fe_len);
480*10d565efSmrg 
481*10d565efSmrg   p = path;
482*10d565efSmrg   do
483*10d565efSmrg     {
484*10d565efSmrg       q = p;
485*10d565efSmrg       while (*q != ';' && *q != '\0')
486*10d565efSmrg 	q++;
487*10d565efSmrg 
488*10d565efSmrg       e = full_executable;
489*10d565efSmrg       memcpy (e, p, q - p);
490*10d565efSmrg       e += (q - p);
491*10d565efSmrg       if (q - p)
492*10d565efSmrg 	*e++ = '\\';
493*10d565efSmrg       strcpy (e, program);
494*10d565efSmrg 
495*10d565efSmrg       if (*q == ';')
496*10d565efSmrg 	q++;
497*10d565efSmrg 
498*10d565efSmrg       for (e = full_executable; *e; e++)
499*10d565efSmrg 	if (*e == '/')
500*10d565efSmrg 	  *e = '\\';
501*10d565efSmrg 
502*10d565efSmrg       /* At this point, e points to the terminating NUL character for
503*10d565efSmrg          full_executable.  */
504*10d565efSmrg       for (ext = std_suffixes; *ext; ext++)
505*10d565efSmrg 	{
506*10d565efSmrg 	  /* Remove any current extension.  */
507*10d565efSmrg 	  *e = '\0';
508*10d565efSmrg 	  /* Add the new one.  */
509*10d565efSmrg 	  strcat (full_executable, *ext);
510*10d565efSmrg 
511*10d565efSmrg 	  /* Attempt to open this file.  */
512*10d565efSmrg 	  h = CreateFile (full_executable, GENERIC_READ,
513*10d565efSmrg 			  FILE_SHARE_READ | FILE_SHARE_WRITE,
514*10d565efSmrg 			  0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
515*10d565efSmrg 	  if (h != INVALID_HANDLE_VALUE)
516*10d565efSmrg 	    goto found;
517*10d565efSmrg 	}
518*10d565efSmrg       p = q;
519*10d565efSmrg     }
520*10d565efSmrg   while (*p);
521*10d565efSmrg   free (full_executable);
522*10d565efSmrg   return 0;
523*10d565efSmrg 
524*10d565efSmrg  found:
525*10d565efSmrg   CloseHandle (h);
526*10d565efSmrg   return full_executable;
527*10d565efSmrg }
528*10d565efSmrg 
529*10d565efSmrg /* Low-level process creation function and helper.  */
530*10d565efSmrg 
531*10d565efSmrg static int
532*10d565efSmrg env_compare (const void *a_ptr, const void *b_ptr)
533*10d565efSmrg {
534*10d565efSmrg   const char *a;
535*10d565efSmrg   const char *b;
536*10d565efSmrg   unsigned char c1;
537*10d565efSmrg   unsigned char c2;
538*10d565efSmrg 
539*10d565efSmrg   a = *(const char **) a_ptr;
540*10d565efSmrg   b = *(const char **) b_ptr;
541*10d565efSmrg 
542*10d565efSmrg   /* a and b will be of the form: VAR=VALUE
543*10d565efSmrg      We compare only the variable name part here using a case-insensitive
544*10d565efSmrg      comparison algorithm.  It might appear that in fact strcasecmp () can
545*10d565efSmrg      take the place of this whole function, and indeed it could, save for
546*10d565efSmrg      the fact that it would fail in cases such as comparing A1=foo and
547*10d565efSmrg      A=bar (because 1 is less than = in the ASCII character set).
548*10d565efSmrg      (Environment variables containing no numbers would work in such a
549*10d565efSmrg      scenario.)  */
550*10d565efSmrg 
551*10d565efSmrg   do
552*10d565efSmrg     {
553*10d565efSmrg       c1 = (unsigned char) tolower (*a++);
554*10d565efSmrg       c2 = (unsigned char) tolower (*b++);
555*10d565efSmrg 
556*10d565efSmrg       if (c1 == '=')
557*10d565efSmrg         c1 = '\0';
558*10d565efSmrg 
559*10d565efSmrg       if (c2 == '=')
560*10d565efSmrg         c2 = '\0';
561*10d565efSmrg     }
562*10d565efSmrg   while (c1 == c2 && c1 != '\0');
563*10d565efSmrg 
564*10d565efSmrg   return c1 - c2;
565*10d565efSmrg }
566*10d565efSmrg 
567*10d565efSmrg /* Execute a Windows executable as a child process.  This will fail if the
568*10d565efSmrg  * target is not actually an executable, such as if it is a shell script. */
569*10d565efSmrg 
570*10d565efSmrg static pid_t
571*10d565efSmrg win32_spawn (const char *executable,
572*10d565efSmrg 	     BOOL search,
573*10d565efSmrg 	     char *const *argv,
574*10d565efSmrg              char *const *env, /* array of strings of the form: VAR=VALUE */
575*10d565efSmrg 	     DWORD dwCreationFlags,
576*10d565efSmrg 	     LPSTARTUPINFO si,
577*10d565efSmrg 	     LPPROCESS_INFORMATION pi)
578*10d565efSmrg {
579*10d565efSmrg   char *full_executable;
580*10d565efSmrg   char *cmdline;
581*10d565efSmrg   char **env_copy;
582*10d565efSmrg   char *env_block = NULL;
583*10d565efSmrg 
584*10d565efSmrg   full_executable = NULL;
585*10d565efSmrg   cmdline = NULL;
586*10d565efSmrg 
587*10d565efSmrg   if (env)
588*10d565efSmrg     {
589*10d565efSmrg       int env_size;
590*10d565efSmrg 
591*10d565efSmrg       /* Count the number of environment bindings supplied.  */
592*10d565efSmrg       for (env_size = 0; env[env_size]; env_size++)
593*10d565efSmrg         continue;
594*10d565efSmrg 
595*10d565efSmrg       /* Assemble an environment block, if required.  This consists of
596*10d565efSmrg          VAR=VALUE strings juxtaposed (with one null character between each
597*10d565efSmrg          pair) and an additional null at the end.  */
598*10d565efSmrg       if (env_size > 0)
599*10d565efSmrg         {
600*10d565efSmrg           int var;
601*10d565efSmrg           int total_size = 1; /* 1 is for the final null.  */
602*10d565efSmrg           char *bufptr;
603*10d565efSmrg 
604*10d565efSmrg           /* Windows needs the members of the block to be sorted by variable
605*10d565efSmrg              name.  */
606*10d565efSmrg           env_copy = (char **) alloca (sizeof (char *) * env_size);
607*10d565efSmrg           memcpy (env_copy, env, sizeof (char *) * env_size);
608*10d565efSmrg           qsort (env_copy, env_size, sizeof (char *), env_compare);
609*10d565efSmrg 
610*10d565efSmrg           for (var = 0; var < env_size; var++)
611*10d565efSmrg             total_size += strlen (env[var]) + 1;
612*10d565efSmrg 
613*10d565efSmrg           env_block = XNEWVEC (char, total_size);
614*10d565efSmrg           bufptr = env_block;
615*10d565efSmrg           for (var = 0; var < env_size; var++)
616*10d565efSmrg             bufptr = stpcpy (bufptr, env_copy[var]) + 1;
617*10d565efSmrg 
618*10d565efSmrg           *bufptr = '\0';
619*10d565efSmrg         }
620*10d565efSmrg     }
621*10d565efSmrg 
622*10d565efSmrg   full_executable = find_executable (executable, search);
623*10d565efSmrg   if (!full_executable)
624*10d565efSmrg     goto error;
625*10d565efSmrg   cmdline = argv_to_cmdline (argv);
626*10d565efSmrg   if (!cmdline)
627*10d565efSmrg     goto error;
628*10d565efSmrg 
629*10d565efSmrg   /* Create the child process.  */
630*10d565efSmrg   if (!CreateProcess (full_executable, cmdline,
631*10d565efSmrg 		      /*lpProcessAttributes=*/NULL,
632*10d565efSmrg 		      /*lpThreadAttributes=*/NULL,
633*10d565efSmrg 		      /*bInheritHandles=*/TRUE,
634*10d565efSmrg 		      dwCreationFlags,
635*10d565efSmrg 		      (LPVOID) env_block,
636*10d565efSmrg 		      /*lpCurrentDirectory=*/NULL,
637*10d565efSmrg 		      si,
638*10d565efSmrg 		      pi))
639*10d565efSmrg     {
640*10d565efSmrg       free (env_block);
641*10d565efSmrg 
642*10d565efSmrg       free (full_executable);
643*10d565efSmrg 
644*10d565efSmrg       return (pid_t) -1;
645*10d565efSmrg     }
646*10d565efSmrg 
647*10d565efSmrg   /* Clean up.  */
648*10d565efSmrg   CloseHandle (pi->hThread);
649*10d565efSmrg   free (full_executable);
650*10d565efSmrg   free (env_block);
651*10d565efSmrg 
652*10d565efSmrg   return (pid_t) pi->hProcess;
653*10d565efSmrg 
654*10d565efSmrg  error:
655*10d565efSmrg   free (env_block);
656*10d565efSmrg   free (cmdline);
657*10d565efSmrg   free (full_executable);
658*10d565efSmrg 
659*10d565efSmrg   return (pid_t) -1;
660*10d565efSmrg }
661*10d565efSmrg 
662*10d565efSmrg /* Spawn a script.  This simulates the Unix script execution mechanism.
663*10d565efSmrg    This function is called as a fallback if win32_spawn fails. */
664*10d565efSmrg 
665*10d565efSmrg static pid_t
666*10d565efSmrg spawn_script (const char *executable, char *const *argv,
667*10d565efSmrg               char* const *env,
668*10d565efSmrg 	      DWORD dwCreationFlags,
669*10d565efSmrg 	      LPSTARTUPINFO si,
670*10d565efSmrg 	      LPPROCESS_INFORMATION pi)
671*10d565efSmrg {
672*10d565efSmrg   pid_t pid = (pid_t) -1;
673*10d565efSmrg   int save_errno = errno;
674*10d565efSmrg   int fd = _open (executable, _O_RDONLY);
675*10d565efSmrg 
676*10d565efSmrg   /* Try to open script, check header format, extract interpreter path,
677*10d565efSmrg      and spawn script using that interpretter. */
678*10d565efSmrg   if (fd >= 0)
679*10d565efSmrg     {
680*10d565efSmrg       char buf[MAX_PATH + 5];
681*10d565efSmrg       int len = _read (fd, buf, sizeof (buf) - 1);
682*10d565efSmrg       _close (fd);
683*10d565efSmrg       if (len > 3)
684*10d565efSmrg 	{
685*10d565efSmrg 	  char *eol;
686*10d565efSmrg 	  buf[len] = '\0';
687*10d565efSmrg 	  eol = strchr (buf, '\n');
688*10d565efSmrg 	  if (eol && strncmp (buf, "#!", 2) == 0)
689*10d565efSmrg 	    {
690*10d565efSmrg 
691*10d565efSmrg 	      /* Header format is OK. */
692*10d565efSmrg 	      char *executable1;
693*10d565efSmrg               int new_argc;
694*10d565efSmrg               const char **avhere;
695*10d565efSmrg 
696*10d565efSmrg 	      /* Extract interpreter path. */
697*10d565efSmrg 	      do
698*10d565efSmrg 		*eol = '\0';
699*10d565efSmrg 	      while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
700*10d565efSmrg 	      for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
701*10d565efSmrg 		continue;
702*10d565efSmrg 	      backslashify (executable1);
703*10d565efSmrg 
704*10d565efSmrg 	      /* Duplicate argv, prepending the interpreter path. */
705*10d565efSmrg 	      new_argc = argv_to_argc (argv) + 1;
706*10d565efSmrg 	      avhere = XNEWVEC (const char *, new_argc + 1);
707*10d565efSmrg 	      *avhere = executable1;
708*10d565efSmrg 	      memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
709*10d565efSmrg 	      argv = (char *const *)avhere;
710*10d565efSmrg 
711*10d565efSmrg 	      /* Spawn the child. */
712*10d565efSmrg #ifndef USE_MINGW_MSYS
713*10d565efSmrg 	      executable = strrchr (executable1, '\\') + 1;
714*10d565efSmrg 	      if (!executable)
715*10d565efSmrg 		executable = executable1;
716*10d565efSmrg 	      pid = win32_spawn (executable, TRUE, argv, env,
717*10d565efSmrg 				 dwCreationFlags, si, pi);
718*10d565efSmrg #else
719*10d565efSmrg 	      if (strchr (executable1, '\\') == NULL)
720*10d565efSmrg 		pid = win32_spawn (executable1, TRUE, argv, env,
721*10d565efSmrg 				   dwCreationFlags, si, pi);
722*10d565efSmrg 	      else if (executable1[0] != '\\')
723*10d565efSmrg 		pid = win32_spawn (executable1, FALSE, argv, env,
724*10d565efSmrg 				   dwCreationFlags, si, pi);
725*10d565efSmrg 	      else
726*10d565efSmrg 		{
727*10d565efSmrg 		  const char *newex = mingw_rootify (executable1);
728*10d565efSmrg 		  *avhere = newex;
729*10d565efSmrg 		  pid = win32_spawn (newex, FALSE, argv, env,
730*10d565efSmrg 				     dwCreationFlags, si, pi);
731*10d565efSmrg 		  if (executable1 != newex)
732*10d565efSmrg 		    free ((char *) newex);
733*10d565efSmrg 		  if (pid == (pid_t) -1)
734*10d565efSmrg 		    {
735*10d565efSmrg 		      newex = msys_rootify (executable1);
736*10d565efSmrg 		      if (newex != executable1)
737*10d565efSmrg 			{
738*10d565efSmrg 			  *avhere = newex;
739*10d565efSmrg 			  pid = win32_spawn (newex, FALSE, argv, env,
740*10d565efSmrg 					     dwCreationFlags, si, pi);
741*10d565efSmrg 			  free ((char *) newex);
742*10d565efSmrg 			}
743*10d565efSmrg 		    }
744*10d565efSmrg 		}
745*10d565efSmrg #endif
746*10d565efSmrg 	      free (avhere);
747*10d565efSmrg 	    }
748*10d565efSmrg 	}
749*10d565efSmrg     }
750*10d565efSmrg   if (pid == (pid_t) -1)
751*10d565efSmrg     errno = save_errno;
752*10d565efSmrg   return pid;
753*10d565efSmrg }
754*10d565efSmrg 
755*10d565efSmrg /* Execute a child.  */
756*10d565efSmrg 
757*10d565efSmrg static pid_t
758*10d565efSmrg pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
759*10d565efSmrg 		      const char *executable, char * const * argv,
760*10d565efSmrg                       char* const* env,
761*10d565efSmrg 		      int in, int out, int errdes,
762*10d565efSmrg 		      int toclose ATTRIBUTE_UNUSED,
763*10d565efSmrg 		      const char **errmsg,
764*10d565efSmrg 		      int *err)
765*10d565efSmrg {
766*10d565efSmrg   pid_t pid;
767*10d565efSmrg   HANDLE stdin_handle;
768*10d565efSmrg   HANDLE stdout_handle;
769*10d565efSmrg   HANDLE stderr_handle;
770*10d565efSmrg   DWORD dwCreationFlags;
771*10d565efSmrg   OSVERSIONINFO version_info;
772*10d565efSmrg   STARTUPINFO si;
773*10d565efSmrg   PROCESS_INFORMATION pi;
774*10d565efSmrg   int orig_out, orig_in, orig_err;
775*10d565efSmrg   BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
776*10d565efSmrg 
777*10d565efSmrg   /* Ensure we have inheritable descriptors to pass to the child.  */
778*10d565efSmrg   orig_in = in;
779*10d565efSmrg   in = _dup (orig_in);
780*10d565efSmrg 
781*10d565efSmrg   orig_out = out;
782*10d565efSmrg   out = _dup (orig_out);
783*10d565efSmrg 
784*10d565efSmrg   if (separate_stderr)
785*10d565efSmrg     {
786*10d565efSmrg       orig_err = errdes;
787*10d565efSmrg       errdes = _dup (orig_err);
788*10d565efSmrg     }
789*10d565efSmrg 
790*10d565efSmrg   stdin_handle = INVALID_HANDLE_VALUE;
791*10d565efSmrg   stdout_handle = INVALID_HANDLE_VALUE;
792*10d565efSmrg   stderr_handle = INVALID_HANDLE_VALUE;
793*10d565efSmrg 
794*10d565efSmrg   stdin_handle = (HANDLE) _get_osfhandle (in);
795*10d565efSmrg   stdout_handle = (HANDLE) _get_osfhandle (out);
796*10d565efSmrg   if (separate_stderr)
797*10d565efSmrg     stderr_handle = (HANDLE) _get_osfhandle (errdes);
798*10d565efSmrg   else
799*10d565efSmrg     stderr_handle = stdout_handle;
800*10d565efSmrg 
801*10d565efSmrg   /* Determine the version of Windows we are running on.  */
802*10d565efSmrg   version_info.dwOSVersionInfoSize = sizeof (version_info);
803*10d565efSmrg   GetVersionEx (&version_info);
804*10d565efSmrg   if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
805*10d565efSmrg     /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
806*10d565efSmrg        supported, so we cannot avoid creating a console window.  */
807*10d565efSmrg     dwCreationFlags = 0;
808*10d565efSmrg   else
809*10d565efSmrg     {
810*10d565efSmrg       HANDLE conout_handle;
811*10d565efSmrg 
812*10d565efSmrg       /* Determine whether or not we have an associated console.  */
813*10d565efSmrg       conout_handle = CreateFile("CONOUT$",
814*10d565efSmrg 				 GENERIC_WRITE,
815*10d565efSmrg 				 FILE_SHARE_WRITE,
816*10d565efSmrg 				 /*lpSecurityAttributes=*/NULL,
817*10d565efSmrg 				 OPEN_EXISTING,
818*10d565efSmrg 				 FILE_ATTRIBUTE_NORMAL,
819*10d565efSmrg 				 /*hTemplateFile=*/NULL);
820*10d565efSmrg       if (conout_handle == INVALID_HANDLE_VALUE)
821*10d565efSmrg 	/* There is no console associated with this process.  Since
822*10d565efSmrg 	   the child is a console process, the OS would normally
823*10d565efSmrg 	   create a new console Window for the child.  Since we'll be
824*10d565efSmrg 	   redirecting the child's standard streams, we do not need
825*10d565efSmrg 	   the console window.  */
826*10d565efSmrg 	dwCreationFlags = CREATE_NO_WINDOW;
827*10d565efSmrg       else
828*10d565efSmrg 	{
829*10d565efSmrg 	  /* There is a console associated with the process, so the OS
830*10d565efSmrg 	     will not create a new console.  And, if we use
831*10d565efSmrg 	     CREATE_NO_WINDOW in this situation, the child will have
832*10d565efSmrg 	     no associated console.  Therefore, if the child's
833*10d565efSmrg 	     standard streams are connected to the console, the output
834*10d565efSmrg 	     will be discarded.  */
835*10d565efSmrg 	  CloseHandle(conout_handle);
836*10d565efSmrg 	  dwCreationFlags = 0;
837*10d565efSmrg 	}
838*10d565efSmrg     }
839*10d565efSmrg 
840*10d565efSmrg   /* Since the child will be a console process, it will, by default,
841*10d565efSmrg      connect standard input/output to its console.  However, we want
842*10d565efSmrg      the child to use the handles specifically designated above.  In
843*10d565efSmrg      addition, if there is no console (such as when we are running in
844*10d565efSmrg      a Cygwin X window), then we must redirect the child's
845*10d565efSmrg      input/output, as there is no console for the child to use.  */
846*10d565efSmrg   memset (&si, 0, sizeof (si));
847*10d565efSmrg   si.cb = sizeof (si);
848*10d565efSmrg   si.dwFlags = STARTF_USESTDHANDLES;
849*10d565efSmrg   si.hStdInput = stdin_handle;
850*10d565efSmrg   si.hStdOutput = stdout_handle;
851*10d565efSmrg   si.hStdError = stderr_handle;
852*10d565efSmrg 
853*10d565efSmrg   /* Create the child process.  */
854*10d565efSmrg   pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
855*10d565efSmrg 		     argv, env, dwCreationFlags, &si, &pi);
856*10d565efSmrg   if (pid == (pid_t) -1)
857*10d565efSmrg     pid = spawn_script (executable, argv, env, dwCreationFlags,
858*10d565efSmrg                         &si, &pi);
859*10d565efSmrg   if (pid == (pid_t) -1)
860*10d565efSmrg     {
861*10d565efSmrg       *err = ENOENT;
862*10d565efSmrg       *errmsg = "CreateProcess";
863*10d565efSmrg     }
864*10d565efSmrg 
865*10d565efSmrg   /* If the child was created successfully, close the original file
866*10d565efSmrg      descriptors.  If the process creation fails, these are closed by
867*10d565efSmrg      pex_run_in_environment instead.  We must not close them twice as
868*10d565efSmrg      that seems to cause a Windows exception.  */
869*10d565efSmrg 
870*10d565efSmrg   if (pid != (pid_t) -1)
871*10d565efSmrg     {
872*10d565efSmrg       if (orig_in != STDIN_FILENO)
873*10d565efSmrg 	_close (orig_in);
874*10d565efSmrg       if (orig_out != STDOUT_FILENO)
875*10d565efSmrg 	_close (orig_out);
876*10d565efSmrg       if (separate_stderr
877*10d565efSmrg 	  && orig_err != STDERR_FILENO)
878*10d565efSmrg 	_close (orig_err);
879*10d565efSmrg     }
880*10d565efSmrg 
881*10d565efSmrg   /* Close the standard input, standard output and standard error handles
882*10d565efSmrg      in the parent.  */
883*10d565efSmrg 
884*10d565efSmrg   _close (in);
885*10d565efSmrg   _close (out);
886*10d565efSmrg   if (separate_stderr)
887*10d565efSmrg     _close (errdes);
888*10d565efSmrg 
889*10d565efSmrg   return pid;
890*10d565efSmrg }
891*10d565efSmrg 
892*10d565efSmrg /* Wait for a child process to complete.  MS CRTDLL doesn't return
893*10d565efSmrg    enough information in status to decide if the child exited due to a
894*10d565efSmrg    signal or not, rather it simply returns an integer with the exit
895*10d565efSmrg    code of the child; eg., if the child exited with an abort() call
896*10d565efSmrg    and didn't have a handler for SIGABRT, it simply returns with
897*10d565efSmrg    status == 3.  We fix the status code to conform to the usual WIF*
898*10d565efSmrg    macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
899*10d565efSmrg 
900*10d565efSmrg static pid_t
901*10d565efSmrg pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
902*10d565efSmrg 		int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
903*10d565efSmrg 		const char **errmsg, int *err)
904*10d565efSmrg {
905*10d565efSmrg   DWORD termstat;
906*10d565efSmrg   HANDLE h;
907*10d565efSmrg 
908*10d565efSmrg   if (time != NULL)
909*10d565efSmrg     memset (time, 0, sizeof *time);
910*10d565efSmrg 
911*10d565efSmrg   h = (HANDLE) pid;
912*10d565efSmrg 
913*10d565efSmrg   /* FIXME: If done is non-zero, we should probably try to kill the
914*10d565efSmrg      process.  */
915*10d565efSmrg   if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
916*10d565efSmrg     {
917*10d565efSmrg       CloseHandle (h);
918*10d565efSmrg       *err = ECHILD;
919*10d565efSmrg       *errmsg = "WaitForSingleObject";
920*10d565efSmrg       return -1;
921*10d565efSmrg     }
922*10d565efSmrg 
923*10d565efSmrg   GetExitCodeProcess (h, &termstat);
924*10d565efSmrg   CloseHandle (h);
925*10d565efSmrg 
926*10d565efSmrg   /* A value of 3 indicates that the child caught a signal, but not
927*10d565efSmrg      which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
928*10d565efSmrg      report SIGABRT.  */
929*10d565efSmrg   if (termstat == 3)
930*10d565efSmrg     *status = SIGABRT;
931*10d565efSmrg   else
932*10d565efSmrg     *status = (termstat & 0xff) << 8;
933*10d565efSmrg 
934*10d565efSmrg   return 0;
935*10d565efSmrg }
936*10d565efSmrg 
937*10d565efSmrg /* Create a pipe.  */
938*10d565efSmrg 
939*10d565efSmrg static int
940*10d565efSmrg pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
941*10d565efSmrg 		int binary)
942*10d565efSmrg {
943*10d565efSmrg   return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
944*10d565efSmrg }
945*10d565efSmrg 
946*10d565efSmrg /* Get a FILE pointer to read from a file descriptor.  */
947*10d565efSmrg 
948*10d565efSmrg static FILE *
949*10d565efSmrg pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
950*10d565efSmrg 		   int binary)
951*10d565efSmrg {
952*10d565efSmrg   HANDLE h = (HANDLE) _get_osfhandle (fd);
953*10d565efSmrg   if (h == INVALID_HANDLE_VALUE)
954*10d565efSmrg     return NULL;
955*10d565efSmrg   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
956*10d565efSmrg     return NULL;
957*10d565efSmrg   return fdopen (fd, binary ? "rb" : "r");
958*10d565efSmrg }
959*10d565efSmrg 
960*10d565efSmrg static FILE *
961*10d565efSmrg pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
962*10d565efSmrg 		   int binary)
963*10d565efSmrg {
964*10d565efSmrg   HANDLE h = (HANDLE) _get_osfhandle (fd);
965*10d565efSmrg   if (h == INVALID_HANDLE_VALUE)
966*10d565efSmrg     return NULL;
967*10d565efSmrg   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
968*10d565efSmrg     return NULL;
969*10d565efSmrg   return fdopen (fd, binary ? "wb" : "w");
970*10d565efSmrg }
971*10d565efSmrg 
972*10d565efSmrg #ifdef MAIN
973*10d565efSmrg #include <stdio.h>
974*10d565efSmrg 
975*10d565efSmrg int
976*10d565efSmrg main (int argc ATTRIBUTE_UNUSED, char **argv)
977*10d565efSmrg {
978*10d565efSmrg   char const *errmsg;
979*10d565efSmrg   int err;
980*10d565efSmrg   argv++;
981*10d565efSmrg   printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
982*10d565efSmrg   exit (0);
983*10d565efSmrg }
984*10d565efSmrg #endif
985