OSDN Git Service

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