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