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
backslashify(char * s)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, 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 *
pex_init(int flags,const char * pname,const char * tempbase)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
pex_win32_open_read(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary)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
pex_win32_open_write(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary,int append)128 pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
129 		      int binary, int append)
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   if (append)
134     return -1;
135   return _open (name,
136 		(_O_WRONLY | _O_CREAT | _O_TRUNC
137 		 | (binary ? _O_BINARY : _O_TEXT)),
138 		_S_IREAD | _S_IWRITE);
139 }
140 
141 /* Close a file.  */
142 
143 static int
pex_win32_close(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd)144 pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
145 {
146   return _close (fd);
147 }
148 
149 #ifdef USE_MINGW_MSYS
150 static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
151 
152 /* Tack the executable on the end of a (possibly slash terminated) buffer
153    and convert everything to \. */
154 static const char *
tack_on_executable(char * buf,const char * executable)155 tack_on_executable (char *buf, const char *executable)
156 {
157   char *p = strchr (buf, '\0');
158   if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
159     p[-1] = '\0';
160   backslashify (strcat (buf, executable));
161   return buf;
162 }
163 
164 /* Walk down a registry hierarchy until the end.  Return the key. */
165 static HKEY
openkey(HKEY hStart,const char * keys[])166 openkey (HKEY hStart, const char *keys[])
167 {
168   HKEY hKey, hTmp;
169   for (hKey = hStart; *keys; keys++)
170     {
171       LONG res;
172       hTmp = hKey;
173       res = RegOpenKey (hTmp, *keys, &hKey);
174 
175       if (hTmp != HKEY_LOCAL_MACHINE)
176 	RegCloseKey (hTmp);
177 
178       if (res != ERROR_SUCCESS)
179 	return NULL;
180     }
181   return hKey;
182 }
183 
184 /* Return the "mingw root" as derived from the mingw uninstall information. */
185 static const char *
mingw_rootify(const char * executable)186 mingw_rootify (const char *executable)
187 {
188   HKEY hKey, hTmp;
189   DWORD maxlen;
190   char *namebuf, *foundbuf;
191   DWORD i;
192   LONG res;
193 
194   /* Open the uninstall "directory". */
195   hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
196 
197   /* Not found. */
198   if (!hKey)
199     return executable;
200 
201   /* Need to enumerate all of the keys here looking for one the most recent
202      one for MinGW. */
203   if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
204 		       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
205     {
206       RegCloseKey (hKey);
207       return executable;
208     }
209   namebuf = XNEWVEC (char, ++maxlen);
210   foundbuf = XNEWVEC (char, maxlen);
211   foundbuf[0] = '\0';
212   if (!namebuf || !foundbuf)
213     {
214       RegCloseKey (hKey);
215       free (namebuf);
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 *
msys_rootify(const char * executable)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   free (buf);
319   return executable;
320 }
321 #endif
322 
323 /* Return the number of arguments in an argv array, not including the null
324    terminating argument. */
325 
326 static int
argv_to_argc(char * const * argv)327 argv_to_argc (char *const *argv)
328 {
329   char *const *i = argv;
330   while (*i)
331     i++;
332   return i - argv;
333 }
334 
335 /* Return a Windows command-line from ARGV.  It is the caller's
336    responsibility to free the string returned.  */
337 
338 static char *
argv_to_cmdline(char * const * argv)339 argv_to_cmdline (char *const *argv)
340 {
341   char *cmdline;
342   char *p;
343   size_t cmdline_len;
344   int i, j, k;
345   int needs_quotes;
346 
347   cmdline_len = 0;
348   for (i = 0; argv[i]; i++)
349     {
350       /* We only quote arguments that contain spaces, \t or " characters to
351 	 prevent wasting 2 chars per argument of the CreateProcess 32k char
352 	 limit.  We need only escape embedded double-quotes and immediately
353 	 preceeding backslash characters.  A sequence of backslach characters
354 	 that is not follwed by a double quote character will not be
355 	 escaped.  */
356       needs_quotes = 0;
357       for (j = 0; argv[i][j]; j++)
358 	{
359 	  if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
360 	    {
361 	      needs_quotes = 1;
362 	    }
363 
364 	  if (argv[i][j] == '"')
365 	    {
366 	      /* Escape preceeding backslashes.  */
367 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
368 		cmdline_len++;
369 	      /* Escape the qote character.  */
370 	      cmdline_len++;
371 	    }
372 	}
373       /* Trailing backslashes also need to be escaped because they will be
374          followed by the terminating quote.  */
375       if (needs_quotes)
376         {
377           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
378             cmdline_len++;
379         }
380       cmdline_len += j;
381       /* for leading and trailing quotes and space */
382       cmdline_len += needs_quotes * 2 + 1;
383     }
384   cmdline = XNEWVEC (char, cmdline_len);
385   p = cmdline;
386   for (i = 0; argv[i]; i++)
387     {
388       needs_quotes = 0;
389       for (j = 0; argv[i][j]; j++)
390         {
391           if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
392             {
393               needs_quotes = 1;
394               break;
395             }
396         }
397 
398       if (needs_quotes)
399         {
400           *p++ = '"';
401         }
402       for (j = 0; argv[i][j]; j++)
403 	{
404 	  if (argv[i][j] == '"')
405 	    {
406 	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
407 		*p++ = '\\';
408 	      *p++ = '\\';
409 	    }
410 	  *p++ = argv[i][j];
411 	}
412       if (needs_quotes)
413         {
414           for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
415             *p++ = '\\';
416           *p++ = '"';
417         }
418       *p++ = ' ';
419     }
420   p[-1] = '\0';
421   return cmdline;
422 }
423 
424 /* We'll try the passed filename with all the known standard
425    extensions, and then without extension.  We try no extension
426    last so that we don't try to run some random extension-less
427    file that might be hanging around.  We try both extension
428    and no extension so that we don't need any fancy logic
429    to determine if a file has extension.  */
430 static const char *const
431 std_suffixes[] = {
432   ".com",
433   ".exe",
434   ".bat",
435   ".cmd",
436   "",
437   0
438 };
439 
440 /* Returns the full path to PROGRAM.  If SEARCH is true, look for
441    PROGRAM in each directory in PATH.  */
442 
443 static char *
find_executable(const char * program,BOOL search)444 find_executable (const char *program, BOOL search)
445 {
446   char *full_executable;
447   char *e;
448   size_t fe_len;
449   const char *path = 0;
450   const char *const *ext;
451   const char *p, *q;
452   size_t proglen = strlen (program);
453   int has_slash = (strchr (program, '/') || strchr (program, '\\'));
454   HANDLE h;
455 
456   if (has_slash)
457     search = FALSE;
458 
459   if (search)
460     path = getenv ("PATH");
461   if (!path)
462     path = "";
463 
464   fe_len = 0;
465   for (p = path; *p; p = q)
466     {
467       q = p;
468       while (*q != ';' && *q != '\0')
469 	q++;
470       if ((size_t)(q - p) > fe_len)
471 	fe_len = q - p;
472       if (*q == ';')
473 	q++;
474     }
475   fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
476   full_executable = XNEWVEC (char, fe_len);
477 
478   p = path;
479   do
480     {
481       q = p;
482       while (*q != ';' && *q != '\0')
483 	q++;
484 
485       e = full_executable;
486       memcpy (e, p, q - p);
487       e += (q - p);
488       if (q - p)
489 	*e++ = '\\';
490       strcpy (e, program);
491 
492       if (*q == ';')
493 	q++;
494 
495       for (e = full_executable; *e; e++)
496 	if (*e == '/')
497 	  *e = '\\';
498 
499       /* At this point, e points to the terminating NUL character for
500          full_executable.  */
501       for (ext = std_suffixes; *ext; ext++)
502 	{
503 	  /* Remove any current extension.  */
504 	  *e = '\0';
505 	  /* Add the new one.  */
506 	  strcat (full_executable, *ext);
507 
508 	  /* Attempt to open this file.  */
509 	  h = CreateFile (full_executable, GENERIC_READ,
510 			  FILE_SHARE_READ | FILE_SHARE_WRITE,
511 			  0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
512 	  if (h != INVALID_HANDLE_VALUE)
513 	    goto found;
514 	}
515       p = q;
516     }
517   while (*p);
518   free (full_executable);
519   return 0;
520 
521  found:
522   CloseHandle (h);
523   return full_executable;
524 }
525 
526 /* Low-level process creation function and helper.  */
527 
528 static int
env_compare(const void * a_ptr,const void * b_ptr)529 env_compare (const void *a_ptr, const void *b_ptr)
530 {
531   const char *a;
532   const char *b;
533   unsigned char c1;
534   unsigned char c2;
535 
536   a = *(const char **) a_ptr;
537   b = *(const char **) b_ptr;
538 
539   /* a and b will be of the form: VAR=VALUE
540      We compare only the variable name part here using a case-insensitive
541      comparison algorithm.  It might appear that in fact strcasecmp () can
542      take the place of this whole function, and indeed it could, save for
543      the fact that it would fail in cases such as comparing A1=foo and
544      A=bar (because 1 is less than = in the ASCII character set).
545      (Environment variables containing no numbers would work in such a
546      scenario.)  */
547 
548   do
549     {
550       c1 = (unsigned char) tolower (*a++);
551       c2 = (unsigned char) tolower (*b++);
552 
553       if (c1 == '=')
554         c1 = '\0';
555 
556       if (c2 == '=')
557         c2 = '\0';
558     }
559   while (c1 == c2 && c1 != '\0');
560 
561   return c1 - c2;
562 }
563 
564 /* Execute a Windows executable as a child process.  This will fail if the
565  * target is not actually an executable, such as if it is a shell script. */
566 
567 static pid_t
win32_spawn(const char * executable,BOOL search,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)568 win32_spawn (const char *executable,
569 	     BOOL search,
570 	     char *const *argv,
571              char *const *env, /* array of strings of the form: VAR=VALUE */
572 	     DWORD dwCreationFlags,
573 	     LPSTARTUPINFO si,
574 	     LPPROCESS_INFORMATION pi)
575 {
576   char *full_executable;
577   char *cmdline;
578   char **env_copy;
579   char *env_block = NULL;
580 
581   full_executable = NULL;
582   cmdline = NULL;
583 
584   if (env)
585     {
586       int env_size;
587 
588       /* Count the number of environment bindings supplied.  */
589       for (env_size = 0; env[env_size]; env_size++)
590         continue;
591 
592       /* Assemble an environment block, if required.  This consists of
593          VAR=VALUE strings juxtaposed (with one null character between each
594          pair) and an additional null at the end.  */
595       if (env_size > 0)
596         {
597           int var;
598           int total_size = 1; /* 1 is for the final null.  */
599           char *bufptr;
600 
601           /* Windows needs the members of the block to be sorted by variable
602              name.  */
603           env_copy = (char **) alloca (sizeof (char *) * env_size);
604           memcpy (env_copy, env, sizeof (char *) * env_size);
605           qsort (env_copy, env_size, sizeof (char *), env_compare);
606 
607           for (var = 0; var < env_size; var++)
608             total_size += strlen (env[var]) + 1;
609 
610           env_block = XNEWVEC (char, total_size);
611           bufptr = env_block;
612           for (var = 0; var < env_size; var++)
613             bufptr = stpcpy (bufptr, env_copy[var]) + 1;
614 
615           *bufptr = '\0';
616         }
617     }
618 
619   full_executable = find_executable (executable, search);
620   if (!full_executable)
621     goto error;
622   cmdline = argv_to_cmdline (argv);
623   if (!cmdline)
624     goto error;
625 
626   /* Create the child process.  */
627   if (!CreateProcess (full_executable, cmdline,
628 		      /*lpProcessAttributes=*/NULL,
629 		      /*lpThreadAttributes=*/NULL,
630 		      /*bInheritHandles=*/TRUE,
631 		      dwCreationFlags,
632 		      (LPVOID) env_block,
633 		      /*lpCurrentDirectory=*/NULL,
634 		      si,
635 		      pi))
636     {
637       free (env_block);
638 
639       free (full_executable);
640 
641       return (pid_t) -1;
642     }
643 
644   /* Clean up.  */
645   CloseHandle (pi->hThread);
646   free (full_executable);
647   free (env_block);
648 
649   return (pid_t) pi->hProcess;
650 
651  error:
652   free (env_block);
653   free (cmdline);
654   free (full_executable);
655 
656   return (pid_t) -1;
657 }
658 
659 /* Spawn a script.  This simulates the Unix script execution mechanism.
660    This function is called as a fallback if win32_spawn fails. */
661 
662 static pid_t
spawn_script(const char * executable,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)663 spawn_script (const char *executable, char *const *argv,
664               char* const *env,
665 	      DWORD dwCreationFlags,
666 	      LPSTARTUPINFO si,
667 	      LPPROCESS_INFORMATION pi)
668 {
669   pid_t pid = (pid_t) -1;
670   int save_errno = errno;
671   int fd = _open (executable, _O_RDONLY);
672 
673   /* Try to open script, check header format, extract interpreter path,
674      and spawn script using that interpretter. */
675   if (fd >= 0)
676     {
677       char buf[MAX_PATH + 5];
678       int len = _read (fd, buf, sizeof (buf) - 1);
679       _close (fd);
680       if (len > 3)
681 	{
682 	  char *eol;
683 	  buf[len] = '\0';
684 	  eol = strchr (buf, '\n');
685 	  if (eol && strncmp (buf, "#!", 2) == 0)
686 	    {
687 
688 	      /* Header format is OK. */
689 	      char *executable1;
690               int new_argc;
691               const char **avhere;
692 
693 	      /* Extract interpreter path. */
694 	      do
695 		*eol = '\0';
696 	      while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
697 	      for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
698 		continue;
699 	      backslashify (executable1);
700 
701 	      /* Duplicate argv, prepending the interpreter path. */
702 	      new_argc = argv_to_argc (argv) + 1;
703 	      avhere = XNEWVEC (const char *, new_argc + 1);
704 	      *avhere = executable1;
705 	      memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
706 	      argv = (char *const *)avhere;
707 
708 	      /* Spawn the child. */
709 #ifndef USE_MINGW_MSYS
710 	      executable = strrchr (executable1, '\\') + 1;
711 	      if (!executable)
712 		executable = executable1;
713 	      pid = win32_spawn (executable, TRUE, argv, env,
714 				 dwCreationFlags, si, pi);
715 #else
716 	      if (strchr (executable1, '\\') == NULL)
717 		pid = win32_spawn (executable1, TRUE, argv, env,
718 				   dwCreationFlags, si, pi);
719 	      else if (executable1[0] != '\\')
720 		pid = win32_spawn (executable1, FALSE, argv, env,
721 				   dwCreationFlags, si, pi);
722 	      else
723 		{
724 		  const char *newex = mingw_rootify (executable1);
725 		  *avhere = newex;
726 		  pid = win32_spawn (newex, FALSE, argv, env,
727 				     dwCreationFlags, si, pi);
728 		  if (executable1 != newex)
729 		    free ((char *) newex);
730 		  if (pid == (pid_t) -1)
731 		    {
732 		      newex = msys_rootify (executable1);
733 		      if (newex != executable1)
734 			{
735 			  *avhere = newex;
736 			  pid = win32_spawn (newex, FALSE, argv, env,
737 					     dwCreationFlags, si, pi);
738 			  free ((char *) newex);
739 			}
740 		    }
741 		}
742 #endif
743 	      free (avhere);
744 	    }
745 	}
746     }
747   if (pid == (pid_t) -1)
748     errno = save_errno;
749   return pid;
750 }
751 
752 /* Execute a child.  */
753 
754 static pid_t
pex_win32_exec_child(struct pex_obj * obj ATTRIBUTE_UNUSED,int flags,const char * executable,char * const * argv,char * const * env,int in,int out,int errdes,int toclose ATTRIBUTE_UNUSED,const char ** errmsg,int * err)755 pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
756 		      const char *executable, char * const * argv,
757                       char* const* env,
758 		      int in, int out, int errdes,
759 		      int toclose ATTRIBUTE_UNUSED,
760 		      const char **errmsg,
761 		      int *err)
762 {
763   pid_t pid;
764   HANDLE stdin_handle;
765   HANDLE stdout_handle;
766   HANDLE stderr_handle;
767   DWORD dwCreationFlags;
768   OSVERSIONINFO version_info;
769   STARTUPINFO si;
770   PROCESS_INFORMATION pi;
771   int orig_out, orig_in, orig_err;
772   BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
773 
774   /* Ensure we have inheritable descriptors to pass to the child.  */
775   orig_in = in;
776   in = _dup (orig_in);
777 
778   orig_out = out;
779   out = _dup (orig_out);
780 
781   if (separate_stderr)
782     {
783       orig_err = errdes;
784       errdes = _dup (orig_err);
785     }
786 
787   stdin_handle = INVALID_HANDLE_VALUE;
788   stdout_handle = INVALID_HANDLE_VALUE;
789   stderr_handle = INVALID_HANDLE_VALUE;
790 
791   stdin_handle = (HANDLE) _get_osfhandle (in);
792   stdout_handle = (HANDLE) _get_osfhandle (out);
793   if (separate_stderr)
794     stderr_handle = (HANDLE) _get_osfhandle (errdes);
795   else
796     stderr_handle = stdout_handle;
797 
798   /* Determine the version of Windows we are running on.  */
799   version_info.dwOSVersionInfoSize = sizeof (version_info);
800   GetVersionEx (&version_info);
801   if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
802     /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
803        supported, so we cannot avoid creating a console window.  */
804     dwCreationFlags = 0;
805   else
806     {
807       HANDLE conout_handle;
808 
809       /* Determine whether or not we have an associated console.  */
810       conout_handle = CreateFile("CONOUT$",
811 				 GENERIC_WRITE,
812 				 FILE_SHARE_WRITE,
813 				 /*lpSecurityAttributes=*/NULL,
814 				 OPEN_EXISTING,
815 				 FILE_ATTRIBUTE_NORMAL,
816 				 /*hTemplateFile=*/NULL);
817       if (conout_handle == INVALID_HANDLE_VALUE)
818 	/* There is no console associated with this process.  Since
819 	   the child is a console process, the OS would normally
820 	   create a new console Window for the child.  Since we'll be
821 	   redirecting the child's standard streams, we do not need
822 	   the console window.  */
823 	dwCreationFlags = CREATE_NO_WINDOW;
824       else
825 	{
826 	  /* There is a console associated with the process, so the OS
827 	     will not create a new console.  And, if we use
828 	     CREATE_NO_WINDOW in this situation, the child will have
829 	     no associated console.  Therefore, if the child's
830 	     standard streams are connected to the console, the output
831 	     will be discarded.  */
832 	  CloseHandle(conout_handle);
833 	  dwCreationFlags = 0;
834 	}
835     }
836 
837   /* Since the child will be a console process, it will, by default,
838      connect standard input/output to its console.  However, we want
839      the child to use the handles specifically designated above.  In
840      addition, if there is no console (such as when we are running in
841      a Cygwin X window), then we must redirect the child's
842      input/output, as there is no console for the child to use.  */
843   memset (&si, 0, sizeof (si));
844   si.cb = sizeof (si);
845   si.dwFlags = STARTF_USESTDHANDLES;
846   si.hStdInput = stdin_handle;
847   si.hStdOutput = stdout_handle;
848   si.hStdError = stderr_handle;
849 
850   /* Create the child process.  */
851   pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
852 		     argv, env, dwCreationFlags, &si, &pi);
853   if (pid == (pid_t) -1)
854     pid = spawn_script (executable, argv, env, dwCreationFlags,
855                         &si, &pi);
856   if (pid == (pid_t) -1)
857     {
858       *err = ENOENT;
859       *errmsg = "CreateProcess";
860     }
861 
862   /* If the child was created successfully, close the original file
863      descriptors.  If the process creation fails, these are closed by
864      pex_run_in_environment instead.  We must not close them twice as
865      that seems to cause a Windows exception.  */
866 
867   if (pid != (pid_t) -1)
868     {
869       if (orig_in != STDIN_FILENO)
870 	_close (orig_in);
871       if (orig_out != STDOUT_FILENO)
872 	_close (orig_out);
873       if (separate_stderr
874 	  && orig_err != STDERR_FILENO)
875 	_close (orig_err);
876     }
877 
878   /* Close the standard input, standard output and standard error handles
879      in the parent.  */
880 
881   _close (in);
882   _close (out);
883   if (separate_stderr)
884     _close (errdes);
885 
886   return pid;
887 }
888 
889 /* Wait for a child process to complete.  MS CRTDLL doesn't return
890    enough information in status to decide if the child exited due to a
891    signal or not, rather it simply returns an integer with the exit
892    code of the child; eg., if the child exited with an abort() call
893    and didn't have a handler for SIGABRT, it simply returns with
894    status == 3.  We fix the status code to conform to the usual WIF*
895    macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
896 
897 static pid_t
pex_win32_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time,int done ATTRIBUTE_UNUSED,const char ** errmsg,int * err)898 pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
899 		int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
900 		const char **errmsg, int *err)
901 {
902   DWORD termstat;
903   HANDLE h;
904 
905   if (time != NULL)
906     memset (time, 0, sizeof *time);
907 
908   h = (HANDLE) pid;
909 
910   /* FIXME: If done is non-zero, we should probably try to kill the
911      process.  */
912   if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
913     {
914       CloseHandle (h);
915       *err = ECHILD;
916       *errmsg = "WaitForSingleObject";
917       return -1;
918     }
919 
920   GetExitCodeProcess (h, &termstat);
921   CloseHandle (h);
922 
923   /* A value of 3 indicates that the child caught a signal, but not
924      which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
925      report SIGABRT.  */
926   if (termstat == 3)
927     *status = SIGABRT;
928   else
929     *status = (termstat & 0xff) << 8;
930 
931   return 0;
932 }
933 
934 /* Create a pipe.  */
935 
936 static int
pex_win32_pipe(struct pex_obj * obj ATTRIBUTE_UNUSED,int * p,int binary)937 pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
938 		int binary)
939 {
940   return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
941 }
942 
943 /* Get a FILE pointer to read from a file descriptor.  */
944 
945 static FILE *
pex_win32_fdopenr(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)946 pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
947 		   int binary)
948 {
949   HANDLE h = (HANDLE) _get_osfhandle (fd);
950   if (h == INVALID_HANDLE_VALUE)
951     return NULL;
952   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
953     return NULL;
954   return fdopen (fd, binary ? "rb" : "r");
955 }
956 
957 static FILE *
pex_win32_fdopenw(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)958 pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
959 		   int binary)
960 {
961   HANDLE h = (HANDLE) _get_osfhandle (fd);
962   if (h == INVALID_HANDLE_VALUE)
963     return NULL;
964   if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
965     return NULL;
966   return fdopen (fd, binary ? "wb" : "w");
967 }
968 
969 #ifdef MAIN
970 #include <stdio.h>
971 
972 int
main(int argc ATTRIBUTE_UNUSED,char ** argv)973 main (int argc ATTRIBUTE_UNUSED, char **argv)
974 {
975   char const *errmsg;
976   int err;
977   argv++;
978   printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
979   exit (0);
980 }
981 #endif
982