(root)/
gcc-13.2.0/
libiberty/
pex-win32.c
       1  /* Utilities to execute a program in a subprocess (possibly linked by pipes
       2     with other subprocesses), and wait for it.  Generic Win32 specialization.
       3     Copyright (C) 1996-2023 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  #define WIN32_LEAN_AND_MEAN
      24  #include <windows.h>
      25  
      26  #ifdef HAVE_STDLIB_H
      27  #include <stdlib.h>
      28  #endif
      29  #ifdef HAVE_STRING_H
      30  #include <string.h>
      31  #endif
      32  #ifdef HAVE_UNISTD_H
      33  #include <unistd.h>
      34  #endif
      35  #ifdef HAVE_SYS_WAIT_H
      36  #include <sys/wait.h>
      37  #endif
      38  
      39  #include <assert.h>
      40  #include <process.h>
      41  #include <io.h>
      42  #include <fcntl.h>
      43  #include <signal.h>
      44  #include <sys/stat.h>
      45  #include <errno.h>
      46  #include <ctype.h>
      47  
      48  /* mingw32 headers may not define the following.  */
      49  
      50  #ifndef _P_WAIT
      51  #  define _P_WAIT	0
      52  #  define _P_NOWAIT	1
      53  #  define _P_OVERLAY	2
      54  #  define _P_NOWAITO	3
      55  #  define _P_DETACH	4
      56  
      57  #  define WAIT_CHILD		0
      58  #  define WAIT_GRANDCHILD	1
      59  #endif
      60  
      61  #define MINGW_NAME "Minimalist GNU for Windows"
      62  #define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
      63  
      64  extern char *stpcpy (char *dst, const char *src);
      65  
      66  /* Ensure that the executable pathname uses Win32 backslashes. This
      67     is not necessary on NT, but on W9x, forward slashes causes
      68     failure of spawn* and exec* functions (and probably any function
      69     that calls CreateProcess) *iff* the executable pathname (argv[0])
      70     is a quoted string.  And quoting is necessary in case a pathname
      71     contains embedded white space.  You can't win.  */
      72  static void
      73  backslashify (char *s)
      74  {
      75    while ((s = strchr (s, '/')) != NULL)
      76      *s = '\\';
      77    return;
      78  }
      79  
      80  static int pex_win32_open_read (struct pex_obj *, const char *, int);
      81  static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
      82  static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
      83  				  char * const *, char * const *,
      84                                    int, int, int, int,
      85  				  const char **, int *);
      86  static int pex_win32_close (struct pex_obj *, int);
      87  static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
      88  			   struct pex_time *, int, const char **, int *);
      89  static int pex_win32_pipe (struct pex_obj *, int *, int);
      90  static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
      91  static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
      92  
      93  /* The list of functions we pass to the common routines.  */
      94  
      95  const struct pex_funcs funcs =
      96  {
      97    pex_win32_open_read,
      98    pex_win32_open_write,
      99    pex_win32_exec_child,
     100    pex_win32_close,
     101    pex_win32_wait,
     102    pex_win32_pipe,
     103    pex_win32_fdopenr,
     104    pex_win32_fdopenw,
     105    NULL /* cleanup */
     106  };
     107  
     108  /* Return a newly initialized pex_obj structure.  */
     109  
     110  struct pex_obj *
     111  pex_init (int flags, const char *pname, const char *tempbase)
     112  {
     113    return pex_init_common (flags, pname, tempbase, &funcs);
     114  }
     115  
     116  /* Open a file for reading.  */
     117  
     118  static int
     119  pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
     120  		     int binary)
     121  {
     122    return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
     123  }
     124  
     125  /* Open a file for writing.  */
     126  
     127  static int
     128  pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
     129  		      int binary, 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
     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 *
     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
     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 *
     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 *
     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
     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 *
     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        if (j == 0)
     374  	needs_quotes = 1;
     375        /* Trailing backslashes also need to be escaped because they will be
     376           followed by the terminating quote.  */
     377        if (needs_quotes)
     378          {
     379            for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
     380              cmdline_len++;
     381          }
     382        cmdline_len += j;
     383        /* for leading and trailing quotes and space */
     384        cmdline_len += needs_quotes * 2 + 1;
     385      }
     386    cmdline = XNEWVEC (char, cmdline_len);
     387    p = cmdline;
     388    for (i = 0; argv[i]; i++)
     389      {
     390        needs_quotes = 0;
     391        for (j = 0; argv[i][j]; j++)
     392          {
     393            if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
     394              {
     395                needs_quotes = 1;
     396                break;
     397              }
     398          }
     399        if (j == 0)
     400  	needs_quotes = 1;
     401  
     402        if (needs_quotes)
     403          {
     404            *p++ = '"';
     405          }
     406        for (j = 0; argv[i][j]; j++)
     407  	{
     408  	  if (argv[i][j] == '"')
     409  	    {
     410  	      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
     411  		*p++ = '\\';
     412  	      *p++ = '\\';
     413  	    }
     414  	  *p++ = argv[i][j];
     415  	}
     416        if (needs_quotes)
     417          {
     418            for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
     419              *p++ = '\\';
     420            *p++ = '"';
     421          }
     422        *p++ = ' ';
     423      }
     424    p[-1] = '\0';
     425    return cmdline;
     426  }
     427  
     428  /* We'll try the passed filename with all the known standard
     429     extensions, and then without extension.  We try no extension
     430     last so that we don't try to run some random extension-less
     431     file that might be hanging around.  We try both extension
     432     and no extension so that we don't need any fancy logic
     433     to determine if a file has extension.  */
     434  static const char *const
     435  std_suffixes[] = {
     436    ".com",
     437    ".exe",
     438    ".bat",
     439    ".cmd",
     440    "",
     441    0
     442  };
     443  
     444  /* Returns the full path to PROGRAM.  If SEARCH is true, look for
     445     PROGRAM in each directory in PATH.  */
     446  
     447  static char *
     448  find_executable (const char *program, BOOL search)
     449  {
     450    char *full_executable;
     451    char *e;
     452    size_t fe_len;
     453    const char *path = 0;
     454    const char *const *ext;
     455    const char *p, *q;
     456    size_t proglen = strlen (program);
     457    int has_slash = (strchr (program, '/') || strchr (program, '\\'));
     458    HANDLE h;
     459  
     460    if (has_slash)
     461      search = FALSE;
     462  
     463    if (search)
     464      path = getenv ("PATH");
     465    if (!path)
     466      path = "";
     467  
     468    fe_len = 0;
     469    for (p = path; *p; p = q)
     470      {
     471        q = p;
     472        while (*q != ';' && *q != '\0')
     473  	q++;
     474        if ((size_t)(q - p) > fe_len)
     475  	fe_len = q - p;
     476        if (*q == ';')
     477  	q++;
     478      }
     479    fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
     480    full_executable = XNEWVEC (char, fe_len);
     481  
     482    p = path;
     483    do
     484      {
     485        q = p;
     486        while (*q != ';' && *q != '\0')
     487  	q++;
     488  
     489        e = full_executable;
     490        memcpy (e, p, q - p);
     491        e += (q - p);
     492        if (q - p)
     493  	*e++ = '\\';
     494        strcpy (e, program);
     495  
     496        if (*q == ';')
     497  	q++;
     498  
     499        for (e = full_executable; *e; e++)
     500  	if (*e == '/')
     501  	  *e = '\\';
     502  
     503        /* At this point, e points to the terminating NUL character for
     504           full_executable.  */
     505        for (ext = std_suffixes; *ext; ext++)
     506  	{
     507  	  /* Remove any current extension.  */
     508  	  *e = '\0';
     509  	  /* Add the new one.  */
     510  	  strcat (full_executable, *ext);
     511  
     512  	  /* Attempt to open this file.  */
     513  	  h = CreateFile (full_executable, GENERIC_READ,
     514  			  FILE_SHARE_READ | FILE_SHARE_WRITE,
     515  			  0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
     516  	  if (h != INVALID_HANDLE_VALUE)
     517  	    goto found;
     518  	}
     519        p = q;
     520      }
     521    while (*p);
     522    free (full_executable);
     523    return 0;
     524  
     525   found:
     526    CloseHandle (h);
     527    return full_executable;
     528  }
     529  
     530  /* Low-level process creation function and helper.  */
     531  
     532  static int
     533  env_compare (const void *a_ptr, const void *b_ptr)
     534  {
     535    const char *a;
     536    const char *b;
     537    unsigned char c1;
     538    unsigned char c2;
     539  
     540    a = *(const char **) a_ptr;
     541    b = *(const char **) b_ptr;
     542  
     543    /* a and b will be of the form: VAR=VALUE
     544       We compare only the variable name part here using a case-insensitive
     545       comparison algorithm.  It might appear that in fact strcasecmp () can
     546       take the place of this whole function, and indeed it could, save for
     547       the fact that it would fail in cases such as comparing A1=foo and
     548       A=bar (because 1 is less than = in the ASCII character set).
     549       (Environment variables containing no numbers would work in such a
     550       scenario.)  */
     551  
     552    do
     553      {
     554        c1 = (unsigned char) tolower (*a++);
     555        c2 = (unsigned char) tolower (*b++);
     556  
     557        if (c1 == '=')
     558          c1 = '\0';
     559  
     560        if (c2 == '=')
     561          c2 = '\0';
     562      }
     563    while (c1 == c2 && c1 != '\0');
     564  
     565    return c1 - c2;
     566  }
     567  
     568  /* Execute a Windows executable as a child process.  This will fail if the
     569   * target is not actually an executable, such as if it is a shell script. */
     570  
     571  static pid_t
     572  win32_spawn (const char *executable,
     573  	     BOOL search,
     574  	     char *const *argv,
     575               char *const *env, /* array of strings of the form: VAR=VALUE */
     576  	     DWORD dwCreationFlags,
     577  	     LPSTARTUPINFO si,
     578  	     LPPROCESS_INFORMATION pi)
     579  {
     580    char *full_executable = NULL;
     581    char *cmdline = NULL;
     582    pid_t pid = (pid_t) -1;
     583    char **env_copy;
     584    char *env_block = NULL;
     585  
     586    if (env)
     587      {
     588        int env_size;
     589  
     590        /* Count the number of environment bindings supplied.  */
     591        for (env_size = 0; env[env_size]; env_size++)
     592          continue;
     593      
     594        /* Assemble an environment block, if required.  This consists of
     595           VAR=VALUE strings juxtaposed (with one null character between each
     596           pair) and an additional null at the end.  */
     597        if (env_size > 0)
     598          {
     599            int var;
     600            int total_size = 1; /* 1 is for the final null.  */
     601            char *bufptr;
     602      
     603            /* Windows needs the members of the block to be sorted by variable
     604               name.  */
     605            env_copy = (char **) alloca (sizeof (char *) * env_size);
     606            memcpy (env_copy, env, sizeof (char *) * env_size);
     607            qsort (env_copy, env_size, sizeof (char *), env_compare);
     608      
     609            for (var = 0; var < env_size; var++)
     610              total_size += strlen (env[var]) + 1;
     611      
     612            env_block = XNEWVEC (char, total_size);
     613            bufptr = env_block;
     614            for (var = 0; var < env_size; var++)
     615              bufptr = stpcpy (bufptr, env_copy[var]) + 1;
     616      
     617            *bufptr = '\0';
     618          }
     619      }
     620  
     621    full_executable = find_executable (executable, search);
     622    if (!full_executable)
     623      goto exit;
     624    cmdline = argv_to_cmdline (argv);
     625    if (!cmdline)
     626      goto exit;
     627      
     628    /* Create the child process.  */  
     629    if (CreateProcess (full_executable, cmdline,
     630  		      /*lpProcessAttributes=*/NULL,
     631  		      /*lpThreadAttributes=*/NULL,
     632  		      /*bInheritHandles=*/TRUE,
     633  		      dwCreationFlags,
     634  		      (LPVOID) env_block,
     635  		      /*lpCurrentDirectory=*/NULL,
     636  		      si,
     637  		      pi))
     638      {
     639        CloseHandle (pi->hThread);
     640        pid = (pid_t) pi->hProcess;
     641      }
     642  
     643   exit:
     644    /* Clean up.  */
     645    free (env_block);
     646    free (cmdline);
     647    free (full_executable);
     648  
     649    return pid;
     650  }
     651  
     652  /* Spawn a script.  This simulates the Unix script execution mechanism.
     653     This function is called as a fallback if win32_spawn fails. */
     654  
     655  static pid_t
     656  spawn_script (const char *executable, char *const *argv,
     657                char* const *env,
     658  	      DWORD dwCreationFlags,
     659  	      LPSTARTUPINFO si,
     660  	      LPPROCESS_INFORMATION pi)
     661  {
     662    pid_t pid = (pid_t) -1;
     663    int save_errno = errno;
     664    int fd = _open (executable, _O_RDONLY);
     665  
     666    /* Try to open script, check header format, extract interpreter path,
     667       and spawn script using that interpretter. */
     668    if (fd >= 0)
     669      {
     670        char buf[MAX_PATH + 5];
     671        int len = _read (fd, buf, sizeof (buf) - 1);
     672        _close (fd);
     673        if (len > 3)
     674  	{
     675  	  char *eol;
     676  	  buf[len] = '\0';
     677  	  eol = strchr (buf, '\n');
     678  	  if (eol && strncmp (buf, "#!", 2) == 0)
     679  	    {
     680              
     681  	      /* Header format is OK. */
     682  	      char *executable1;
     683                int new_argc;
     684                const char **avhere;
     685  
     686  	      /* Extract interpreter path. */
     687  	      do
     688  		*eol = '\0';
     689  	      while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
     690  	      for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
     691  		continue;
     692  	      backslashify (executable1);
     693  
     694  	      /* Duplicate argv, prepending the interpreter path. */
     695  	      new_argc = argv_to_argc (argv) + 1;
     696  	      avhere = XNEWVEC (const char *, new_argc + 1);
     697  	      *avhere = executable1;
     698  	      memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
     699  	      argv = (char *const *)avhere;
     700  
     701  	      /* Spawn the child. */
     702  #ifndef USE_MINGW_MSYS
     703  	      executable = strrchr (executable1, '\\') + 1;
     704  	      if (!executable)
     705  		executable = executable1;
     706  	      pid = win32_spawn (executable, TRUE, argv, env,
     707  				 dwCreationFlags, si, pi);
     708  #else
     709  	      if (strchr (executable1, '\\') == NULL)
     710  		pid = win32_spawn (executable1, TRUE, argv, env,
     711  				   dwCreationFlags, si, pi);
     712  	      else if (executable1[0] != '\\')
     713  		pid = win32_spawn (executable1, FALSE, argv, env,
     714  				   dwCreationFlags, si, pi);
     715  	      else
     716  		{
     717  		  const char *newex = mingw_rootify (executable1);
     718  		  *avhere = newex;
     719  		  pid = win32_spawn (newex, FALSE, argv, env,
     720  				     dwCreationFlags, si, pi);
     721  		  if (executable1 != newex)
     722  		    free ((char *) newex);
     723  		  if (pid == (pid_t) -1)
     724  		    {
     725  		      newex = msys_rootify (executable1);
     726  		      if (newex != executable1)
     727  			{
     728  			  *avhere = newex;
     729  			  pid = win32_spawn (newex, FALSE, argv, env,
     730  					     dwCreationFlags, si, pi);
     731  			  free ((char *) newex);
     732  			}
     733  		    }
     734  		}
     735  #endif
     736  	      free (avhere);
     737  	    }
     738  	}
     739      }
     740    if (pid == (pid_t) -1)
     741      errno = save_errno;
     742    return pid;
     743  }
     744  
     745  /* Execute a child.  */
     746  
     747  static pid_t
     748  pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
     749  		      const char *executable, char * const * argv,
     750                        char* const* env,
     751  		      int in, int out, int errdes,
     752  		      int toclose ATTRIBUTE_UNUSED,
     753  		      const char **errmsg,
     754  		      int *err)
     755  {
     756    pid_t pid;
     757    HANDLE stdin_handle;
     758    HANDLE stdout_handle;
     759    HANDLE stderr_handle;
     760    DWORD dwCreationFlags;
     761    OSVERSIONINFO version_info;
     762    STARTUPINFO si;
     763    PROCESS_INFORMATION pi;
     764    int orig_out, orig_in, orig_err = 0;
     765    BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
     766  
     767    /* Ensure we have inheritable descriptors to pass to the child.  */
     768    orig_in = in;
     769    in = _dup (orig_in);
     770    
     771    orig_out = out;
     772    out = _dup (orig_out);
     773    
     774    if (separate_stderr)
     775      {
     776        orig_err = errdes;
     777        errdes = _dup (orig_err);
     778      }
     779  
     780    stdin_handle = INVALID_HANDLE_VALUE;
     781    stdout_handle = INVALID_HANDLE_VALUE;
     782    stderr_handle = INVALID_HANDLE_VALUE;
     783  
     784    stdin_handle = (HANDLE) _get_osfhandle (in);
     785    stdout_handle = (HANDLE) _get_osfhandle (out);
     786    if (separate_stderr)
     787      stderr_handle = (HANDLE) _get_osfhandle (errdes);
     788    else
     789      stderr_handle = stdout_handle;
     790  
     791    /* Determine the version of Windows we are running on.  */
     792    version_info.dwOSVersionInfoSize = sizeof (version_info); 
     793    GetVersionEx (&version_info);
     794    if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
     795      /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
     796         supported, so we cannot avoid creating a console window.  */
     797      dwCreationFlags = 0;
     798    else
     799      {
     800        HANDLE conout_handle;
     801  
     802        /* Determine whether or not we have an associated console.  */
     803        conout_handle = CreateFile("CONOUT$", 
     804  				 GENERIC_WRITE,
     805  				 FILE_SHARE_WRITE,
     806  				 /*lpSecurityAttributes=*/NULL,
     807  				 OPEN_EXISTING,
     808  				 FILE_ATTRIBUTE_NORMAL,
     809  				 /*hTemplateFile=*/NULL);
     810        if (conout_handle == INVALID_HANDLE_VALUE)
     811  	/* There is no console associated with this process.  Since
     812  	   the child is a console process, the OS would normally
     813  	   create a new console Window for the child.  Since we'll be
     814  	   redirecting the child's standard streams, we do not need
     815  	   the console window.  */ 
     816  	dwCreationFlags = CREATE_NO_WINDOW;
     817        else 
     818  	{
     819  	  /* There is a console associated with the process, so the OS
     820  	     will not create a new console.  And, if we use
     821  	     CREATE_NO_WINDOW in this situation, the child will have
     822  	     no associated console.  Therefore, if the child's
     823  	     standard streams are connected to the console, the output
     824  	     will be discarded.  */
     825  	  CloseHandle(conout_handle);
     826  	  dwCreationFlags = 0;
     827  	}
     828      }
     829  
     830    /* Since the child will be a console process, it will, by default,
     831       connect standard input/output to its console.  However, we want
     832       the child to use the handles specifically designated above.  In
     833       addition, if there is no console (such as when we are running in
     834       a Cygwin X window), then we must redirect the child's
     835       input/output, as there is no console for the child to use.  */
     836    memset (&si, 0, sizeof (si));
     837    si.cb = sizeof (si);
     838    si.dwFlags = STARTF_USESTDHANDLES;
     839    si.hStdInput = stdin_handle;
     840    si.hStdOutput = stdout_handle;
     841    si.hStdError = stderr_handle;
     842  
     843    /* Create the child process.  */  
     844    pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
     845  		     argv, env, dwCreationFlags, &si, &pi);
     846    if (pid == (pid_t) -1)
     847      pid = spawn_script (executable, argv, env, dwCreationFlags,
     848                          &si, &pi);
     849    if (pid == (pid_t) -1)
     850      {
     851        *err = ENOENT;
     852        *errmsg = "CreateProcess";
     853      }
     854  
     855    /* If the child was created successfully, close the original file
     856       descriptors.  If the process creation fails, these are closed by
     857       pex_run_in_environment instead.  We must not close them twice as
     858       that seems to cause a Windows exception.  */
     859       
     860    if (pid != (pid_t) -1)
     861      {
     862        if (orig_in != STDIN_FILENO)
     863  	_close (orig_in);
     864        if (orig_out != STDOUT_FILENO)
     865  	_close (orig_out);
     866        if (separate_stderr
     867  	  && orig_err != STDERR_FILENO)
     868  	_close (orig_err);
     869      }
     870  
     871    /* Close the standard input, standard output and standard error handles
     872       in the parent.  */ 
     873  
     874    _close (in);
     875    _close (out);
     876    if (separate_stderr)
     877      _close (errdes);
     878  
     879    return pid;
     880  }
     881  
     882  /* Wait for a child process to complete.  MS CRTDLL doesn't return
     883     enough information in status to decide if the child exited due to a
     884     signal or not, rather it simply returns an integer with the exit
     885     code of the child; eg., if the child exited with an abort() call
     886     and didn't have a handler for SIGABRT, it simply returns with
     887     status == 3.  We fix the status code to conform to the usual WIF*
     888     macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
     889  
     890  static pid_t
     891  pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
     892  		int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
     893  		const char **errmsg, int *err)
     894  {
     895    DWORD termstat;
     896    HANDLE h;
     897  
     898    if (time != NULL)
     899      memset (time, 0, sizeof *time);
     900  
     901    h = (HANDLE) pid;
     902  
     903    /* FIXME: If done is non-zero, we should probably try to kill the
     904       process.  */
     905    if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
     906      {
     907        CloseHandle (h);
     908        *err = ECHILD;
     909        *errmsg = "WaitForSingleObject";
     910        return -1;
     911      }
     912  
     913    GetExitCodeProcess (h, &termstat);
     914    CloseHandle (h);
     915   
     916    /* A value of 3 indicates that the child caught a signal, but not
     917       which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
     918       report SIGABRT.  */
     919    if (termstat == 3)
     920      *status = SIGABRT;
     921    else
     922      *status = (termstat & 0xff) << 8;
     923  
     924    return 0;
     925  }
     926  
     927  /* Create a pipe.  */
     928  
     929  static int
     930  pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
     931  		int binary)
     932  {
     933    return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
     934  }
     935  
     936  /* Get a FILE pointer to read from a file descriptor.  */
     937  
     938  static FILE *
     939  pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
     940  		   int binary)
     941  {
     942    HANDLE h = (HANDLE) _get_osfhandle (fd);
     943    if (h == INVALID_HANDLE_VALUE)
     944      return NULL;
     945    if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
     946      return NULL;
     947    return fdopen (fd, binary ? "rb" : "r");
     948  }
     949  
     950  static FILE *
     951  pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
     952  		   int binary)
     953  {
     954    HANDLE h = (HANDLE) _get_osfhandle (fd);
     955    if (h == INVALID_HANDLE_VALUE)
     956      return NULL;
     957    if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
     958      return NULL;
     959    return fdopen (fd, binary ? "wb" : "w");
     960  }
     961  
     962  #ifdef MAIN
     963  #include <stdio.h>
     964  
     965  int
     966  main (int argc ATTRIBUTE_UNUSED, char **argv)
     967  {
     968    char const *errmsg;
     969    int err;
     970    argv++;
     971    printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
     972    exit (0);
     973  }
     974  #endif