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