OSDN Git Service

2014-05-07 Richard Biener <rguenther@suse.de>
[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       free (namebuf);
214       free (foundbuf);
215       return executable;
216     }
217
218   /* Look through all of the keys for one that begins with Minimal GNU...
219      Try to get the latest version by doing a string compare although that
220      string never really works with version number sorting. */
221   for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
222     {
223       int match = strcasecmp (namebuf, MINGW_NAME);
224       if (match < 0)
225         continue;
226       if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
227         continue;
228       if (strcasecmp (namebuf, foundbuf) > 0)
229         strcpy (foundbuf, namebuf);
230     }
231   free (namebuf);
232
233   /* If foundbuf is empty, we didn't find anything.  Punt. */
234   if (!foundbuf[0])
235     {
236       free (foundbuf);
237       RegCloseKey (hKey);
238       return executable;
239     }
240
241   /* Open the key that we wanted */
242   res = RegOpenKey (hKey, foundbuf, &hTmp);
243   RegCloseKey (hKey);
244   free (foundbuf);
245
246   /* Don't know why this would fail, but you gotta check */
247   if (res != ERROR_SUCCESS)
248     return executable;
249
250   maxlen = 0;
251   /* Get the length of the value pointed to by InstallLocation */
252   if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
253                        &maxlen) != ERROR_SUCCESS || maxlen == 0)
254     {
255       RegCloseKey (hTmp);
256       return executable;
257     }
258
259   /* Allocate space for the install location */
260   foundbuf = XNEWVEC (char, maxlen + strlen (executable));
261   if (!foundbuf)
262     {
263       free (foundbuf);
264       RegCloseKey (hTmp);
265     }
266
267   /* Read the install location into the buffer */
268   res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
269                          &maxlen);
270   RegCloseKey (hTmp);
271   if (res != ERROR_SUCCESS)
272     {
273       free (foundbuf);
274       return executable;
275     }
276
277   /* Concatenate the install location and the executable, turn all slashes
278      to backslashes, and return that. */
279   return tack_on_executable (foundbuf, executable);
280 }
281
282 /* Read the install location of msys from it's installation file and
283    rootify the executable based on that. */
284 static const char *
285 msys_rootify (const char *executable)
286 {
287   size_t bufsize = 64;
288   size_t execlen = strlen (executable) + 1;
289   char *buf;
290   DWORD res = 0;
291   for (;;)
292     {
293       buf = XNEWVEC (char, bufsize + execlen);
294       if (!buf)
295         break;
296       res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
297                                      buf, bufsize, "msys.ini");
298       if (!res)
299         break;
300       if (strlen (buf) < bufsize)
301         break;
302       res = 0;
303       free (buf);
304       bufsize *= 2;
305       if (bufsize > 65536)
306         {
307           buf = NULL;
308           break;
309         }
310     }
311
312   if (res)
313     return tack_on_executable (buf, executable);
314
315   /* failed */
316   free (buf);
317   return executable;
318 }
319 #endif
320
321 /* Return the number of arguments in an argv array, not including the null
322    terminating argument. */
323
324 static int
325 argv_to_argc (char *const *argv)
326 {
327   char *const *i = argv;
328   while (*i)
329     i++;
330   return i - argv;
331 }
332
333 /* Return a Windows command-line from ARGV.  It is the caller's
334    responsibility to free the string returned.  */
335
336 static char *
337 argv_to_cmdline (char *const *argv)
338 {
339   char *cmdline;
340   char *p;
341   size_t cmdline_len;
342   int i, j, k;
343
344   cmdline_len = 0;
345   for (i = 0; argv[i]; i++)
346     {
347       /* We quote every last argument.  This simplifies the problem;
348          we need only escape embedded double-quotes and immediately
349          preceeding backslash characters.  A sequence of backslach characters
350          that is not follwed by a double quote character will not be
351          escaped.  */
352       for (j = 0; argv[i][j]; j++)
353         {
354           if (argv[i][j] == '"')
355             {
356               /* Escape preceeding backslashes.  */
357               for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
358                 cmdline_len++;
359               /* Escape the qote character.  */
360               cmdline_len++;
361             }
362         }
363       /* Trailing backslashes also need to be escaped because they will be
364          followed by the terminating quote.  */
365       for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
366         cmdline_len++;
367       cmdline_len += j;
368       cmdline_len += 3;  /* for leading and trailing quotes and space */
369     }
370   cmdline = XNEWVEC (char, cmdline_len);
371   p = cmdline;
372   for (i = 0; argv[i]; i++)
373     {
374       *p++ = '"';
375       for (j = 0; argv[i][j]; j++)
376         {
377           if (argv[i][j] == '"')
378             {
379               for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
380                 *p++ = '\\';
381               *p++ = '\\';
382             }
383           *p++ = argv[i][j];
384         }
385       for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
386         *p++ = '\\';
387       *p++ = '"';
388       *p++ = ' ';
389     }
390   p[-1] = '\0';
391   return cmdline;
392 }
393
394 /* We'll try the passed filename with all the known standard
395    extensions, and then without extension.  We try no extension
396    last so that we don't try to run some random extension-less
397    file that might be hanging around.  We try both extension
398    and no extension so that we don't need any fancy logic
399    to determine if a file has extension.  */
400 static const char *const
401 std_suffixes[] = {
402   ".com",
403   ".exe",
404   ".bat",
405   ".cmd",
406   "",
407   0
408 };
409
410 /* Returns the full path to PROGRAM.  If SEARCH is true, look for
411    PROGRAM in each directory in PATH.  */
412
413 static char *
414 find_executable (const char *program, BOOL search)
415 {
416   char *full_executable;
417   char *e;
418   size_t fe_len;
419   const char *path = 0;
420   const char *const *ext;
421   const char *p, *q;
422   size_t proglen = strlen (program);
423   int has_slash = (strchr (program, '/') || strchr (program, '\\'));
424   HANDLE h;
425
426   if (has_slash)
427     search = FALSE;
428
429   if (search)
430     path = getenv ("PATH");
431   if (!path)
432     path = "";
433
434   fe_len = 0;
435   for (p = path; *p; p = q)
436     {
437       q = p;
438       while (*q != ';' && *q != '\0')
439         q++;
440       if ((size_t)(q - p) > fe_len)
441         fe_len = q - p;
442       if (*q == ';')
443         q++;
444     }
445   fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
446   full_executable = XNEWVEC (char, fe_len);
447
448   p = path;
449   do
450     {
451       q = p;
452       while (*q != ';' && *q != '\0')
453         q++;
454
455       e = full_executable;
456       memcpy (e, p, q - p);
457       e += (q - p);
458       if (q - p)
459         *e++ = '\\';
460       strcpy (e, program);
461
462       if (*q == ';')
463         q++;
464
465       for (e = full_executable; *e; e++)
466         if (*e == '/')
467           *e = '\\';
468
469       /* At this point, e points to the terminating NUL character for
470          full_executable.  */
471       for (ext = std_suffixes; *ext; ext++)
472         {
473           /* Remove any current extension.  */
474           *e = '\0';
475           /* Add the new one.  */
476           strcat (full_executable, *ext);
477
478           /* Attempt to open this file.  */
479           h = CreateFile (full_executable, GENERIC_READ,
480                           FILE_SHARE_READ | FILE_SHARE_WRITE,
481                           0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
482           if (h != INVALID_HANDLE_VALUE)
483             goto found;
484         }
485       p = q;
486     }
487   while (*p);
488   free (full_executable);
489   return 0;
490
491  found:
492   CloseHandle (h);
493   return full_executable;
494 }
495
496 /* Low-level process creation function and helper.  */
497
498 static int
499 env_compare (const void *a_ptr, const void *b_ptr)
500 {
501   const char *a;
502   const char *b;
503   unsigned char c1;
504   unsigned char c2;
505
506   a = *(const char **) a_ptr;
507   b = *(const char **) b_ptr;
508
509   /* a and b will be of the form: VAR=VALUE
510      We compare only the variable name part here using a case-insensitive
511      comparison algorithm.  It might appear that in fact strcasecmp () can
512      take the place of this whole function, and indeed it could, save for
513      the fact that it would fail in cases such as comparing A1=foo and
514      A=bar (because 1 is less than = in the ASCII character set).
515      (Environment variables containing no numbers would work in such a
516      scenario.)  */
517
518   do
519     {
520       c1 = (unsigned char) tolower (*a++);
521       c2 = (unsigned char) tolower (*b++);
522
523       if (c1 == '=')
524         c1 = '\0';
525
526       if (c2 == '=')
527         c2 = '\0';
528     }
529   while (c1 == c2 && c1 != '\0');
530
531   return c1 - c2;
532 }
533
534 /* Execute a Windows executable as a child process.  This will fail if the
535  * target is not actually an executable, such as if it is a shell script. */
536
537 static pid_t
538 win32_spawn (const char *executable,
539              BOOL search,
540              char *const *argv,
541              char *const *env, /* array of strings of the form: VAR=VALUE */
542              DWORD dwCreationFlags,
543              LPSTARTUPINFO si,
544              LPPROCESS_INFORMATION pi)
545 {
546   char *full_executable;
547   char *cmdline;
548   char **env_copy;
549   char *env_block = NULL;
550
551   full_executable = NULL;
552   cmdline = NULL;
553
554   if (env)
555     {
556       int env_size;
557
558       /* Count the number of environment bindings supplied.  */
559       for (env_size = 0; env[env_size]; env_size++)
560         continue;
561     
562       /* Assemble an environment block, if required.  This consists of
563          VAR=VALUE strings juxtaposed (with one null character between each
564          pair) and an additional null at the end.  */
565       if (env_size > 0)
566         {
567           int var;
568           int total_size = 1; /* 1 is for the final null.  */
569           char *bufptr;
570     
571           /* Windows needs the members of the block to be sorted by variable
572              name.  */
573           env_copy = (char **) alloca (sizeof (char *) * env_size);
574           memcpy (env_copy, env, sizeof (char *) * env_size);
575           qsort (env_copy, env_size, sizeof (char *), env_compare);
576     
577           for (var = 0; var < env_size; var++)
578             total_size += strlen (env[var]) + 1;
579     
580           env_block = XNEWVEC (char, total_size);
581           bufptr = env_block;
582           for (var = 0; var < env_size; var++)
583             bufptr = stpcpy (bufptr, env_copy[var]) + 1;
584     
585           *bufptr = '\0';
586         }
587     }
588
589   full_executable = find_executable (executable, search);
590   if (!full_executable)
591     goto error;
592   cmdline = argv_to_cmdline (argv);
593   if (!cmdline)
594     goto error;
595     
596   /* Create the child process.  */  
597   if (!CreateProcess (full_executable, cmdline, 
598                       /*lpProcessAttributes=*/NULL,
599                       /*lpThreadAttributes=*/NULL,
600                       /*bInheritHandles=*/TRUE,
601                       dwCreationFlags,
602                       (LPVOID) env_block,
603                       /*lpCurrentDirectory=*/NULL,
604                       si,
605                       pi))
606     {
607       free (env_block);
608
609       free (full_executable);
610
611       return (pid_t) -1;
612     }
613
614   /* Clean up.  */
615   CloseHandle (pi->hThread);
616   free (full_executable);
617   free (env_block);
618
619   return (pid_t) pi->hProcess;
620
621  error:
622   free (env_block);
623   free (cmdline);
624   free (full_executable);
625
626   return (pid_t) -1;
627 }
628
629 /* Spawn a script.  This simulates the Unix script execution mechanism.
630    This function is called as a fallback if win32_spawn fails. */
631
632 static pid_t
633 spawn_script (const char *executable, char *const *argv,
634               char* const *env,
635               DWORD dwCreationFlags,
636               LPSTARTUPINFO si,
637               LPPROCESS_INFORMATION pi)
638 {
639   pid_t pid = (pid_t) -1;
640   int save_errno = errno;
641   int fd = _open (executable, _O_RDONLY);
642
643   /* Try to open script, check header format, extract interpreter path,
644      and spawn script using that interpretter. */
645   if (fd >= 0)
646     {
647       char buf[MAX_PATH + 5];
648       int len = _read (fd, buf, sizeof (buf) - 1);
649       _close (fd);
650       if (len > 3)
651         {
652           char *eol;
653           buf[len] = '\0';
654           eol = strchr (buf, '\n');
655           if (eol && strncmp (buf, "#!", 2) == 0)
656             {
657             
658               /* Header format is OK. */
659               char *executable1;
660               int new_argc;
661               const char **avhere;
662
663               /* Extract interpreter path. */
664               do
665                 *eol = '\0';
666               while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
667               for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
668                 continue;
669               backslashify (executable1);
670
671               /* Duplicate argv, prepending the interpreter path. */
672               new_argc = argv_to_argc (argv) + 1;
673               avhere = XNEWVEC (const char *, new_argc + 1);
674               *avhere = executable1;
675               memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
676               argv = (char *const *)avhere;
677
678               /* Spawn the child. */
679 #ifndef USE_MINGW_MSYS
680               executable = strrchr (executable1, '\\') + 1;
681               if (!executable)
682                 executable = executable1;
683               pid = win32_spawn (executable, TRUE, argv, env,
684                                  dwCreationFlags, si, pi);
685 #else
686               if (strchr (executable1, '\\') == NULL)
687                 pid = win32_spawn (executable1, TRUE, argv, env,
688                                    dwCreationFlags, si, pi);
689               else if (executable1[0] != '\\')
690                 pid = win32_spawn (executable1, FALSE, argv, env,
691                                    dwCreationFlags, si, pi);
692               else
693                 {
694                   const char *newex = mingw_rootify (executable1);
695                   *avhere = newex;
696                   pid = win32_spawn (newex, FALSE, argv, env,
697                                      dwCreationFlags, si, pi);
698                   if (executable1 != newex)
699                     free ((char *) newex);
700                   if (pid == (pid_t) -1)
701                     {
702                       newex = msys_rootify (executable1);
703                       if (newex != executable1)
704                         {
705                           *avhere = newex;
706                           pid = win32_spawn (newex, FALSE, argv, env,
707                                              dwCreationFlags, si, pi);
708                           free ((char *) newex);
709                         }
710                     }
711                 }
712 #endif
713               free (avhere);
714             }
715         }
716     }
717   if (pid == (pid_t) -1)
718     errno = save_errno;
719   return pid;
720 }
721
722 /* Execute a child.  */
723
724 static pid_t
725 pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
726                       const char *executable, char * const * argv,
727                       char* const* env,
728                       int in, int out, int errdes,
729                       int toclose ATTRIBUTE_UNUSED,
730                       const char **errmsg,
731                       int *err)
732 {
733   pid_t pid;
734   HANDLE stdin_handle;
735   HANDLE stdout_handle;
736   HANDLE stderr_handle;
737   DWORD dwCreationFlags;
738   OSVERSIONINFO version_info;
739   STARTUPINFO si;
740   PROCESS_INFORMATION pi;
741   int orig_out, orig_in, orig_err;
742   BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
743
744   /* Ensure we have inheritable descriptors to pass to the child, and close the
745      original descriptors.  */
746   orig_in = in;
747   in = _dup (orig_in);
748   if (orig_in != STDIN_FILENO)
749     _close (orig_in);
750   
751   orig_out = out;
752   out = _dup (orig_out);
753   if (orig_out != STDOUT_FILENO)
754     _close (orig_out);
755   
756   if (separate_stderr)
757     {
758       orig_err = errdes;
759       errdes = _dup (orig_err);
760       if (orig_err != STDERR_FILENO)
761         _close (orig_err);
762     }
763
764   stdin_handle = INVALID_HANDLE_VALUE;
765   stdout_handle = INVALID_HANDLE_VALUE;
766   stderr_handle = INVALID_HANDLE_VALUE;
767
768   stdin_handle = (HANDLE) _get_osfhandle (in);
769   stdout_handle = (HANDLE) _get_osfhandle (out);
770   if (separate_stderr)
771     stderr_handle = (HANDLE) _get_osfhandle (errdes);
772   else
773     stderr_handle = stdout_handle;
774
775   /* Determine the version of Windows we are running on.  */
776   version_info.dwOSVersionInfoSize = sizeof (version_info); 
777   GetVersionEx (&version_info);
778   if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
779     /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
780        supported, so we cannot avoid creating a console window.  */
781     dwCreationFlags = 0;
782   else
783     {
784       HANDLE conout_handle;
785
786       /* Determine whether or not we have an associated console.  */
787       conout_handle = CreateFile("CONOUT$", 
788                                  GENERIC_WRITE,
789                                  FILE_SHARE_WRITE,
790                                  /*lpSecurityAttributes=*/NULL,
791                                  OPEN_EXISTING,
792                                  FILE_ATTRIBUTE_NORMAL,
793                                  /*hTemplateFile=*/NULL);
794       if (conout_handle == INVALID_HANDLE_VALUE)
795         /* There is no console associated with this process.  Since
796            the child is a console process, the OS would normally
797            create a new console Window for the child.  Since we'll be
798            redirecting the child's standard streams, we do not need
799            the console window.  */ 
800         dwCreationFlags = CREATE_NO_WINDOW;
801       else 
802         {
803           /* There is a console associated with the process, so the OS
804              will not create a new console.  And, if we use
805              CREATE_NO_WINDOW in this situation, the child will have
806              no associated console.  Therefore, if the child's
807              standard streams are connected to the console, the output
808              will be discarded.  */
809           CloseHandle(conout_handle);
810           dwCreationFlags = 0;
811         }
812     }
813
814   /* Since the child will be a console process, it will, by default,
815      connect standard input/output to its console.  However, we want
816      the child to use the handles specifically designated above.  In
817      addition, if there is no console (such as when we are running in
818      a Cygwin X window), then we must redirect the child's
819      input/output, as there is no console for the child to use.  */
820   memset (&si, 0, sizeof (si));
821   si.cb = sizeof (si);
822   si.dwFlags = STARTF_USESTDHANDLES;
823   si.hStdInput = stdin_handle;
824   si.hStdOutput = stdout_handle;
825   si.hStdError = stderr_handle;
826
827   /* Create the child process.  */  
828   pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
829                      argv, env, dwCreationFlags, &si, &pi);
830   if (pid == (pid_t) -1)
831     pid = spawn_script (executable, argv, env, dwCreationFlags,
832                         &si, &pi);
833   if (pid == (pid_t) -1)
834     {
835       *err = ENOENT;
836       *errmsg = "CreateProcess";
837     }
838
839   /* Close the standard input, standard output and standard error handles
840      in the parent.  */ 
841
842   _close (in);
843   _close (out);
844   if (separate_stderr)
845     _close (errdes);
846
847   return pid;
848 }
849
850 /* Wait for a child process to complete.  MS CRTDLL doesn't return
851    enough information in status to decide if the child exited due to a
852    signal or not, rather it simply returns an integer with the exit
853    code of the child; eg., if the child exited with an abort() call
854    and didn't have a handler for SIGABRT, it simply returns with
855    status == 3.  We fix the status code to conform to the usual WIF*
856    macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
857
858 static pid_t
859 pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
860                 int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
861                 const char **errmsg, int *err)
862 {
863   DWORD termstat;
864   HANDLE h;
865
866   if (time != NULL)
867     memset (time, 0, sizeof *time);
868
869   h = (HANDLE) pid;
870
871   /* FIXME: If done is non-zero, we should probably try to kill the
872      process.  */
873   if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
874     {
875       CloseHandle (h);
876       *err = ECHILD;
877       *errmsg = "WaitForSingleObject";
878       return -1;
879     }
880
881   GetExitCodeProcess (h, &termstat);
882   CloseHandle (h);
883  
884   /* A value of 3 indicates that the child caught a signal, but not
885      which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
886      report SIGABRT.  */
887   if (termstat == 3)
888     *status = SIGABRT;
889   else
890     *status = (termstat & 0xff) << 8;
891
892   return 0;
893 }
894
895 /* Create a pipe.  */
896
897 static int
898 pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
899                 int binary)
900 {
901   return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
902 }
903
904 /* Get a FILE pointer to read from a file descriptor.  */
905
906 static FILE *
907 pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
908                    int binary)
909 {
910   HANDLE h = (HANDLE) _get_osfhandle (fd);
911   if (h == INVALID_HANDLE_VALUE)
912     return NULL;
913   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
914     return NULL;
915   return fdopen (fd, binary ? "rb" : "r");
916 }
917
918 static FILE *
919 pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
920                    int binary)
921 {
922   HANDLE h = (HANDLE) _get_osfhandle (fd);
923   if (h == INVALID_HANDLE_VALUE)
924     return NULL;
925   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
926     return NULL;
927   return fdopen (fd, binary ? "wb" : "w");
928 }
929
930 #ifdef MAIN
931 #include <stdio.h>
932
933 int
934 main (int argc ATTRIBUTE_UNUSED, char **argv)
935 {
936   char const *errmsg;
937   int err;
938   argv++;
939   printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
940   exit (0);
941 }
942 #endif