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