OSDN Git Service

libiberty/
[pf3gnuchains/gcc-fork.git] / libiberty / pex-win32.c
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   return fdopen (fd, binary ? "rb" : "r");
919 }
920
921 static FILE *
922 pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
923                    int binary)
924 {
925   HANDLE h = (HANDLE) _get_osfhandle (fd);
926   if (h == INVALID_HANDLE_VALUE)
927     return NULL;
928   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
929     return NULL;
930   return fdopen (fd, binary ? "wb" : "w");
931 }
932
933 #ifdef MAIN
934 #include <stdio.h>
935
936 int
937 main (int argc ATTRIBUTE_UNUSED, char **argv)
938 {
939   char const *errmsg;
940   int err;
941   argv++;
942   printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
943   exit (0);
944 }
945 #endif