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