12a6b7db3Sskrll /* Utilities to execute a program in a subprocess (possibly linked by pipes
22a6b7db3Sskrll with other subprocesses), and wait for it. Generic Win32 specialization.
3*f22f0ef4Schristos Copyright (C) 1996-2022 Free Software Foundation, Inc.
42a6b7db3Sskrll
52a6b7db3Sskrll This file is part of the libiberty library.
62a6b7db3Sskrll Libiberty is free software; you can redistribute it and/or
72a6b7db3Sskrll modify it under the terms of the GNU Library General Public
82a6b7db3Sskrll License as published by the Free Software Foundation; either
92a6b7db3Sskrll version 2 of the License, or (at your option) any later version.
102a6b7db3Sskrll
112a6b7db3Sskrll Libiberty is distributed in the hope that it will be useful,
122a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
132a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
142a6b7db3Sskrll Library General Public License for more details.
152a6b7db3Sskrll
162a6b7db3Sskrll You should have received a copy of the GNU Library General Public
172a6b7db3Sskrll License along with libiberty; see the file COPYING.LIB. If not,
182a6b7db3Sskrll write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
192a6b7db3Sskrll Boston, MA 02110-1301, USA. */
202a6b7db3Sskrll
212a6b7db3Sskrll #include "pex-common.h"
222a6b7db3Sskrll
232a6b7db3Sskrll #include <windows.h>
242a6b7db3Sskrll
252a6b7db3Sskrll #ifdef HAVE_STDLIB_H
262a6b7db3Sskrll #include <stdlib.h>
272a6b7db3Sskrll #endif
282a6b7db3Sskrll #ifdef HAVE_STRING_H
292a6b7db3Sskrll #include <string.h>
302a6b7db3Sskrll #endif
312a6b7db3Sskrll #ifdef HAVE_UNISTD_H
322a6b7db3Sskrll #include <unistd.h>
332a6b7db3Sskrll #endif
342a6b7db3Sskrll #ifdef HAVE_SYS_WAIT_H
352a6b7db3Sskrll #include <sys/wait.h>
362a6b7db3Sskrll #endif
372a6b7db3Sskrll
382a6b7db3Sskrll #include <assert.h>
392a6b7db3Sskrll #include <process.h>
402a6b7db3Sskrll #include <io.h>
412a6b7db3Sskrll #include <fcntl.h>
422a6b7db3Sskrll #include <signal.h>
432a6b7db3Sskrll #include <sys/stat.h>
442a6b7db3Sskrll #include <errno.h>
452a6b7db3Sskrll #include <ctype.h>
462a6b7db3Sskrll
472a6b7db3Sskrll /* mingw32 headers may not define the following. */
482a6b7db3Sskrll
492a6b7db3Sskrll #ifndef _P_WAIT
502a6b7db3Sskrll # define _P_WAIT 0
512a6b7db3Sskrll # define _P_NOWAIT 1
522a6b7db3Sskrll # define _P_OVERLAY 2
532a6b7db3Sskrll # define _P_NOWAITO 3
542a6b7db3Sskrll # define _P_DETACH 4
552a6b7db3Sskrll
562a6b7db3Sskrll # define WAIT_CHILD 0
572a6b7db3Sskrll # define WAIT_GRANDCHILD 1
582a6b7db3Sskrll #endif
592a6b7db3Sskrll
602a6b7db3Sskrll #define MINGW_NAME "Minimalist GNU for Windows"
612a6b7db3Sskrll #define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
622a6b7db3Sskrll
632a6b7db3Sskrll extern char *stpcpy (char *dst, const char *src);
642a6b7db3Sskrll
652a6b7db3Sskrll /* Ensure that the executable pathname uses Win32 backslashes. This
662a6b7db3Sskrll is not necessary on NT, but on W9x, forward slashes causes
672a6b7db3Sskrll failure of spawn* and exec* functions (and probably any function
682a6b7db3Sskrll that calls CreateProcess) *iff* the executable pathname (argv[0])
692a6b7db3Sskrll is a quoted string. And quoting is necessary in case a pathname
702a6b7db3Sskrll contains embedded white space. You can't win. */
712a6b7db3Sskrll static void
backslashify(char * s)722a6b7db3Sskrll backslashify (char *s)
732a6b7db3Sskrll {
742a6b7db3Sskrll while ((s = strchr (s, '/')) != NULL)
752a6b7db3Sskrll *s = '\\';
762a6b7db3Sskrll return;
772a6b7db3Sskrll }
782a6b7db3Sskrll
792a6b7db3Sskrll static int pex_win32_open_read (struct pex_obj *, const char *, int);
805ba6b03cSchristos static int pex_win32_open_write (struct pex_obj *, const char *, int, int);
812a6b7db3Sskrll static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
822a6b7db3Sskrll char * const *, char * const *,
832a6b7db3Sskrll int, int, int, int,
842a6b7db3Sskrll const char **, int *);
852a6b7db3Sskrll static int pex_win32_close (struct pex_obj *, int);
86b3ac4aedSchristos static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
872a6b7db3Sskrll struct pex_time *, int, const char **, int *);
882a6b7db3Sskrll static int pex_win32_pipe (struct pex_obj *, int *, int);
892a6b7db3Sskrll static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
902a6b7db3Sskrll static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
912a6b7db3Sskrll
922a6b7db3Sskrll /* The list of functions we pass to the common routines. */
932a6b7db3Sskrll
942a6b7db3Sskrll const struct pex_funcs funcs =
952a6b7db3Sskrll {
962a6b7db3Sskrll pex_win32_open_read,
972a6b7db3Sskrll pex_win32_open_write,
982a6b7db3Sskrll pex_win32_exec_child,
992a6b7db3Sskrll pex_win32_close,
1002a6b7db3Sskrll pex_win32_wait,
1012a6b7db3Sskrll pex_win32_pipe,
1022a6b7db3Sskrll pex_win32_fdopenr,
1032a6b7db3Sskrll pex_win32_fdopenw,
1042a6b7db3Sskrll NULL /* cleanup */
1052a6b7db3Sskrll };
1062a6b7db3Sskrll
1072a6b7db3Sskrll /* Return a newly initialized pex_obj structure. */
1082a6b7db3Sskrll
1092a6b7db3Sskrll struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)1102a6b7db3Sskrll pex_init (int flags, const char *pname, const char *tempbase)
1112a6b7db3Sskrll {
1122a6b7db3Sskrll return pex_init_common (flags, pname, tempbase, &funcs);
1132a6b7db3Sskrll }
1142a6b7db3Sskrll
1152a6b7db3Sskrll /* Open a file for reading. */
1162a6b7db3Sskrll
1172a6b7db3Sskrll static int
pex_win32_open_read(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary)1182a6b7db3Sskrll pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
1192a6b7db3Sskrll int binary)
1202a6b7db3Sskrll {
1212a6b7db3Sskrll return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
1222a6b7db3Sskrll }
1232a6b7db3Sskrll
1242a6b7db3Sskrll /* Open a file for writing. */
1252a6b7db3Sskrll
1262a6b7db3Sskrll static int
pex_win32_open_write(struct pex_obj * obj ATTRIBUTE_UNUSED,const char * name,int binary,int append)1272a6b7db3Sskrll pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
1285ba6b03cSchristos int binary, int append)
1292a6b7db3Sskrll {
1302a6b7db3Sskrll /* Note that we can't use O_EXCL here because gcc may have already
1312a6b7db3Sskrll created the temporary file via make_temp_file. */
1325ba6b03cSchristos if (append)
1335ba6b03cSchristos return -1;
1342a6b7db3Sskrll return _open (name,
1352a6b7db3Sskrll (_O_WRONLY | _O_CREAT | _O_TRUNC
1362a6b7db3Sskrll | (binary ? _O_BINARY : _O_TEXT)),
1372a6b7db3Sskrll _S_IREAD | _S_IWRITE);
1382a6b7db3Sskrll }
1392a6b7db3Sskrll
1402a6b7db3Sskrll /* Close a file. */
1412a6b7db3Sskrll
1422a6b7db3Sskrll static int
pex_win32_close(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd)1432a6b7db3Sskrll pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
1442a6b7db3Sskrll {
1452a6b7db3Sskrll return _close (fd);
1462a6b7db3Sskrll }
1472a6b7db3Sskrll
1482a6b7db3Sskrll #ifdef USE_MINGW_MSYS
1492a6b7db3Sskrll static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
1502a6b7db3Sskrll
1512a6b7db3Sskrll /* Tack the executable on the end of a (possibly slash terminated) buffer
1522a6b7db3Sskrll and convert everything to \. */
1532a6b7db3Sskrll static const char *
tack_on_executable(char * buf,const char * executable)1542a6b7db3Sskrll tack_on_executable (char *buf, const char *executable)
1552a6b7db3Sskrll {
1562a6b7db3Sskrll char *p = strchr (buf, '\0');
1572a6b7db3Sskrll if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
1582a6b7db3Sskrll p[-1] = '\0';
1592a6b7db3Sskrll backslashify (strcat (buf, executable));
1602a6b7db3Sskrll return buf;
1612a6b7db3Sskrll }
1622a6b7db3Sskrll
1632a6b7db3Sskrll /* Walk down a registry hierarchy until the end. Return the key. */
1642a6b7db3Sskrll static HKEY
openkey(HKEY hStart,const char * keys[])1652a6b7db3Sskrll openkey (HKEY hStart, const char *keys[])
1662a6b7db3Sskrll {
1672a6b7db3Sskrll HKEY hKey, hTmp;
1682a6b7db3Sskrll for (hKey = hStart; *keys; keys++)
1692a6b7db3Sskrll {
1702a6b7db3Sskrll LONG res;
1712a6b7db3Sskrll hTmp = hKey;
1722a6b7db3Sskrll res = RegOpenKey (hTmp, *keys, &hKey);
1732a6b7db3Sskrll
1742a6b7db3Sskrll if (hTmp != HKEY_LOCAL_MACHINE)
1752a6b7db3Sskrll RegCloseKey (hTmp);
1762a6b7db3Sskrll
1772a6b7db3Sskrll if (res != ERROR_SUCCESS)
1782a6b7db3Sskrll return NULL;
1792a6b7db3Sskrll }
1802a6b7db3Sskrll return hKey;
1812a6b7db3Sskrll }
1822a6b7db3Sskrll
1832a6b7db3Sskrll /* Return the "mingw root" as derived from the mingw uninstall information. */
1842a6b7db3Sskrll static const char *
mingw_rootify(const char * executable)1852a6b7db3Sskrll mingw_rootify (const char *executable)
1862a6b7db3Sskrll {
1872a6b7db3Sskrll HKEY hKey, hTmp;
1882a6b7db3Sskrll DWORD maxlen;
1892a6b7db3Sskrll char *namebuf, *foundbuf;
1902a6b7db3Sskrll DWORD i;
1912a6b7db3Sskrll LONG res;
1922a6b7db3Sskrll
1932a6b7db3Sskrll /* Open the uninstall "directory". */
1942a6b7db3Sskrll hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
1952a6b7db3Sskrll
1962a6b7db3Sskrll /* Not found. */
1972a6b7db3Sskrll if (!hKey)
1982a6b7db3Sskrll return executable;
1992a6b7db3Sskrll
2002a6b7db3Sskrll /* Need to enumerate all of the keys here looking for one the most recent
2012a6b7db3Sskrll one for MinGW. */
2022a6b7db3Sskrll if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
2032a6b7db3Sskrll NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
2042a6b7db3Sskrll {
2052a6b7db3Sskrll RegCloseKey (hKey);
2062a6b7db3Sskrll return executable;
2072a6b7db3Sskrll }
2082a6b7db3Sskrll namebuf = XNEWVEC (char, ++maxlen);
2092a6b7db3Sskrll foundbuf = XNEWVEC (char, maxlen);
2102a6b7db3Sskrll foundbuf[0] = '\0';
2112a6b7db3Sskrll if (!namebuf || !foundbuf)
2122a6b7db3Sskrll {
2132a6b7db3Sskrll RegCloseKey (hKey);
2142a6b7db3Sskrll free (namebuf);
2152a6b7db3Sskrll free (foundbuf);
2162a6b7db3Sskrll return executable;
2172a6b7db3Sskrll }
2182a6b7db3Sskrll
2192a6b7db3Sskrll /* Look through all of the keys for one that begins with Minimal GNU...
2202a6b7db3Sskrll Try to get the latest version by doing a string compare although that
2212a6b7db3Sskrll string never really works with version number sorting. */
2222a6b7db3Sskrll for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
2232a6b7db3Sskrll {
2242a6b7db3Sskrll int match = strcasecmp (namebuf, MINGW_NAME);
2252a6b7db3Sskrll if (match < 0)
2262a6b7db3Sskrll continue;
2272a6b7db3Sskrll if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
2282a6b7db3Sskrll continue;
2292a6b7db3Sskrll if (strcasecmp (namebuf, foundbuf) > 0)
2302a6b7db3Sskrll strcpy (foundbuf, namebuf);
2312a6b7db3Sskrll }
2322a6b7db3Sskrll free (namebuf);
2332a6b7db3Sskrll
2342a6b7db3Sskrll /* If foundbuf is empty, we didn't find anything. Punt. */
2352a6b7db3Sskrll if (!foundbuf[0])
2362a6b7db3Sskrll {
2372a6b7db3Sskrll free (foundbuf);
2382a6b7db3Sskrll RegCloseKey (hKey);
2392a6b7db3Sskrll return executable;
2402a6b7db3Sskrll }
2412a6b7db3Sskrll
2422a6b7db3Sskrll /* Open the key that we wanted */
2432a6b7db3Sskrll res = RegOpenKey (hKey, foundbuf, &hTmp);
2442a6b7db3Sskrll RegCloseKey (hKey);
2452a6b7db3Sskrll free (foundbuf);
2462a6b7db3Sskrll
2472a6b7db3Sskrll /* Don't know why this would fail, but you gotta check */
2482a6b7db3Sskrll if (res != ERROR_SUCCESS)
2492a6b7db3Sskrll return executable;
2502a6b7db3Sskrll
2512a6b7db3Sskrll maxlen = 0;
2522a6b7db3Sskrll /* Get the length of the value pointed to by InstallLocation */
2532a6b7db3Sskrll if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
2542a6b7db3Sskrll &maxlen) != ERROR_SUCCESS || maxlen == 0)
2552a6b7db3Sskrll {
2562a6b7db3Sskrll RegCloseKey (hTmp);
2572a6b7db3Sskrll return executable;
2582a6b7db3Sskrll }
2592a6b7db3Sskrll
2602a6b7db3Sskrll /* Allocate space for the install location */
2612a6b7db3Sskrll foundbuf = XNEWVEC (char, maxlen + strlen (executable));
2622a6b7db3Sskrll if (!foundbuf)
2632a6b7db3Sskrll {
2642a6b7db3Sskrll free (foundbuf);
2652a6b7db3Sskrll RegCloseKey (hTmp);
2662a6b7db3Sskrll }
2672a6b7db3Sskrll
2682a6b7db3Sskrll /* Read the install location into the buffer */
2692a6b7db3Sskrll res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
2702a6b7db3Sskrll &maxlen);
2712a6b7db3Sskrll RegCloseKey (hTmp);
2722a6b7db3Sskrll if (res != ERROR_SUCCESS)
2732a6b7db3Sskrll {
2742a6b7db3Sskrll free (foundbuf);
2752a6b7db3Sskrll return executable;
2762a6b7db3Sskrll }
2772a6b7db3Sskrll
2782a6b7db3Sskrll /* Concatenate the install location and the executable, turn all slashes
2792a6b7db3Sskrll to backslashes, and return that. */
2802a6b7db3Sskrll return tack_on_executable (foundbuf, executable);
2812a6b7db3Sskrll }
2822a6b7db3Sskrll
2832a6b7db3Sskrll /* Read the install location of msys from it's installation file and
2842a6b7db3Sskrll rootify the executable based on that. */
2852a6b7db3Sskrll static const char *
msys_rootify(const char * executable)2862a6b7db3Sskrll msys_rootify (const char *executable)
2872a6b7db3Sskrll {
2882a6b7db3Sskrll size_t bufsize = 64;
2892a6b7db3Sskrll size_t execlen = strlen (executable) + 1;
2902a6b7db3Sskrll char *buf;
2912a6b7db3Sskrll DWORD res = 0;
2922a6b7db3Sskrll for (;;)
2932a6b7db3Sskrll {
2942a6b7db3Sskrll buf = XNEWVEC (char, bufsize + execlen);
2952a6b7db3Sskrll if (!buf)
2962a6b7db3Sskrll break;
2972a6b7db3Sskrll res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
2982a6b7db3Sskrll buf, bufsize, "msys.ini");
2992a6b7db3Sskrll if (!res)
3002a6b7db3Sskrll break;
3012a6b7db3Sskrll if (strlen (buf) < bufsize)
3022a6b7db3Sskrll break;
3032a6b7db3Sskrll res = 0;
3042a6b7db3Sskrll free (buf);
3052a6b7db3Sskrll bufsize *= 2;
3062a6b7db3Sskrll if (bufsize > 65536)
3072a6b7db3Sskrll {
3082a6b7db3Sskrll buf = NULL;
3092a6b7db3Sskrll break;
3102a6b7db3Sskrll }
3112a6b7db3Sskrll }
3122a6b7db3Sskrll
3132a6b7db3Sskrll if (res)
3142a6b7db3Sskrll return tack_on_executable (buf, executable);
3152a6b7db3Sskrll
3162a6b7db3Sskrll /* failed */
3172a6b7db3Sskrll free (buf);
3182a6b7db3Sskrll return executable;
3192a6b7db3Sskrll }
3202a6b7db3Sskrll #endif
3212a6b7db3Sskrll
3222a6b7db3Sskrll /* Return the number of arguments in an argv array, not including the null
3232a6b7db3Sskrll terminating argument. */
3242a6b7db3Sskrll
3252a6b7db3Sskrll static int
argv_to_argc(char * const * argv)3262a6b7db3Sskrll argv_to_argc (char *const *argv)
3272a6b7db3Sskrll {
3282a6b7db3Sskrll char *const *i = argv;
3292a6b7db3Sskrll while (*i)
3302a6b7db3Sskrll i++;
3312a6b7db3Sskrll return i - argv;
3322a6b7db3Sskrll }
3332a6b7db3Sskrll
3342a6b7db3Sskrll /* Return a Windows command-line from ARGV. It is the caller's
3352a6b7db3Sskrll responsibility to free the string returned. */
3362a6b7db3Sskrll
3372a6b7db3Sskrll static char *
argv_to_cmdline(char * const * argv)3382a6b7db3Sskrll argv_to_cmdline (char *const *argv)
3392a6b7db3Sskrll {
3402a6b7db3Sskrll char *cmdline;
3412a6b7db3Sskrll char *p;
3422a6b7db3Sskrll size_t cmdline_len;
3432a6b7db3Sskrll int i, j, k;
3445ba6b03cSchristos int needs_quotes;
3452a6b7db3Sskrll
3462a6b7db3Sskrll cmdline_len = 0;
3472a6b7db3Sskrll for (i = 0; argv[i]; i++)
3482a6b7db3Sskrll {
3495ba6b03cSchristos /* We only quote arguments that contain spaces, \t or " characters to
3505ba6b03cSchristos prevent wasting 2 chars per argument of the CreateProcess 32k char
3515ba6b03cSchristos limit. We need only escape embedded double-quotes and immediately
3522a6b7db3Sskrll preceeding backslash characters. A sequence of backslach characters
3532a6b7db3Sskrll that is not follwed by a double quote character will not be
3542a6b7db3Sskrll escaped. */
3555ba6b03cSchristos needs_quotes = 0;
3562a6b7db3Sskrll for (j = 0; argv[i][j]; j++)
3572a6b7db3Sskrll {
3585ba6b03cSchristos if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
3595ba6b03cSchristos {
3605ba6b03cSchristos needs_quotes = 1;
3615ba6b03cSchristos }
3625ba6b03cSchristos
3632a6b7db3Sskrll if (argv[i][j] == '"')
3642a6b7db3Sskrll {
3652a6b7db3Sskrll /* Escape preceeding backslashes. */
3662a6b7db3Sskrll for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
3672a6b7db3Sskrll cmdline_len++;
3682a6b7db3Sskrll /* Escape the qote character. */
3692a6b7db3Sskrll cmdline_len++;
3702a6b7db3Sskrll }
3712a6b7db3Sskrll }
37298f124a6Schristos if (j == 0)
37398f124a6Schristos needs_quotes = 1;
3742a6b7db3Sskrll /* Trailing backslashes also need to be escaped because they will be
3752a6b7db3Sskrll followed by the terminating quote. */
3765ba6b03cSchristos if (needs_quotes)
3775ba6b03cSchristos {
3782a6b7db3Sskrll for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
3792a6b7db3Sskrll cmdline_len++;
3805ba6b03cSchristos }
3812a6b7db3Sskrll cmdline_len += j;
3825ba6b03cSchristos /* for leading and trailing quotes and space */
3835ba6b03cSchristos cmdline_len += needs_quotes * 2 + 1;
3842a6b7db3Sskrll }
3852a6b7db3Sskrll cmdline = XNEWVEC (char, cmdline_len);
3862a6b7db3Sskrll p = cmdline;
3872a6b7db3Sskrll for (i = 0; argv[i]; i++)
3882a6b7db3Sskrll {
3895ba6b03cSchristos needs_quotes = 0;
3905ba6b03cSchristos for (j = 0; argv[i][j]; j++)
3915ba6b03cSchristos {
3925ba6b03cSchristos if (argv[i][j] == ' ' || argv[i][j] == '\t' || argv[i][j] == '"')
3935ba6b03cSchristos {
3945ba6b03cSchristos needs_quotes = 1;
3955ba6b03cSchristos break;
3965ba6b03cSchristos }
3975ba6b03cSchristos }
39898f124a6Schristos if (j == 0)
39998f124a6Schristos needs_quotes = 1;
4005ba6b03cSchristos
4015ba6b03cSchristos if (needs_quotes)
4025ba6b03cSchristos {
4032a6b7db3Sskrll *p++ = '"';
4045ba6b03cSchristos }
4052a6b7db3Sskrll for (j = 0; argv[i][j]; j++)
4062a6b7db3Sskrll {
4072a6b7db3Sskrll if (argv[i][j] == '"')
4082a6b7db3Sskrll {
4092a6b7db3Sskrll for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
4102a6b7db3Sskrll *p++ = '\\';
4112a6b7db3Sskrll *p++ = '\\';
4122a6b7db3Sskrll }
4132a6b7db3Sskrll *p++ = argv[i][j];
4142a6b7db3Sskrll }
4155ba6b03cSchristos if (needs_quotes)
4165ba6b03cSchristos {
4172a6b7db3Sskrll for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
4182a6b7db3Sskrll *p++ = '\\';
4192a6b7db3Sskrll *p++ = '"';
4205ba6b03cSchristos }
4212a6b7db3Sskrll *p++ = ' ';
4222a6b7db3Sskrll }
4232a6b7db3Sskrll p[-1] = '\0';
4242a6b7db3Sskrll return cmdline;
4252a6b7db3Sskrll }
4262a6b7db3Sskrll
4272a6b7db3Sskrll /* We'll try the passed filename with all the known standard
4282a6b7db3Sskrll extensions, and then without extension. We try no extension
4292a6b7db3Sskrll last so that we don't try to run some random extension-less
4302a6b7db3Sskrll file that might be hanging around. We try both extension
4312a6b7db3Sskrll and no extension so that we don't need any fancy logic
4322a6b7db3Sskrll to determine if a file has extension. */
4332a6b7db3Sskrll static const char *const
4342a6b7db3Sskrll std_suffixes[] = {
4352a6b7db3Sskrll ".com",
4362a6b7db3Sskrll ".exe",
4372a6b7db3Sskrll ".bat",
4382a6b7db3Sskrll ".cmd",
4392a6b7db3Sskrll "",
4402a6b7db3Sskrll 0
4412a6b7db3Sskrll };
4422a6b7db3Sskrll
4432a6b7db3Sskrll /* Returns the full path to PROGRAM. If SEARCH is true, look for
4442a6b7db3Sskrll PROGRAM in each directory in PATH. */
4452a6b7db3Sskrll
4462a6b7db3Sskrll static char *
find_executable(const char * program,BOOL search)4472a6b7db3Sskrll find_executable (const char *program, BOOL search)
4482a6b7db3Sskrll {
4492a6b7db3Sskrll char *full_executable;
4502a6b7db3Sskrll char *e;
4512a6b7db3Sskrll size_t fe_len;
4522a6b7db3Sskrll const char *path = 0;
4532a6b7db3Sskrll const char *const *ext;
4542a6b7db3Sskrll const char *p, *q;
4552a6b7db3Sskrll size_t proglen = strlen (program);
4562a6b7db3Sskrll int has_slash = (strchr (program, '/') || strchr (program, '\\'));
4572a6b7db3Sskrll HANDLE h;
4582a6b7db3Sskrll
4592a6b7db3Sskrll if (has_slash)
4602a6b7db3Sskrll search = FALSE;
4612a6b7db3Sskrll
4622a6b7db3Sskrll if (search)
4632a6b7db3Sskrll path = getenv ("PATH");
4642a6b7db3Sskrll if (!path)
4652a6b7db3Sskrll path = "";
4662a6b7db3Sskrll
4672a6b7db3Sskrll fe_len = 0;
4682a6b7db3Sskrll for (p = path; *p; p = q)
4692a6b7db3Sskrll {
4702a6b7db3Sskrll q = p;
4712a6b7db3Sskrll while (*q != ';' && *q != '\0')
4722a6b7db3Sskrll q++;
4732a6b7db3Sskrll if ((size_t)(q - p) > fe_len)
4742a6b7db3Sskrll fe_len = q - p;
4752a6b7db3Sskrll if (*q == ';')
4762a6b7db3Sskrll q++;
4772a6b7db3Sskrll }
4782a6b7db3Sskrll fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
4792a6b7db3Sskrll full_executable = XNEWVEC (char, fe_len);
4802a6b7db3Sskrll
4812a6b7db3Sskrll p = path;
4822a6b7db3Sskrll do
4832a6b7db3Sskrll {
4842a6b7db3Sskrll q = p;
4852a6b7db3Sskrll while (*q != ';' && *q != '\0')
4862a6b7db3Sskrll q++;
4872a6b7db3Sskrll
4882a6b7db3Sskrll e = full_executable;
4892a6b7db3Sskrll memcpy (e, p, q - p);
4902a6b7db3Sskrll e += (q - p);
4912a6b7db3Sskrll if (q - p)
4922a6b7db3Sskrll *e++ = '\\';
4932a6b7db3Sskrll strcpy (e, program);
4942a6b7db3Sskrll
4952a6b7db3Sskrll if (*q == ';')
4962a6b7db3Sskrll q++;
4972a6b7db3Sskrll
4982a6b7db3Sskrll for (e = full_executable; *e; e++)
4992a6b7db3Sskrll if (*e == '/')
5002a6b7db3Sskrll *e = '\\';
5012a6b7db3Sskrll
5022a6b7db3Sskrll /* At this point, e points to the terminating NUL character for
5032a6b7db3Sskrll full_executable. */
5042a6b7db3Sskrll for (ext = std_suffixes; *ext; ext++)
5052a6b7db3Sskrll {
5062a6b7db3Sskrll /* Remove any current extension. */
5072a6b7db3Sskrll *e = '\0';
5082a6b7db3Sskrll /* Add the new one. */
5092a6b7db3Sskrll strcat (full_executable, *ext);
5102a6b7db3Sskrll
5112a6b7db3Sskrll /* Attempt to open this file. */
5122a6b7db3Sskrll h = CreateFile (full_executable, GENERIC_READ,
5132a6b7db3Sskrll FILE_SHARE_READ | FILE_SHARE_WRITE,
5142a6b7db3Sskrll 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
5152a6b7db3Sskrll if (h != INVALID_HANDLE_VALUE)
5162a6b7db3Sskrll goto found;
5172a6b7db3Sskrll }
5182a6b7db3Sskrll p = q;
5192a6b7db3Sskrll }
5202a6b7db3Sskrll while (*p);
5212a6b7db3Sskrll free (full_executable);
5222a6b7db3Sskrll return 0;
5232a6b7db3Sskrll
5242a6b7db3Sskrll found:
5252a6b7db3Sskrll CloseHandle (h);
5262a6b7db3Sskrll return full_executable;
5272a6b7db3Sskrll }
5282a6b7db3Sskrll
5292a6b7db3Sskrll /* Low-level process creation function and helper. */
5302a6b7db3Sskrll
5312a6b7db3Sskrll static int
env_compare(const void * a_ptr,const void * b_ptr)5322a6b7db3Sskrll env_compare (const void *a_ptr, const void *b_ptr)
5332a6b7db3Sskrll {
5342a6b7db3Sskrll const char *a;
5352a6b7db3Sskrll const char *b;
5362a6b7db3Sskrll unsigned char c1;
5372a6b7db3Sskrll unsigned char c2;
5382a6b7db3Sskrll
5392a6b7db3Sskrll a = *(const char **) a_ptr;
5402a6b7db3Sskrll b = *(const char **) b_ptr;
5412a6b7db3Sskrll
5422a6b7db3Sskrll /* a and b will be of the form: VAR=VALUE
5432a6b7db3Sskrll We compare only the variable name part here using a case-insensitive
5442a6b7db3Sskrll comparison algorithm. It might appear that in fact strcasecmp () can
5452a6b7db3Sskrll take the place of this whole function, and indeed it could, save for
5462a6b7db3Sskrll the fact that it would fail in cases such as comparing A1=foo and
5472a6b7db3Sskrll A=bar (because 1 is less than = in the ASCII character set).
5482a6b7db3Sskrll (Environment variables containing no numbers would work in such a
5492a6b7db3Sskrll scenario.) */
5502a6b7db3Sskrll
5512a6b7db3Sskrll do
5522a6b7db3Sskrll {
5532a6b7db3Sskrll c1 = (unsigned char) tolower (*a++);
5542a6b7db3Sskrll c2 = (unsigned char) tolower (*b++);
5552a6b7db3Sskrll
5562a6b7db3Sskrll if (c1 == '=')
5572a6b7db3Sskrll c1 = '\0';
5582a6b7db3Sskrll
5592a6b7db3Sskrll if (c2 == '=')
5602a6b7db3Sskrll c2 = '\0';
5612a6b7db3Sskrll }
5622a6b7db3Sskrll while (c1 == c2 && c1 != '\0');
5632a6b7db3Sskrll
5642a6b7db3Sskrll return c1 - c2;
5652a6b7db3Sskrll }
5662a6b7db3Sskrll
5672a6b7db3Sskrll /* Execute a Windows executable as a child process. This will fail if the
5682a6b7db3Sskrll * target is not actually an executable, such as if it is a shell script. */
5692a6b7db3Sskrll
5702a6b7db3Sskrll static pid_t
win32_spawn(const char * executable,BOOL search,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)5712a6b7db3Sskrll win32_spawn (const char *executable,
5722a6b7db3Sskrll BOOL search,
5732a6b7db3Sskrll char *const *argv,
5742a6b7db3Sskrll char *const *env, /* array of strings of the form: VAR=VALUE */
5752a6b7db3Sskrll DWORD dwCreationFlags,
5762a6b7db3Sskrll LPSTARTUPINFO si,
5772a6b7db3Sskrll LPPROCESS_INFORMATION pi)
5782a6b7db3Sskrll {
5792a6b7db3Sskrll char *full_executable;
5802a6b7db3Sskrll char *cmdline;
5812a6b7db3Sskrll char **env_copy;
5822a6b7db3Sskrll char *env_block = NULL;
5832a6b7db3Sskrll
5842a6b7db3Sskrll full_executable = NULL;
5852a6b7db3Sskrll cmdline = NULL;
5862a6b7db3Sskrll
5872a6b7db3Sskrll if (env)
5882a6b7db3Sskrll {
5892a6b7db3Sskrll int env_size;
5902a6b7db3Sskrll
5912a6b7db3Sskrll /* Count the number of environment bindings supplied. */
5922a6b7db3Sskrll for (env_size = 0; env[env_size]; env_size++)
5932a6b7db3Sskrll continue;
5942a6b7db3Sskrll
5952a6b7db3Sskrll /* Assemble an environment block, if required. This consists of
5962a6b7db3Sskrll VAR=VALUE strings juxtaposed (with one null character between each
5972a6b7db3Sskrll pair) and an additional null at the end. */
5982a6b7db3Sskrll if (env_size > 0)
5992a6b7db3Sskrll {
6002a6b7db3Sskrll int var;
6012a6b7db3Sskrll int total_size = 1; /* 1 is for the final null. */
6022a6b7db3Sskrll char *bufptr;
6032a6b7db3Sskrll
6042a6b7db3Sskrll /* Windows needs the members of the block to be sorted by variable
6052a6b7db3Sskrll name. */
6062a6b7db3Sskrll env_copy = (char **) alloca (sizeof (char *) * env_size);
6072a6b7db3Sskrll memcpy (env_copy, env, sizeof (char *) * env_size);
6082a6b7db3Sskrll qsort (env_copy, env_size, sizeof (char *), env_compare);
6092a6b7db3Sskrll
6102a6b7db3Sskrll for (var = 0; var < env_size; var++)
6112a6b7db3Sskrll total_size += strlen (env[var]) + 1;
6122a6b7db3Sskrll
6132a6b7db3Sskrll env_block = XNEWVEC (char, total_size);
6142a6b7db3Sskrll bufptr = env_block;
6152a6b7db3Sskrll for (var = 0; var < env_size; var++)
6162a6b7db3Sskrll bufptr = stpcpy (bufptr, env_copy[var]) + 1;
6172a6b7db3Sskrll
6182a6b7db3Sskrll *bufptr = '\0';
6192a6b7db3Sskrll }
6202a6b7db3Sskrll }
6212a6b7db3Sskrll
6222a6b7db3Sskrll full_executable = find_executable (executable, search);
6232a6b7db3Sskrll if (!full_executable)
6242a6b7db3Sskrll goto error;
6252a6b7db3Sskrll cmdline = argv_to_cmdline (argv);
6262a6b7db3Sskrll if (!cmdline)
6272a6b7db3Sskrll goto error;
6282a6b7db3Sskrll
6292a6b7db3Sskrll /* Create the child process. */
6302a6b7db3Sskrll if (!CreateProcess (full_executable, cmdline,
6312a6b7db3Sskrll /*lpProcessAttributes=*/NULL,
6322a6b7db3Sskrll /*lpThreadAttributes=*/NULL,
6332a6b7db3Sskrll /*bInheritHandles=*/TRUE,
6342a6b7db3Sskrll dwCreationFlags,
6352a6b7db3Sskrll (LPVOID) env_block,
6362a6b7db3Sskrll /*lpCurrentDirectory=*/NULL,
6372a6b7db3Sskrll si,
6382a6b7db3Sskrll pi))
6392a6b7db3Sskrll {
6402a6b7db3Sskrll free (env_block);
6412a6b7db3Sskrll
6422a6b7db3Sskrll free (full_executable);
6432a6b7db3Sskrll
6442a6b7db3Sskrll return (pid_t) -1;
6452a6b7db3Sskrll }
6462a6b7db3Sskrll
6472a6b7db3Sskrll /* Clean up. */
6482a6b7db3Sskrll CloseHandle (pi->hThread);
6492a6b7db3Sskrll free (full_executable);
6502a6b7db3Sskrll free (env_block);
6512a6b7db3Sskrll
6522a6b7db3Sskrll return (pid_t) pi->hProcess;
6532a6b7db3Sskrll
6542a6b7db3Sskrll error:
6552a6b7db3Sskrll free (env_block);
6562a6b7db3Sskrll free (cmdline);
6572a6b7db3Sskrll free (full_executable);
6582a6b7db3Sskrll
6592a6b7db3Sskrll return (pid_t) -1;
6602a6b7db3Sskrll }
6612a6b7db3Sskrll
6622a6b7db3Sskrll /* Spawn a script. This simulates the Unix script execution mechanism.
6632a6b7db3Sskrll This function is called as a fallback if win32_spawn fails. */
6642a6b7db3Sskrll
6652a6b7db3Sskrll static pid_t
spawn_script(const char * executable,char * const * argv,char * const * env,DWORD dwCreationFlags,LPSTARTUPINFO si,LPPROCESS_INFORMATION pi)6662a6b7db3Sskrll spawn_script (const char *executable, char *const *argv,
6672a6b7db3Sskrll char* const *env,
6682a6b7db3Sskrll DWORD dwCreationFlags,
6692a6b7db3Sskrll LPSTARTUPINFO si,
6702a6b7db3Sskrll LPPROCESS_INFORMATION pi)
6712a6b7db3Sskrll {
6722a6b7db3Sskrll pid_t pid = (pid_t) -1;
6732a6b7db3Sskrll int save_errno = errno;
6742a6b7db3Sskrll int fd = _open (executable, _O_RDONLY);
6752a6b7db3Sskrll
6762a6b7db3Sskrll /* Try to open script, check header format, extract interpreter path,
6772a6b7db3Sskrll and spawn script using that interpretter. */
6782a6b7db3Sskrll if (fd >= 0)
6792a6b7db3Sskrll {
6802a6b7db3Sskrll char buf[MAX_PATH + 5];
6812a6b7db3Sskrll int len = _read (fd, buf, sizeof (buf) - 1);
6822a6b7db3Sskrll _close (fd);
6832a6b7db3Sskrll if (len > 3)
6842a6b7db3Sskrll {
6852a6b7db3Sskrll char *eol;
6862a6b7db3Sskrll buf[len] = '\0';
6872a6b7db3Sskrll eol = strchr (buf, '\n');
6882a6b7db3Sskrll if (eol && strncmp (buf, "#!", 2) == 0)
6892a6b7db3Sskrll {
6902a6b7db3Sskrll
6912a6b7db3Sskrll /* Header format is OK. */
6922a6b7db3Sskrll char *executable1;
6932a6b7db3Sskrll int new_argc;
6942a6b7db3Sskrll const char **avhere;
6952a6b7db3Sskrll
6962a6b7db3Sskrll /* Extract interpreter path. */
6972a6b7db3Sskrll do
6982a6b7db3Sskrll *eol = '\0';
6992a6b7db3Sskrll while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
7002a6b7db3Sskrll for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
7012a6b7db3Sskrll continue;
7022a6b7db3Sskrll backslashify (executable1);
7032a6b7db3Sskrll
7042a6b7db3Sskrll /* Duplicate argv, prepending the interpreter path. */
7052a6b7db3Sskrll new_argc = argv_to_argc (argv) + 1;
7062a6b7db3Sskrll avhere = XNEWVEC (const char *, new_argc + 1);
7072a6b7db3Sskrll *avhere = executable1;
7082a6b7db3Sskrll memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
7092a6b7db3Sskrll argv = (char *const *)avhere;
7102a6b7db3Sskrll
7112a6b7db3Sskrll /* Spawn the child. */
7122a6b7db3Sskrll #ifndef USE_MINGW_MSYS
7132a6b7db3Sskrll executable = strrchr (executable1, '\\') + 1;
7142a6b7db3Sskrll if (!executable)
7152a6b7db3Sskrll executable = executable1;
7162a6b7db3Sskrll pid = win32_spawn (executable, TRUE, argv, env,
7172a6b7db3Sskrll dwCreationFlags, si, pi);
7182a6b7db3Sskrll #else
7192a6b7db3Sskrll if (strchr (executable1, '\\') == NULL)
7202a6b7db3Sskrll pid = win32_spawn (executable1, TRUE, argv, env,
7212a6b7db3Sskrll dwCreationFlags, si, pi);
7222a6b7db3Sskrll else if (executable1[0] != '\\')
7232a6b7db3Sskrll pid = win32_spawn (executable1, FALSE, argv, env,
7242a6b7db3Sskrll dwCreationFlags, si, pi);
7252a6b7db3Sskrll else
7262a6b7db3Sskrll {
7272a6b7db3Sskrll const char *newex = mingw_rootify (executable1);
7282a6b7db3Sskrll *avhere = newex;
7292a6b7db3Sskrll pid = win32_spawn (newex, FALSE, argv, env,
7302a6b7db3Sskrll dwCreationFlags, si, pi);
7312a6b7db3Sskrll if (executable1 != newex)
7322a6b7db3Sskrll free ((char *) newex);
733b3ac4aedSchristos if (pid == (pid_t) -1)
7342a6b7db3Sskrll {
7352a6b7db3Sskrll newex = msys_rootify (executable1);
7362a6b7db3Sskrll if (newex != executable1)
7372a6b7db3Sskrll {
7382a6b7db3Sskrll *avhere = newex;
7392a6b7db3Sskrll pid = win32_spawn (newex, FALSE, argv, env,
7402a6b7db3Sskrll dwCreationFlags, si, pi);
7412a6b7db3Sskrll free ((char *) newex);
7422a6b7db3Sskrll }
7432a6b7db3Sskrll }
7442a6b7db3Sskrll }
7452a6b7db3Sskrll #endif
7462a6b7db3Sskrll free (avhere);
7472a6b7db3Sskrll }
7482a6b7db3Sskrll }
7492a6b7db3Sskrll }
750b3ac4aedSchristos if (pid == (pid_t) -1)
7512a6b7db3Sskrll errno = save_errno;
7522a6b7db3Sskrll return pid;
7532a6b7db3Sskrll }
7542a6b7db3Sskrll
7552a6b7db3Sskrll /* Execute a child. */
7562a6b7db3Sskrll
7572a6b7db3Sskrll static pid_t
pex_win32_exec_child(struct pex_obj * obj ATTRIBUTE_UNUSED,int flags,const char * executable,char * const * argv,char * const * env,int in,int out,int errdes,int toclose ATTRIBUTE_UNUSED,const char ** errmsg,int * err)7582a6b7db3Sskrll pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
7592a6b7db3Sskrll const char *executable, char * const * argv,
7602a6b7db3Sskrll char* const* env,
7612a6b7db3Sskrll int in, int out, int errdes,
7622a6b7db3Sskrll int toclose ATTRIBUTE_UNUSED,
7632a6b7db3Sskrll const char **errmsg,
7642a6b7db3Sskrll int *err)
7652a6b7db3Sskrll {
7662a6b7db3Sskrll pid_t pid;
7672a6b7db3Sskrll HANDLE stdin_handle;
7682a6b7db3Sskrll HANDLE stdout_handle;
7692a6b7db3Sskrll HANDLE stderr_handle;
7702a6b7db3Sskrll DWORD dwCreationFlags;
7712a6b7db3Sskrll OSVERSIONINFO version_info;
7722a6b7db3Sskrll STARTUPINFO si;
7732a6b7db3Sskrll PROCESS_INFORMATION pi;
774*f22f0ef4Schristos int orig_out, orig_in, orig_err = 0;
775b3ac4aedSchristos BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
776b3ac4aedSchristos
77705caefcfSchristos /* Ensure we have inheritable descriptors to pass to the child. */
778b3ac4aedSchristos orig_in = in;
779b3ac4aedSchristos in = _dup (orig_in);
780b3ac4aedSchristos
781b3ac4aedSchristos orig_out = out;
782b3ac4aedSchristos out = _dup (orig_out);
783b3ac4aedSchristos
784b3ac4aedSchristos if (separate_stderr)
785b3ac4aedSchristos {
786b3ac4aedSchristos orig_err = errdes;
787b3ac4aedSchristos errdes = _dup (orig_err);
788b3ac4aedSchristos }
7892a6b7db3Sskrll
7902a6b7db3Sskrll stdin_handle = INVALID_HANDLE_VALUE;
7912a6b7db3Sskrll stdout_handle = INVALID_HANDLE_VALUE;
7922a6b7db3Sskrll stderr_handle = INVALID_HANDLE_VALUE;
7932a6b7db3Sskrll
7942a6b7db3Sskrll stdin_handle = (HANDLE) _get_osfhandle (in);
7952a6b7db3Sskrll stdout_handle = (HANDLE) _get_osfhandle (out);
796b3ac4aedSchristos if (separate_stderr)
7972a6b7db3Sskrll stderr_handle = (HANDLE) _get_osfhandle (errdes);
7982a6b7db3Sskrll else
7992a6b7db3Sskrll stderr_handle = stdout_handle;
8002a6b7db3Sskrll
8012a6b7db3Sskrll /* Determine the version of Windows we are running on. */
8022a6b7db3Sskrll version_info.dwOSVersionInfoSize = sizeof (version_info);
8032a6b7db3Sskrll GetVersionEx (&version_info);
8042a6b7db3Sskrll if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
8052a6b7db3Sskrll /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
8062a6b7db3Sskrll supported, so we cannot avoid creating a console window. */
8072a6b7db3Sskrll dwCreationFlags = 0;
8082a6b7db3Sskrll else
8092a6b7db3Sskrll {
8102a6b7db3Sskrll HANDLE conout_handle;
8112a6b7db3Sskrll
8122a6b7db3Sskrll /* Determine whether or not we have an associated console. */
8132a6b7db3Sskrll conout_handle = CreateFile("CONOUT$",
8142a6b7db3Sskrll GENERIC_WRITE,
8152a6b7db3Sskrll FILE_SHARE_WRITE,
8162a6b7db3Sskrll /*lpSecurityAttributes=*/NULL,
8172a6b7db3Sskrll OPEN_EXISTING,
8182a6b7db3Sskrll FILE_ATTRIBUTE_NORMAL,
8192a6b7db3Sskrll /*hTemplateFile=*/NULL);
8202a6b7db3Sskrll if (conout_handle == INVALID_HANDLE_VALUE)
8212a6b7db3Sskrll /* There is no console associated with this process. Since
8222a6b7db3Sskrll the child is a console process, the OS would normally
8232a6b7db3Sskrll create a new console Window for the child. Since we'll be
8242a6b7db3Sskrll redirecting the child's standard streams, we do not need
8252a6b7db3Sskrll the console window. */
8262a6b7db3Sskrll dwCreationFlags = CREATE_NO_WINDOW;
8272a6b7db3Sskrll else
8282a6b7db3Sskrll {
8292a6b7db3Sskrll /* There is a console associated with the process, so the OS
8302a6b7db3Sskrll will not create a new console. And, if we use
8312a6b7db3Sskrll CREATE_NO_WINDOW in this situation, the child will have
8322a6b7db3Sskrll no associated console. Therefore, if the child's
8332a6b7db3Sskrll standard streams are connected to the console, the output
8342a6b7db3Sskrll will be discarded. */
8352a6b7db3Sskrll CloseHandle(conout_handle);
8362a6b7db3Sskrll dwCreationFlags = 0;
8372a6b7db3Sskrll }
8382a6b7db3Sskrll }
8392a6b7db3Sskrll
8402a6b7db3Sskrll /* Since the child will be a console process, it will, by default,
8412a6b7db3Sskrll connect standard input/output to its console. However, we want
8422a6b7db3Sskrll the child to use the handles specifically designated above. In
8432a6b7db3Sskrll addition, if there is no console (such as when we are running in
8442a6b7db3Sskrll a Cygwin X window), then we must redirect the child's
8452a6b7db3Sskrll input/output, as there is no console for the child to use. */
8462a6b7db3Sskrll memset (&si, 0, sizeof (si));
8472a6b7db3Sskrll si.cb = sizeof (si);
8482a6b7db3Sskrll si.dwFlags = STARTF_USESTDHANDLES;
8492a6b7db3Sskrll si.hStdInput = stdin_handle;
8502a6b7db3Sskrll si.hStdOutput = stdout_handle;
8512a6b7db3Sskrll si.hStdError = stderr_handle;
8522a6b7db3Sskrll
8532a6b7db3Sskrll /* Create the child process. */
8542a6b7db3Sskrll pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
8552a6b7db3Sskrll argv, env, dwCreationFlags, &si, &pi);
8562a6b7db3Sskrll if (pid == (pid_t) -1)
8572a6b7db3Sskrll pid = spawn_script (executable, argv, env, dwCreationFlags,
8582a6b7db3Sskrll &si, &pi);
8592a6b7db3Sskrll if (pid == (pid_t) -1)
8602a6b7db3Sskrll {
8612a6b7db3Sskrll *err = ENOENT;
8622a6b7db3Sskrll *errmsg = "CreateProcess";
8632a6b7db3Sskrll }
8642a6b7db3Sskrll
86505caefcfSchristos /* If the child was created successfully, close the original file
86605caefcfSchristos descriptors. If the process creation fails, these are closed by
86705caefcfSchristos pex_run_in_environment instead. We must not close them twice as
86805caefcfSchristos that seems to cause a Windows exception. */
86905caefcfSchristos
87005caefcfSchristos if (pid != (pid_t) -1)
87105caefcfSchristos {
87205caefcfSchristos if (orig_in != STDIN_FILENO)
87305caefcfSchristos _close (orig_in);
87405caefcfSchristos if (orig_out != STDOUT_FILENO)
87505caefcfSchristos _close (orig_out);
87605caefcfSchristos if (separate_stderr
87705caefcfSchristos && orig_err != STDERR_FILENO)
87805caefcfSchristos _close (orig_err);
87905caefcfSchristos }
88005caefcfSchristos
881b3ac4aedSchristos /* Close the standard input, standard output and standard error handles
882b3ac4aedSchristos in the parent. */
883b3ac4aedSchristos
884b3ac4aedSchristos _close (in);
885b3ac4aedSchristos _close (out);
886b3ac4aedSchristos if (separate_stderr)
887b3ac4aedSchristos _close (errdes);
8882a6b7db3Sskrll
8892a6b7db3Sskrll return pid;
8902a6b7db3Sskrll }
8912a6b7db3Sskrll
8922a6b7db3Sskrll /* Wait for a child process to complete. MS CRTDLL doesn't return
8932a6b7db3Sskrll enough information in status to decide if the child exited due to a
8942a6b7db3Sskrll signal or not, rather it simply returns an integer with the exit
8952a6b7db3Sskrll code of the child; eg., if the child exited with an abort() call
8962a6b7db3Sskrll and didn't have a handler for SIGABRT, it simply returns with
8972a6b7db3Sskrll status == 3. We fix the status code to conform to the usual WIF*
8982a6b7db3Sskrll macros. Note that WIFSIGNALED will never be true under CRTDLL. */
8992a6b7db3Sskrll
900b3ac4aedSchristos static pid_t
pex_win32_wait(struct pex_obj * obj ATTRIBUTE_UNUSED,pid_t pid,int * status,struct pex_time * time,int done ATTRIBUTE_UNUSED,const char ** errmsg,int * err)9012a6b7db3Sskrll pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
9022a6b7db3Sskrll int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
9032a6b7db3Sskrll const char **errmsg, int *err)
9042a6b7db3Sskrll {
9052a6b7db3Sskrll DWORD termstat;
9062a6b7db3Sskrll HANDLE h;
9072a6b7db3Sskrll
9082a6b7db3Sskrll if (time != NULL)
9092a6b7db3Sskrll memset (time, 0, sizeof *time);
9102a6b7db3Sskrll
9112a6b7db3Sskrll h = (HANDLE) pid;
9122a6b7db3Sskrll
9132a6b7db3Sskrll /* FIXME: If done is non-zero, we should probably try to kill the
9142a6b7db3Sskrll process. */
9152a6b7db3Sskrll if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
9162a6b7db3Sskrll {
9172a6b7db3Sskrll CloseHandle (h);
9182a6b7db3Sskrll *err = ECHILD;
9192a6b7db3Sskrll *errmsg = "WaitForSingleObject";
9202a6b7db3Sskrll return -1;
9212a6b7db3Sskrll }
9222a6b7db3Sskrll
9232a6b7db3Sskrll GetExitCodeProcess (h, &termstat);
9242a6b7db3Sskrll CloseHandle (h);
9252a6b7db3Sskrll
9262a6b7db3Sskrll /* A value of 3 indicates that the child caught a signal, but not
9272a6b7db3Sskrll which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we
9282a6b7db3Sskrll report SIGABRT. */
9292a6b7db3Sskrll if (termstat == 3)
9302a6b7db3Sskrll *status = SIGABRT;
9312a6b7db3Sskrll else
9322a6b7db3Sskrll *status = (termstat & 0xff) << 8;
9332a6b7db3Sskrll
9342a6b7db3Sskrll return 0;
9352a6b7db3Sskrll }
9362a6b7db3Sskrll
9372a6b7db3Sskrll /* Create a pipe. */
9382a6b7db3Sskrll
9392a6b7db3Sskrll static int
pex_win32_pipe(struct pex_obj * obj ATTRIBUTE_UNUSED,int * p,int binary)9402a6b7db3Sskrll pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
9412a6b7db3Sskrll int binary)
9422a6b7db3Sskrll {
943b3ac4aedSchristos return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
9442a6b7db3Sskrll }
9452a6b7db3Sskrll
9462a6b7db3Sskrll /* Get a FILE pointer to read from a file descriptor. */
9472a6b7db3Sskrll
9482a6b7db3Sskrll static FILE *
pex_win32_fdopenr(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)9492a6b7db3Sskrll pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9502a6b7db3Sskrll int binary)
9512a6b7db3Sskrll {
952b3ac4aedSchristos HANDLE h = (HANDLE) _get_osfhandle (fd);
953b3ac4aedSchristos if (h == INVALID_HANDLE_VALUE)
954b3ac4aedSchristos return NULL;
955b3ac4aedSchristos if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
956b3ac4aedSchristos return NULL;
9572a6b7db3Sskrll return fdopen (fd, binary ? "rb" : "r");
9582a6b7db3Sskrll }
9592a6b7db3Sskrll
9602a6b7db3Sskrll static FILE *
pex_win32_fdopenw(struct pex_obj * obj ATTRIBUTE_UNUSED,int fd,int binary)9612a6b7db3Sskrll pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
9622a6b7db3Sskrll int binary)
9632a6b7db3Sskrll {
9642a6b7db3Sskrll HANDLE h = (HANDLE) _get_osfhandle (fd);
9652a6b7db3Sskrll if (h == INVALID_HANDLE_VALUE)
9662a6b7db3Sskrll return NULL;
9672a6b7db3Sskrll if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
9682a6b7db3Sskrll return NULL;
9692a6b7db3Sskrll return fdopen (fd, binary ? "wb" : "w");
9702a6b7db3Sskrll }
9712a6b7db3Sskrll
9722a6b7db3Sskrll #ifdef MAIN
9732a6b7db3Sskrll #include <stdio.h>
9742a6b7db3Sskrll
9752a6b7db3Sskrll int
main(int argc ATTRIBUTE_UNUSED,char ** argv)9762a6b7db3Sskrll main (int argc ATTRIBUTE_UNUSED, char **argv)
9772a6b7db3Sskrll {
9782a6b7db3Sskrll char const *errmsg;
9792a6b7db3Sskrll int err;
9802a6b7db3Sskrll argv++;
9812a6b7db3Sskrll printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
9822a6b7db3Sskrll exit (0);
9832a6b7db3Sskrll }
9842a6b7db3Sskrll #endif
985