OSDN Git Service

* configure.ac (setobjs, msdosdjgpp): Move a-priori setting of
[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
750   stdin_handle = INVALID_HANDLE_VALUE;
751   stdout_handle = INVALID_HANDLE_VALUE;
752   stderr_handle = INVALID_HANDLE_VALUE;
753
754   stdin_handle = (HANDLE) _get_osfhandle (in);
755   stdout_handle = (HANDLE) _get_osfhandle (out);
756   if (!(flags & PEX_STDERR_TO_STDOUT))
757     stderr_handle = (HANDLE) _get_osfhandle (errdes);
758   else
759     stderr_handle = stdout_handle;
760
761   /* Determine the version of Windows we are running on.  */
762   version_info.dwOSVersionInfoSize = sizeof (version_info); 
763   GetVersionEx (&version_info);
764   if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
765     /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
766        supported, so we cannot avoid creating a console window.  */
767     dwCreationFlags = 0;
768   else
769     {
770       HANDLE conout_handle;
771
772       /* Determine whether or not we have an associated console.  */
773       conout_handle = CreateFile("CONOUT$", 
774                                  GENERIC_WRITE,
775                                  FILE_SHARE_WRITE,
776                                  /*lpSecurityAttributes=*/NULL,
777                                  OPEN_EXISTING,
778                                  FILE_ATTRIBUTE_NORMAL,
779                                  /*hTemplateFile=*/NULL);
780       if (conout_handle == INVALID_HANDLE_VALUE)
781         /* There is no console associated with this process.  Since
782            the child is a console process, the OS would normally
783            create a new console Window for the child.  Since we'll be
784            redirecting the child's standard streams, we do not need
785            the console window.  */ 
786         dwCreationFlags = CREATE_NO_WINDOW;
787       else 
788         {
789           /* There is a console associated with the process, so the OS
790              will not create a new console.  And, if we use
791              CREATE_NO_WINDOW in this situation, the child will have
792              no associated console.  Therefore, if the child's
793              standard streams are connected to the console, the output
794              will be discarded.  */
795           CloseHandle(conout_handle);
796           dwCreationFlags = 0;
797         }
798     }
799
800   /* Since the child will be a console process, it will, by default,
801      connect standard input/output to its console.  However, we want
802      the child to use the handles specifically designated above.  In
803      addition, if there is no console (such as when we are running in
804      a Cygwin X window), then we must redirect the child's
805      input/output, as there is no console for the child to use.  */
806   memset (&si, 0, sizeof (si));
807   si.cb = sizeof (si);
808   si.dwFlags = STARTF_USESTDHANDLES;
809   si.hStdInput = stdin_handle;
810   si.hStdOutput = stdout_handle;
811   si.hStdError = stderr_handle;
812
813   /* Create the child process.  */  
814   pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
815                      argv, env, dwCreationFlags, &si, &pi);
816   if (pid == (pid_t) -1)
817     pid = spawn_script (executable, argv, env, dwCreationFlags,
818                         &si, &pi);
819   if (pid == (pid_t) -1)
820     {
821       *err = ENOENT;
822       *errmsg = "CreateProcess";
823     }
824
825   /* Close the standard output and standard error handles in the
826      parent.  */ 
827   if (out != STDOUT_FILENO)
828     obj->funcs->close (obj, out);
829   if (errdes != STDERR_FILENO)
830     obj->funcs->close (obj, errdes);
831
832   return pid;
833 }
834
835 /* Wait for a child process to complete.  MS CRTDLL doesn't return
836    enough information in status to decide if the child exited due to a
837    signal or not, rather it simply returns an integer with the exit
838    code of the child; eg., if the child exited with an abort() call
839    and didn't have a handler for SIGABRT, it simply returns with
840    status == 3.  We fix the status code to conform to the usual WIF*
841    macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
842
843 static pid_t
844 pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
845                 int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
846                 const char **errmsg, int *err)
847 {
848   DWORD termstat;
849   HANDLE h;
850
851   if (time != NULL)
852     memset (time, 0, sizeof *time);
853
854   h = (HANDLE) pid;
855
856   /* FIXME: If done is non-zero, we should probably try to kill the
857      process.  */
858   if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
859     {
860       CloseHandle (h);
861       *err = ECHILD;
862       *errmsg = "WaitForSingleObject";
863       return -1;
864     }
865
866   GetExitCodeProcess (h, &termstat);
867   CloseHandle (h);
868  
869   /* A value of 3 indicates that the child caught a signal, but not
870      which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
871      report SIGABRT.  */
872   if (termstat == 3)
873     *status = SIGABRT;
874   else
875     *status = (termstat & 0xff) << 8;
876
877   return 0;
878 }
879
880 /* Create a pipe.  */
881
882 static int
883 pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
884                 int binary)
885 {
886   return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
887 }
888
889 /* Get a FILE pointer to read from a file descriptor.  */
890
891 static FILE *
892 pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
893                    int binary)
894 {
895   return fdopen (fd, binary ? "rb" : "r");
896 }
897
898 static FILE *
899 pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
900                    int binary)
901 {
902   HANDLE h = (HANDLE) _get_osfhandle (fd);
903   if (h == INVALID_HANDLE_VALUE)
904     return NULL;
905   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
906     return NULL;
907   return fdopen (fd, binary ? "wb" : "w");
908 }
909
910 #ifdef MAIN
911 #include <stdio.h>
912
913 int
914 main (int argc ATTRIBUTE_UNUSED, char **argv)
915 {
916   char const *errmsg;
917   int err;
918   argv++;
919   printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
920   exit (0);
921 }
922 #endif