1/* Utilities to execute a program in a subprocess (possibly linked by pipes 2 with other subprocesses), and wait for it. Generic Win32 specialization. 3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 4 Free Software Foundation, Inc. 5 6This file is part of the libiberty library. 7Libiberty is free software; you can redistribute it and/or 8modify it under the terms of the GNU Library General Public 9License as published by the Free Software Foundation; either 10version 2 of the License, or (at your option) any later version. 11 12Libiberty is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15Library General Public License for more details. 16 17You should have received a copy of the GNU Library General Public 18License along with libiberty; see the file COPYING.LIB. If not, 19write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 20Boston, 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 64extern 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. */ 72static void 73backslashify (char *s) 74{ 75 while ((s = strchr (s, '/')) != NULL) 76 *s = '\\'; 77 return; 78} 79 80static int pex_win32_open_read (struct pex_obj *, const char *, int); 81static int pex_win32_open_write (struct pex_obj *, const char *, int); 82static long pex_win32_exec_child (struct pex_obj *, int, const char *, 83 char * const *, char * const *, 84 int, int, int, int, 85 const char **, int *); 86static int pex_win32_close (struct pex_obj *, int); 87static int pex_win32_wait (struct pex_obj *, long, int *, 88 struct pex_time *, int, const char **, int *); 89static int pex_win32_pipe (struct pex_obj *, int *, int); 90static FILE *pex_win32_fdopenr (struct pex_obj *, int, int); 91static FILE *pex_win32_fdopenw (struct pex_obj *, int, int); 92 93/* The list of functions we pass to the common routines. */ 94 95const 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 110struct pex_obj * 111pex_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 118static int 119pex_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 127static int 128pex_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 141static int 142pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) 143{ 144 return _close (fd); 145} 146 147#ifdef USE_MINGW_MSYS 148static 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 \. */ 152static const char * 153tack_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. */ 163static HKEY 164openkey (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. */ 183static const char * 184mingw_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. */ 286static const char * 287msys_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/* Return a Windows command-line from ARGV. It is the caller's 325 responsibility to free the string returned. */ 326 327static char * 328argv_to_cmdline (char *const *argv) 329{ 330 char *cmdline; 331 char *p; 332 size_t cmdline_len; 333 int i, j, k; 334 335 cmdline_len = 0; 336 for (i = 0; argv[i]; i++) 337 { 338 /* We quote every last argument. This simplifies the problem; 339 we need only escape embedded double-quotes and immediately 340 preceeding backslash characters. A sequence of backslach characters 341 that is not follwed by a double quote character will not be 342 escaped. */ 343 for (j = 0; argv[i][j]; j++) 344 { 345 if (argv[i][j] == '"') 346 { 347 /* Escape preceeding backslashes. */ 348 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) 349 cmdline_len++; 350 /* Escape the qote character. */ 351 cmdline_len++; 352 } 353 } 354 /* Trailing backslashes also need to be escaped because they will be 355 followed by the terminating quote. */ 356 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) 357 cmdline_len++; 358 cmdline_len += j; 359 cmdline_len += 3; /* for leading and trailing quotes and space */ 360 } 361 cmdline = XNEWVEC (char, cmdline_len); 362 p = cmdline; 363 for (i = 0; argv[i]; i++) 364 { 365 *p++ = '"'; 366 for (j = 0; argv[i][j]; j++) 367 { 368 if (argv[i][j] == '"') 369 { 370 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) 371 *p++ = '\\'; 372 *p++ = '\\'; 373 } 374 *p++ = argv[i][j]; 375 } 376 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--) 377 *p++ = '\\'; 378 *p++ = '"'; 379 *p++ = ' '; 380 } 381 p[-1] = '\0'; 382 return cmdline; 383} 384 385/* We'll try the passed filename with all the known standard 386 extensions, and then without extension. We try no extension 387 last so that we don't try to run some random extension-less 388 file that might be hanging around. We try both extension 389 and no extension so that we don't need any fancy logic 390 to determine if a file has extension. */ 391static const char *const 392std_suffixes[] = { 393 ".com", 394 ".exe", 395 ".bat", 396 ".cmd", 397 "", 398 0 399}; 400 401/* Returns the full path to PROGRAM. If SEARCH is true, look for 402 PROGRAM in each directory in PATH. */ 403 404static char * 405find_executable (const char *program, BOOL search) 406{ 407 char *full_executable; 408 char *e; 409 size_t fe_len; 410 const char *path = 0; 411 const char *const *ext; 412 const char *p, *q; 413 size_t proglen = strlen (program); 414 int has_slash = (strchr (program, '/') || strchr (program, '\\')); 415 HANDLE h; 416 417 if (has_slash) 418 search = FALSE; 419 420 if (search) 421 path = getenv ("PATH"); 422 if (!path) 423 path = ""; 424 425 fe_len = 0; 426 for (p = path; *p; p = q) 427 { 428 q = p; 429 while (*q != ';' && *q != '\0') 430 q++; 431 if ((size_t)(q - p) > fe_len) 432 fe_len = q - p; 433 if (*q == ';') 434 q++; 435 } 436 fe_len = fe_len + 1 + proglen + 5 /* space for extension */; 437 full_executable = XNEWVEC (char, fe_len); 438 439 p = path; 440 do 441 { 442 q = p; 443 while (*q != ';' && *q != '\0') 444 q++; 445 446 e = full_executable; 447 memcpy (e, p, q - p); 448 e += (q - p); 449 if (q - p) 450 *e++ = '\\'; 451 strcpy (e, program); 452 453 if (*q == ';') 454 q++; 455 456 for (e = full_executable; *e; e++) 457 if (*e == '/') 458 *e = '\\'; 459 460 /* At this point, e points to the terminating NUL character for 461 full_executable. */ 462 for (ext = std_suffixes; *ext; ext++) 463 { 464 /* Remove any current extension. */ 465 *e = '\0'; 466 /* Add the new one. */ 467 strcat (full_executable, *ext); 468 469 /* Attempt to open this file. */ 470 h = CreateFile (full_executable, GENERIC_READ, 471 FILE_SHARE_READ | FILE_SHARE_WRITE, 472 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 473 if (h != INVALID_HANDLE_VALUE) 474 goto found; 475 } 476 p = q; 477 } 478 while (*p); 479 free (full_executable); 480 return 0; 481 482 found: 483 CloseHandle (h); 484 return full_executable; 485} 486 487/* Low-level process creation function and helper. */ 488 489static int 490env_compare (const void *a_ptr, const void *b_ptr) 491{ 492 const char *a; 493 const char *b; 494 unsigned char c1; 495 unsigned char c2; 496 497 a = *(const char **) a_ptr; 498 b = *(const char **) b_ptr; 499 500 /* a and b will be of the form: VAR=VALUE 501 We compare only the variable name part here using a case-insensitive 502 comparison algorithm. It might appear that in fact strcasecmp () can 503 take the place of this whole function, and indeed it could, save for 504 the fact that it would fail in cases such as comparing A1=foo and 505 A=bar (because 1 is less than = in the ASCII character set). 506 (Environment variables containing no numbers would work in such a 507 scenario.) */ 508 509 do 510 { 511 c1 = (unsigned char) tolower (*a++); 512 c2 = (unsigned char) tolower (*b++); 513 514 if (c1 == '=') 515 c1 = '\0'; 516 517 if (c2 == '=') 518 c2 = '\0'; 519 } 520 while (c1 == c2 && c1 != '\0'); 521 522 return c1 - c2; 523} 524 525static long 526win32_spawn (const char *executable, 527 BOOL search, 528 char *const *argv, 529 char *const *env, /* array of strings of the form: VAR=VALUE */ 530 DWORD dwCreationFlags, 531 LPSTARTUPINFO si, 532 LPPROCESS_INFORMATION pi) 533{ 534 char *full_executable; 535 char *cmdline; 536 char **env_copy; 537 char *env_block = NULL; 538 539 full_executable = NULL; 540 cmdline = NULL; 541 542 if (env) 543 { 544 int env_size; 545 546 /* Count the number of environment bindings supplied. */ 547 for (env_size = 0; env[env_size]; env_size++) 548 continue; 549 550 /* Assemble an environment block, if required. This consists of 551 VAR=VALUE strings juxtaposed (with one null character between each 552 pair) and an additional null at the end. */ 553 if (env_size > 0) 554 { 555 int var; 556 int total_size = 1; /* 1 is for the final null. */ 557 char *bufptr; 558 559 /* Windows needs the members of the block to be sorted by variable 560 name. */ 561 env_copy = (char **) alloca (sizeof (char *) * env_size); 562 memcpy (env_copy, env, sizeof (char *) * env_size); 563 qsort (env_copy, env_size, sizeof (char *), env_compare); 564 565 for (var = 0; var < env_size; var++) 566 total_size += strlen (env[var]) + 1; 567 568 env_block = XNEWVEC (char, total_size); 569 bufptr = env_block; 570 for (var = 0; var < env_size; var++) 571 bufptr = stpcpy (bufptr, env_copy[var]) + 1; 572 573 *bufptr = '\0'; 574 } 575 } 576 577 full_executable = find_executable (executable, search); 578 if (!full_executable) 579 goto error; 580 cmdline = argv_to_cmdline (argv); 581 if (!cmdline) 582 goto error; 583 584 /* Create the child process. */ 585 if (!CreateProcess (full_executable, cmdline, 586 /*lpProcessAttributes=*/NULL, 587 /*lpThreadAttributes=*/NULL, 588 /*bInheritHandles=*/TRUE, 589 dwCreationFlags, 590 (LPVOID) env_block, 591 /*lpCurrentDirectory=*/NULL, 592 si, 593 pi)) 594 { 595 if (env_block) 596 free (env_block); 597 598 free (full_executable); 599 600 return -1; 601 } 602 603 /* Clean up. */ 604 CloseHandle (pi->hThread); 605 free (full_executable); 606 if (env_block) 607 free (env_block); 608 609 return (long) pi->hProcess; 610 611 error: 612 if (env_block) 613 free (env_block); 614 if (cmdline) 615 free (cmdline); 616 if (full_executable) 617 free (full_executable); 618 619 return -1; 620} 621 622static long 623spawn_script (const char *executable, char *const *argv, 624 char* const *env, 625 DWORD dwCreationFlags, 626 LPSTARTUPINFO si, 627 LPPROCESS_INFORMATION pi) 628{ 629 int pid = -1; 630 int save_errno = errno; 631 int fd = _open (executable, _O_RDONLY); 632 633 if (fd >= 0) 634 { 635 char buf[MAX_PATH + 5]; 636 int len = _read (fd, buf, sizeof (buf) - 1); 637 _close (fd); 638 if (len > 3) 639 { 640 char *eol; 641 buf[len] = '\0'; 642 eol = strchr (buf, '\n'); 643 if (eol && strncmp (buf, "#!", 2) == 0) 644 { 645 char *executable1; 646 const char ** avhere = (const char **) --argv; 647 do 648 *eol = '\0'; 649 while (*--eol == '\r' || *eol == ' ' || *eol == '\t'); 650 for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++) 651 continue; 652 653 backslashify (executable1); 654 *avhere = executable1; 655#ifndef USE_MINGW_MSYS 656 executable = strrchr (executable1, '\\') + 1; 657 if (!executable) 658 executable = executable1; 659 pid = win32_spawn (executable, TRUE, argv, env, 660 dwCreationFlags, si, pi); 661#else 662 if (strchr (executable1, '\\') == NULL) 663 pid = win32_spawn (executable1, TRUE, argv, env, 664 dwCreationFlags, si, pi); 665 else if (executable1[0] != '\\') 666 pid = win32_spawn (executable1, FALSE, argv, env, 667 dwCreationFlags, si, pi); 668 else 669 { 670 const char *newex = mingw_rootify (executable1); 671 *avhere = newex; 672 pid = win32_spawn (newex, FALSE, argv, env, 673 dwCreationFlags, si, pi); 674 if (executable1 != newex) 675 free ((char *) newex); 676 if (pid < 0) 677 { 678 newex = msys_rootify (executable1); 679 if (newex != executable1) 680 { 681 *avhere = newex; 682 pid = win32_spawn (newex, FALSE, argv, env, 683 dwCreationFlags, si, pi); 684 free ((char *) newex); 685 } 686 } 687 } 688#endif 689 } 690 } 691 } 692 if (pid < 0) 693 errno = save_errno; 694 return pid; 695} 696 697/* Execute a child. */ 698 699static long 700pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags, 701 const char *executable, char * const * argv, 702 char* const* env, 703 int in, int out, int errdes, 704 int toclose ATTRIBUTE_UNUSED, 705 const char **errmsg, 706 int *err) 707{ 708 long pid; 709 HANDLE stdin_handle; 710 HANDLE stdout_handle; 711 HANDLE stderr_handle; 712 DWORD dwCreationFlags; 713 OSVERSIONINFO version_info; 714 STARTUPINFO si; 715 PROCESS_INFORMATION pi; 716 717 stdin_handle = INVALID_HANDLE_VALUE; 718 stdout_handle = INVALID_HANDLE_VALUE; 719 stderr_handle = INVALID_HANDLE_VALUE; 720 721 stdin_handle = (HANDLE) _get_osfhandle (in); 722 stdout_handle = (HANDLE) _get_osfhandle (out); 723 if (!(flags & PEX_STDERR_TO_STDOUT)) 724 stderr_handle = (HANDLE) _get_osfhandle (errdes); 725 else 726 stderr_handle = stdout_handle; 727 728 /* Determine the version of Windows we are running on. */ 729 version_info.dwOSVersionInfoSize = sizeof (version_info); 730 GetVersionEx (&version_info); 731 if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) 732 /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not 733 supported, so we cannot avoid creating a console window. */ 734 dwCreationFlags = 0; 735 else 736 { 737 HANDLE conout_handle; 738 739 /* Determine whether or not we have an associated console. */ 740 conout_handle = CreateFile("CONOUT$", 741 GENERIC_WRITE, 742 FILE_SHARE_WRITE, 743 /*lpSecurityAttributes=*/NULL, 744 OPEN_EXISTING, 745 FILE_ATTRIBUTE_NORMAL, 746 /*hTemplateFile=*/NULL); 747 if (conout_handle == INVALID_HANDLE_VALUE) 748 /* There is no console associated with this process. Since 749 the child is a console process, the OS would normally 750 create a new console Window for the child. Since we'll be 751 redirecting the child's standard streams, we do not need 752 the console window. */ 753 dwCreationFlags = CREATE_NO_WINDOW; 754 else 755 { 756 /* There is a console associated with the process, so the OS 757 will not create a new console. And, if we use 758 CREATE_NO_WINDOW in this situation, the child will have 759 no associated console. Therefore, if the child's 760 standard streams are connected to the console, the output 761 will be discarded. */ 762 CloseHandle(conout_handle); 763 dwCreationFlags = 0; 764 } 765 } 766 767 /* Since the child will be a console process, it will, by default, 768 connect standard input/output to its console. However, we want 769 the child to use the handles specifically designated above. In 770 addition, if there is no console (such as when we are running in 771 a Cygwin X window), then we must redirect the child's 772 input/output, as there is no console for the child to use. */ 773 memset (&si, 0, sizeof (si)); 774 si.cb = sizeof (si); 775 si.dwFlags = STARTF_USESTDHANDLES; 776 si.hStdInput = stdin_handle; 777 si.hStdOutput = stdout_handle; 778 si.hStdError = stderr_handle; 779 780 /* Create the child process. */ 781 pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0, 782 argv, env, dwCreationFlags, &si, &pi); 783 if (pid == -1) 784 pid = spawn_script (executable, argv, env, dwCreationFlags, 785 &si, &pi); 786 if (pid == -1) 787 { 788 *err = ENOENT; 789 *errmsg = "CreateProcess"; 790 } 791 792 /* Close the standard output and standard error handles in the 793 parent. */ 794 if (out != STDOUT_FILENO) 795 obj->funcs->close (obj, out); 796 if (errdes != STDERR_FILENO) 797 obj->funcs->close (obj, errdes); 798 799 return pid; 800} 801 802/* Wait for a child process to complete. MS CRTDLL doesn't return 803 enough information in status to decide if the child exited due to a 804 signal or not, rather it simply returns an integer with the exit 805 code of the child; eg., if the child exited with an abort() call 806 and didn't have a handler for SIGABRT, it simply returns with 807 status == 3. We fix the status code to conform to the usual WIF* 808 macros. Note that WIFSIGNALED will never be true under CRTDLL. */ 809 810static int 811pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid, 812 int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED, 813 const char **errmsg, int *err) 814{ 815 DWORD termstat; 816 HANDLE h; 817 818 if (time != NULL) 819 memset (time, 0, sizeof *time); 820 821 h = (HANDLE) pid; 822 823 /* FIXME: If done is non-zero, we should probably try to kill the 824 process. */ 825 if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0) 826 { 827 CloseHandle (h); 828 *err = ECHILD; 829 *errmsg = "WaitForSingleObject"; 830 return -1; 831 } 832 833 GetExitCodeProcess (h, &termstat); 834 CloseHandle (h); 835 836 /* A value of 3 indicates that the child caught a signal, but not 837 which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we 838 report SIGABRT. */ 839 if (termstat == 3) 840 *status = SIGABRT; 841 else 842 *status = (termstat & 0xff) << 8; 843 844 return 0; 845} 846 847/* Create a pipe. */ 848 849static int 850pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, 851 int binary) 852{ 853 return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT); 854} 855 856/* Get a FILE pointer to read from a file descriptor. */ 857 858static FILE * 859pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, 860 int binary) 861{ 862 return fdopen (fd, binary ? "rb" : "r"); 863} 864 865static FILE * 866pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, 867 int binary) 868{ 869 HANDLE h = (HANDLE) _get_osfhandle (fd); 870 if (h == INVALID_HANDLE_VALUE) 871 return NULL; 872 if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0)) 873 return NULL; 874 return fdopen (fd, binary ? "wb" : "w"); 875} 876 877#ifdef MAIN 878#include <stdio.h> 879 880int 881main (int argc ATTRIBUTE_UNUSED, char **argv) 882{ 883 char const *errmsg; 884 int err; 885 argv++; 886 printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err)); 887 exit (0); 888} 889#endif 890