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