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