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