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