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, int);
82static pid_t 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 pid_t pex_win32_wait (struct pex_obj *, pid_t, 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, int append)
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  if (append)
134    return -1;
135  return _open (name,
136		(_O_WRONLY | _O_CREAT | _O_TRUNC
137		 | (binary ? _O_BINARY : _O_TEXT)),
138		_S_IREAD | _S_IWRITE);
139}
140
141/* Close a file.  */
142
143static int
144pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
145{
146  return _close (fd);
147}
148
149#ifdef USE_MINGW_MSYS
150static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
151
152/* Tack the executable on the end of a (possibly slash terminated) buffer
153   and convert everything to \. */
154static const char *
155tack_on_executable (char *buf, const char *executable)
156{
157  char *p = strchr (buf, '\0');
158  if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
159    p[-1] = '\0';
160  backslashify (strcat (buf, executable));
161  return buf;
162}
163
164/* Walk down a registry hierarchy until the end.  Return the key. */
165static HKEY
166openkey (HKEY hStart, const char *keys[])
167{
168  HKEY hKey, hTmp;
169  for (hKey = hStart; *keys; keys++)
170    {
171      LONG res;
172      hTmp = hKey;
173      res = RegOpenKey (hTmp, *keys, &hKey);
174
175      if (hTmp != HKEY_LOCAL_MACHINE)
176	RegCloseKey (hTmp);
177
178      if (res != ERROR_SUCCESS)
179	return NULL;
180    }
181  return hKey;
182}
183
184/* Return the "mingw root" as derived from the mingw uninstall information. */
185static const char *
186mingw_rootify (const char *executable)
187{
188  HKEY hKey, hTmp;
189  DWORD maxlen;
190  char *namebuf, *foundbuf;
191  DWORD i;
192  LONG res;
193
194  /* Open the uninstall "directory". */
195  hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
196
197  /* Not found. */
198  if (!hKey)
199    return executable;
200
201  /* Need to enumerate all of the keys here looking for one the most recent
202     one for MinGW. */
203  if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
204		       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
205    {
206      RegCloseKey (hKey);
207      return executable;
208    }
209  namebuf = XNEWVEC (char, ++maxlen);
210  foundbuf = XNEWVEC (char, maxlen);
211  foundbuf[0] = '\0';
212  if (!namebuf || !foundbuf)
213    {
214      RegCloseKey (hKey);
215      free (namebuf);
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  free (buf);
319  return executable;
320}
321#endif
322
323/* Return the number of arguments in an argv array, not including the null
324   terminating argument. */
325
326static int
327argv_to_argc (char *const *argv)
328{
329  char *const *i = argv;
330  while (*i)
331    i++;
332  return i - argv;
333}
334
335/* Return a Windows command-line from ARGV.  It is the caller's
336   responsibility to free the string returned.  */
337
338static char *
339argv_to_cmdline (char *const *argv)
340{
341  char *cmdline;
342  char *p;
343  size_t cmdline_len;
344  int i, j, k;
345  int needs_quotes;
346
347  cmdline_len = 0;
348  for (i = 0; argv[i]; i++)
349    {
350      /* We only quote arguments that contain spaces, \t or " characters to
351	 prevent wasting 2 chars per argument of the CreateProcess 32k char
352	 limit.  We need only escape embedded double-quotes and immediately
353	 preceeding backslash characters.  A sequence of backslach characters
354	 that is not follwed by a double quote character will not be
355	 escaped.  */
356      needs_quotes = 0;
357      for (j = 0; argv[i][j]; j++)
358	{
359	  if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
360	    {
361	      needs_quotes = 1;
362	    }
363
364	  if (argv[i][j] == '"')
365	    {
366	      /* Escape preceeding backslashes.  */
367	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
368		cmdline_len++;
369	      /* Escape the qote character.  */
370	      cmdline_len++;
371	    }
372	}
373      if (j == 0)
374	needs_quotes = 1;
375      /* Trailing backslashes also need to be escaped because they will be
376         followed by the terminating quote.  */
377      if (needs_quotes)
378        {
379          for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
380            cmdline_len++;
381        }
382      cmdline_len += j;
383      /* for leading and trailing quotes and space */
384      cmdline_len += needs_quotes * 2 + 1;
385    }
386  cmdline = XNEWVEC (char, cmdline_len);
387  p = cmdline;
388  for (i = 0; argv[i]; i++)
389    {
390      needs_quotes = 0;
391      for (j = 0; argv[i][j]; j++)
392        {
393          if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
394            {
395              needs_quotes = 1;
396              break;
397            }
398        }
399      if (j == 0)
400	needs_quotes = 1;
401
402      if (needs_quotes)
403        {
404          *p++ = '"';
405        }
406      for (j = 0; argv[i][j]; j++)
407	{
408	  if (argv[i][j] == '"')
409	    {
410	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
411		*p++ = '\\';
412	      *p++ = '\\';
413	    }
414	  *p++ = argv[i][j];
415	}
416      if (needs_quotes)
417        {
418          for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
419            *p++ = '\\';
420          *p++ = '"';
421        }
422      *p++ = ' ';
423    }
424  p[-1] = '\0';
425  return cmdline;
426}
427
428/* We'll try the passed filename with all the known standard
429   extensions, and then without extension.  We try no extension
430   last so that we don't try to run some random extension-less
431   file that might be hanging around.  We try both extension
432   and no extension so that we don't need any fancy logic
433   to determine if a file has extension.  */
434static const char *const
435std_suffixes[] = {
436  ".com",
437  ".exe",
438  ".bat",
439  ".cmd",
440  "",
441  0
442};
443
444/* Returns the full path to PROGRAM.  If SEARCH is true, look for
445   PROGRAM in each directory in PATH.  */
446
447static char *
448find_executable (const char *program, BOOL search)
449{
450  char *full_executable;
451  char *e;
452  size_t fe_len;
453  const char *path = 0;
454  const char *const *ext;
455  const char *p, *q;
456  size_t proglen = strlen (program);
457  int has_slash = (strchr (program, '/') || strchr (program, '\\'));
458  HANDLE h;
459
460  if (has_slash)
461    search = FALSE;
462
463  if (search)
464    path = getenv ("PATH");
465  if (!path)
466    path = "";
467
468  fe_len = 0;
469  for (p = path; *p; p = q)
470    {
471      q = p;
472      while (*q != ';' && *q != '\0')
473	q++;
474      if ((size_t)(q - p) > fe_len)
475	fe_len = q - p;
476      if (*q == ';')
477	q++;
478    }
479  fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
480  full_executable = XNEWVEC (char, fe_len);
481
482  p = path;
483  do
484    {
485      q = p;
486      while (*q != ';' && *q != '\0')
487	q++;
488
489      e = full_executable;
490      memcpy (e, p, q - p);
491      e += (q - p);
492      if (q - p)
493	*e++ = '\\';
494      strcpy (e, program);
495
496      if (*q == ';')
497	q++;
498
499      for (e = full_executable; *e; e++)
500	if (*e == '/')
501	  *e = '\\';
502
503      /* At this point, e points to the terminating NUL character for
504         full_executable.  */
505      for (ext = std_suffixes; *ext; ext++)
506	{
507	  /* Remove any current extension.  */
508	  *e = '\0';
509	  /* Add the new one.  */
510	  strcat (full_executable, *ext);
511
512	  /* Attempt to open this file.  */
513	  h = CreateFile (full_executable, GENERIC_READ,
514			  FILE_SHARE_READ | FILE_SHARE_WRITE,
515			  0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
516	  if (h != INVALID_HANDLE_VALUE)
517	    goto found;
518	}
519      p = q;
520    }
521  while (*p);
522  free (full_executable);
523  return 0;
524
525 found:
526  CloseHandle (h);
527  return full_executable;
528}
529
530/* Low-level process creation function and helper.  */
531
532static int
533env_compare (const void *a_ptr, const void *b_ptr)
534{
535  const char *a;
536  const char *b;
537  unsigned char c1;
538  unsigned char c2;
539
540  a = *(const char **) a_ptr;
541  b = *(const char **) b_ptr;
542
543  /* a and b will be of the form: VAR=VALUE
544     We compare only the variable name part here using a case-insensitive
545     comparison algorithm.  It might appear that in fact strcasecmp () can
546     take the place of this whole function, and indeed it could, save for
547     the fact that it would fail in cases such as comparing A1=foo and
548     A=bar (because 1 is less than = in the ASCII character set).
549     (Environment variables containing no numbers would work in such a
550     scenario.)  */
551
552  do
553    {
554      c1 = (unsigned char) tolower (*a++);
555      c2 = (unsigned char) tolower (*b++);
556
557      if (c1 == '=')
558        c1 = '\0';
559
560      if (c2 == '=')
561        c2 = '\0';
562    }
563  while (c1 == c2 && c1 != '\0');
564
565  return c1 - c2;
566}
567
568/* Execute a Windows executable as a child process.  This will fail if the
569 * target is not actually an executable, such as if it is a shell script. */
570
571static pid_t
572win32_spawn (const char *executable,
573	     BOOL search,
574	     char *const *argv,
575             char *const *env, /* array of strings of the form: VAR=VALUE */
576	     DWORD dwCreationFlags,
577	     LPSTARTUPINFO si,
578	     LPPROCESS_INFORMATION pi)
579{
580  char *full_executable;
581  char *cmdline;
582  char **env_copy;
583  char *env_block = NULL;
584
585  full_executable = NULL;
586  cmdline = NULL;
587
588  if (env)
589    {
590      int env_size;
591
592      /* Count the number of environment bindings supplied.  */
593      for (env_size = 0; env[env_size]; env_size++)
594        continue;
595
596      /* Assemble an environment block, if required.  This consists of
597         VAR=VALUE strings juxtaposed (with one null character between each
598         pair) and an additional null at the end.  */
599      if (env_size > 0)
600        {
601          int var;
602          int total_size = 1; /* 1 is for the final null.  */
603          char *bufptr;
604
605          /* Windows needs the members of the block to be sorted by variable
606             name.  */
607          env_copy = (char **) alloca (sizeof (char *) * env_size);
608          memcpy (env_copy, env, sizeof (char *) * env_size);
609          qsort (env_copy, env_size, sizeof (char *), env_compare);
610
611          for (var = 0; var < env_size; var++)
612            total_size += strlen (env[var]) + 1;
613
614          env_block = XNEWVEC (char, total_size);
615          bufptr = env_block;
616          for (var = 0; var < env_size; var++)
617            bufptr = stpcpy (bufptr, env_copy[var]) + 1;
618
619          *bufptr = '\0';
620        }
621    }
622
623  full_executable = find_executable (executable, search);
624  if (!full_executable)
625    goto error;
626  cmdline = argv_to_cmdline (argv);
627  if (!cmdline)
628    goto error;
629
630  /* Create the child process.  */
631  if (!CreateProcess (full_executable, cmdline,
632		      /*lpProcessAttributes=*/NULL,
633		      /*lpThreadAttributes=*/NULL,
634		      /*bInheritHandles=*/TRUE,
635		      dwCreationFlags,
636		      (LPVOID) env_block,
637		      /*lpCurrentDirectory=*/NULL,
638		      si,
639		      pi))
640    {
641      free (env_block);
642
643      free (full_executable);
644
645      return (pid_t) -1;
646    }
647
648  /* Clean up.  */
649  CloseHandle (pi->hThread);
650  free (full_executable);
651  free (env_block);
652
653  return (pid_t) pi->hProcess;
654
655 error:
656  free (env_block);
657  free (cmdline);
658  free (full_executable);
659
660  return (pid_t) -1;
661}
662
663/* Spawn a script.  This simulates the Unix script execution mechanism.
664   This function is called as a fallback if win32_spawn fails. */
665
666static pid_t
667spawn_script (const char *executable, char *const *argv,
668              char* const *env,
669	      DWORD dwCreationFlags,
670	      LPSTARTUPINFO si,
671	      LPPROCESS_INFORMATION pi)
672{
673  pid_t pid = (pid_t) -1;
674  int save_errno = errno;
675  int fd = _open (executable, _O_RDONLY);
676
677  /* Try to open script, check header format, extract interpreter path,
678     and spawn script using that interpretter. */
679  if (fd >= 0)
680    {
681      char buf[MAX_PATH + 5];
682      int len = _read (fd, buf, sizeof (buf) - 1);
683      _close (fd);
684      if (len > 3)
685	{
686	  char *eol;
687	  buf[len] = '\0';
688	  eol = strchr (buf, '\n');
689	  if (eol && strncmp (buf, "#!", 2) == 0)
690	    {
691
692	      /* Header format is OK. */
693	      char *executable1;
694              int new_argc;
695              const char **avhere;
696
697	      /* Extract interpreter path. */
698	      do
699		*eol = '\0';
700	      while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
701	      for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
702		continue;
703	      backslashify (executable1);
704
705	      /* Duplicate argv, prepending the interpreter path. */
706	      new_argc = argv_to_argc (argv) + 1;
707	      avhere = XNEWVEC (const char *, new_argc + 1);
708	      *avhere = executable1;
709	      memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
710	      argv = (char *const *)avhere;
711
712	      /* Spawn the child. */
713#ifndef USE_MINGW_MSYS
714	      executable = strrchr (executable1, '\\') + 1;
715	      if (!executable)
716		executable = executable1;
717	      pid = win32_spawn (executable, TRUE, argv, env,
718				 dwCreationFlags, si, pi);
719#else
720	      if (strchr (executable1, '\\') == NULL)
721		pid = win32_spawn (executable1, TRUE, argv, env,
722				   dwCreationFlags, si, pi);
723	      else if (executable1[0] != '\\')
724		pid = win32_spawn (executable1, FALSE, argv, env,
725				   dwCreationFlags, si, pi);
726	      else
727		{
728		  const char *newex = mingw_rootify (executable1);
729		  *avhere = newex;
730		  pid = win32_spawn (newex, FALSE, argv, env,
731				     dwCreationFlags, si, pi);
732		  if (executable1 != newex)
733		    free ((char *) newex);
734		  if (pid == (pid_t) -1)
735		    {
736		      newex = msys_rootify (executable1);
737		      if (newex != executable1)
738			{
739			  *avhere = newex;
740			  pid = win32_spawn (newex, FALSE, argv, env,
741					     dwCreationFlags, si, pi);
742			  free ((char *) newex);
743			}
744		    }
745		}
746#endif
747	      free (avhere);
748	    }
749	}
750    }
751  if (pid == (pid_t) -1)
752    errno = save_errno;
753  return pid;
754}
755
756/* Execute a child.  */
757
758static pid_t
759pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
760		      const char *executable, char * const * argv,
761                      char* const* env,
762		      int in, int out, int errdes,
763		      int toclose ATTRIBUTE_UNUSED,
764		      const char **errmsg,
765		      int *err)
766{
767  pid_t pid;
768  HANDLE stdin_handle;
769  HANDLE stdout_handle;
770  HANDLE stderr_handle;
771  DWORD dwCreationFlags;
772  OSVERSIONINFO version_info;
773  STARTUPINFO si;
774  PROCESS_INFORMATION pi;
775  int orig_out, orig_in, orig_err;
776  BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
777
778  /* Ensure we have inheritable descriptors to pass to the child.  */
779  orig_in = in;
780  in = _dup (orig_in);
781
782  orig_out = out;
783  out = _dup (orig_out);
784
785  if (separate_stderr)
786    {
787      orig_err = errdes;
788      errdes = _dup (orig_err);
789    }
790
791  stdin_handle = INVALID_HANDLE_VALUE;
792  stdout_handle = INVALID_HANDLE_VALUE;
793  stderr_handle = INVALID_HANDLE_VALUE;
794
795  stdin_handle = (HANDLE) _get_osfhandle (in);
796  stdout_handle = (HANDLE) _get_osfhandle (out);
797  if (separate_stderr)
798    stderr_handle = (HANDLE) _get_osfhandle (errdes);
799  else
800    stderr_handle = stdout_handle;
801
802  /* Determine the version of Windows we are running on.  */
803  version_info.dwOSVersionInfoSize = sizeof (version_info);
804  GetVersionEx (&version_info);
805  if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
806    /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
807       supported, so we cannot avoid creating a console window.  */
808    dwCreationFlags = 0;
809  else
810    {
811      HANDLE conout_handle;
812
813      /* Determine whether or not we have an associated console.  */
814      conout_handle = CreateFile("CONOUT$",
815				 GENERIC_WRITE,
816				 FILE_SHARE_WRITE,
817				 /*lpSecurityAttributes=*/NULL,
818				 OPEN_EXISTING,
819				 FILE_ATTRIBUTE_NORMAL,
820				 /*hTemplateFile=*/NULL);
821      if (conout_handle == INVALID_HANDLE_VALUE)
822	/* There is no console associated with this process.  Since
823	   the child is a console process, the OS would normally
824	   create a new console Window for the child.  Since we'll be
825	   redirecting the child's standard streams, we do not need
826	   the console window.  */
827	dwCreationFlags = CREATE_NO_WINDOW;
828      else
829	{
830	  /* There is a console associated with the process, so the OS
831	     will not create a new console.  And, if we use
832	     CREATE_NO_WINDOW in this situation, the child will have
833	     no associated console.  Therefore, if the child's
834	     standard streams are connected to the console, the output
835	     will be discarded.  */
836	  CloseHandle(conout_handle);
837	  dwCreationFlags = 0;
838	}
839    }
840
841  /* Since the child will be a console process, it will, by default,
842     connect standard input/output to its console.  However, we want
843     the child to use the handles specifically designated above.  In
844     addition, if there is no console (such as when we are running in
845     a Cygwin X window), then we must redirect the child's
846     input/output, as there is no console for the child to use.  */
847  memset (&si, 0, sizeof (si));
848  si.cb = sizeof (si);
849  si.dwFlags = STARTF_USESTDHANDLES;
850  si.hStdInput = stdin_handle;
851  si.hStdOutput = stdout_handle;
852  si.hStdError = stderr_handle;
853
854  /* Create the child process.  */
855  pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
856		     argv, env, dwCreationFlags, &si, &pi);
857  if (pid == (pid_t) -1)
858    pid = spawn_script (executable, argv, env, dwCreationFlags,
859                        &si, &pi);
860  if (pid == (pid_t) -1)
861    {
862      *err = ENOENT;
863      *errmsg = "CreateProcess";
864    }
865
866  /* If the child was created successfully, close the original file
867     descriptors.  If the process creation fails, these are closed by
868     pex_run_in_environment instead.  We must not close them twice as
869     that seems to cause a Windows exception.  */
870
871  if (pid != (pid_t) -1)
872    {
873      if (orig_in != STDIN_FILENO)
874	_close (orig_in);
875      if (orig_out != STDOUT_FILENO)
876	_close (orig_out);
877      if (separate_stderr
878	  && orig_err != STDERR_FILENO)
879	_close (orig_err);
880    }
881
882  /* Close the standard input, standard output and standard error handles
883     in the parent.  */
884
885  _close (in);
886  _close (out);
887  if (separate_stderr)
888    _close (errdes);
889
890  return pid;
891}
892
893/* Wait for a child process to complete.  MS CRTDLL doesn't return
894   enough information in status to decide if the child exited due to a
895   signal or not, rather it simply returns an integer with the exit
896   code of the child; eg., if the child exited with an abort() call
897   and didn't have a handler for SIGABRT, it simply returns with
898   status == 3.  We fix the status code to conform to the usual WIF*
899   macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
900
901static pid_t
902pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
903		int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
904		const char **errmsg, int *err)
905{
906  DWORD termstat;
907  HANDLE h;
908
909  if (time != NULL)
910    memset (time, 0, sizeof *time);
911
912  h = (HANDLE) pid;
913
914  /* FIXME: If done is non-zero, we should probably try to kill the
915     process.  */
916  if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
917    {
918      CloseHandle (h);
919      *err = ECHILD;
920      *errmsg = "WaitForSingleObject";
921      return -1;
922    }
923
924  GetExitCodeProcess (h, &termstat);
925  CloseHandle (h);
926
927  /* A value of 3 indicates that the child caught a signal, but not
928     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
929     report SIGABRT.  */
930  if (termstat == 3)
931    *status = SIGABRT;
932  else
933    *status = (termstat & 0xff) << 8;
934
935  return 0;
936}
937
938/* Create a pipe.  */
939
940static int
941pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
942		int binary)
943{
944  return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
945}
946
947/* Get a FILE pointer to read from a file descriptor.  */
948
949static FILE *
950pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
951		   int binary)
952{
953  HANDLE h = (HANDLE) _get_osfhandle (fd);
954  if (h == INVALID_HANDLE_VALUE)
955    return NULL;
956  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
957    return NULL;
958  return fdopen (fd, binary ? "rb" : "r");
959}
960
961static FILE *
962pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
963		   int binary)
964{
965  HANDLE h = (HANDLE) _get_osfhandle (fd);
966  if (h == INVALID_HANDLE_VALUE)
967    return NULL;
968  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
969    return NULL;
970  return fdopen (fd, binary ? "wb" : "w");
971}
972
973#ifdef MAIN
974#include <stdio.h>
975
976int
977main (int argc ATTRIBUTE_UNUSED, char **argv)
978{
979  char const *errmsg;
980  int err;
981  argv++;
982  printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
983  exit (0);
984}
985#endif
986