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
4 Free Software Foundation, Inc.
6 This file is part of the libiberty library.
7 Libiberty is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 Libiberty is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with libiberty; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 #include "pex-common.h"
35 #ifdef HAVE_SYS_WAIT_H
45 /* mingw32 headers may not define the following. */
55 # define WAIT_GRANDCHILD 1
58 #define MINGW_NAME "Minimalist GNU for Windows"
59 #define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
61 /* Ensure that the executable pathname uses Win32 backslashes. This
62 is not necessary on NT, but on W9x, forward slashes causes
63 failure of spawn* and exec* functions (and probably any function
64 that calls CreateProcess) *iff* the executable pathname (argv[0])
65 is a quoted string. And quoting is necessary in case a pathname
66 contains embedded white space. You can't win. */
68 backslashify (char *s
)
70 while ((s
= strchr (s
, '/')) != NULL
)
75 /* This is a kludge to get around the Microsoft C spawn functions' propensity
76 to remove the outermost set of double quotes from all arguments. */
78 static const char * const *
79 fix_argv (char * const *argvec
)
85 /* See whether we need to change anything. */
86 for (command0
= argvec
[0]; *command0
!= '\0'; command0
++)
89 if (*command0
== '\0')
91 for (i
= 1; argvec
[i
] != NULL
; i
++)
92 if (strpbrk (argvec
[i
], "\" \t") != NULL
)
95 if (argvec
[i
] == NULL
)
96 return (const char * const *) argvec
;
99 for (i
= 0; argvec
[i
] != NULL
; i
++)
101 argv
= XNEWVEC (char *, i
+ 2);
103 argv
++; /* Leave space at the beginning of argv
104 for potential #! handling */
106 for (i
= 0; argvec
[i
] != NULL
; i
++)
107 argv
[i
] = xstrdup (argvec
[i
]);
110 backslashify (argv
[0]);
112 for (i
= 1; argv
[i
] != 0; i
++)
115 char *temp
, *newtemp
;
119 for (j
= 0; j
< len
; j
++)
123 newtemp
= XNEWVEC (char, len
+ 2);
124 strncpy (newtemp
, temp
, j
);
126 strncpy (&newtemp
[j
+1], &temp
[j
], len
-j
);
141 for (i
= 0; argv
[i
] != 0; i
++)
143 if (strpbrk (argv
[i
], " \t"))
145 int len
, trailing_backslash
;
148 len
= strlen (argv
[i
]);
149 trailing_backslash
= 0;
151 /* There is an added complication when an arg with embedded white
152 space ends in a backslash (such as in the case of -iprefix arg
153 passed to cpp). The resulting quoted strings gets misinterpreted
154 by the command interpreter -- it thinks that the ending quote
155 is escaped by the trailing backslash and things get confused.
156 We handle this case by escaping the trailing backslash, provided
157 it was not escaped in the first place. */
159 && argv
[i
][len
-1] == '\\'
160 && argv
[i
][len
-2] != '\\')
162 trailing_backslash
= 1;
163 ++len
; /* to escape the final backslash. */
166 len
+= 2; /* and for the enclosing quotes. */
168 temp
= XNEWVEC (char, len
+ 1);
170 strcpy (temp
+ 1, argv
[i
]);
171 if (trailing_backslash
)
172 temp
[len
- 2] = '\\';
181 return (const char * const *) argv
;
184 static int pex_win32_open_read (struct pex_obj
*, const char *, int);
185 static int pex_win32_open_write (struct pex_obj
*, const char *, int);
186 static long pex_win32_exec_child (struct pex_obj
*, int, const char *,
187 char * const *, int, int, int,
188 const char **, int *);
189 static int pex_win32_close (struct pex_obj
*, int);
190 static int pex_win32_wait (struct pex_obj
*, long, int *,
191 struct pex_time
*, int, const char **, int *);
192 static int pex_win32_pipe (struct pex_obj
*, int *, int);
193 static FILE *pex_win32_fdopenr (struct pex_obj
*, int, int);
195 /* The list of functions we pass to the common routines. */
197 const struct pex_funcs funcs
=
200 pex_win32_open_write
,
201 pex_win32_exec_child
,
209 /* Return a newly initialized pex_obj structure. */
212 pex_init (int flags
, const char *pname
, const char *tempbase
)
214 return pex_init_common (flags
, pname
, tempbase
, &funcs
);
217 /* Open a file for reading. */
220 pex_win32_open_read (struct pex_obj
*obj ATTRIBUTE_UNUSED
, const char *name
,
223 return _open (name
, _O_RDONLY
| (binary
? _O_BINARY
: _O_TEXT
));
226 /* Open a file for writing. */
229 pex_win32_open_write (struct pex_obj
*obj ATTRIBUTE_UNUSED
, const char *name
,
232 /* Note that we can't use O_EXCL here because gcc may have already
233 created the temporary file via make_temp_file. */
235 (_O_WRONLY
| _O_CREAT
| _O_TRUNC
236 | (binary
? _O_BINARY
: _O_TEXT
)),
237 _S_IREAD
| _S_IWRITE
);
243 pex_win32_close (struct pex_obj
*obj ATTRIBUTE_UNUSED
, int fd
)
248 #ifdef USE_MINGW_MSYS
249 static const char *mingw_keys
[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL
};
251 /* Tack the executable on the end of a (possibly slash terminated) buffer
252 and convert everything to \. */
254 tack_on_executable (char *buf
, const char *executable
)
256 char *p
= strchr (buf
, '\0');
257 if (p
> buf
&& (p
[-1] == '\\' || p
[-1] == '/'))
259 backslashify (strcat (buf
, executable
));
263 /* Walk down a registry hierarchy until the end. Return the key. */
265 openkey (HKEY hStart
, const char *keys
[])
268 for (hKey
= hStart
; *keys
; keys
++)
272 res
= RegOpenKey (hTmp
, *keys
, &hKey
);
274 if (hTmp
!= HKEY_LOCAL_MACHINE
)
277 if (res
!= ERROR_SUCCESS
)
283 /* Return the "mingw root" as derived from the mingw uninstall information. */
285 mingw_rootify (const char *executable
)
289 char *namebuf
, *foundbuf
;
293 /* Open the uninstall "directory". */
294 hKey
= openkey (HKEY_LOCAL_MACHINE
, mingw_keys
);
300 /* Need to enumerate all of the keys here looking for one the most recent
302 if (RegQueryInfoKey (hKey
, NULL
, NULL
, NULL
, NULL
, &maxlen
, NULL
, NULL
,
303 NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
308 namebuf
= XNEWVEC (char, ++maxlen
);
309 foundbuf
= XNEWVEC (char, maxlen
);
311 if (!namebuf
|| !foundbuf
)
321 /* Look through all of the keys for one that begins with Minimal GNU...
322 Try to get the latest version by doing a string compare although that
323 string never really works with version number sorting. */
324 for (i
= 0; RegEnumKey (hKey
, i
, namebuf
, maxlen
) == ERROR_SUCCESS
; i
++)
326 int match
= strcasecmp (namebuf
, MINGW_NAME
);
329 if (match
> 0 && strncasecmp (namebuf
, MINGW_NAME
, MINGW_NAME_LEN
) > 0)
331 if (strcasecmp (namebuf
, foundbuf
) > 0)
332 strcpy (foundbuf
, namebuf
);
336 /* If foundbuf is empty, we didn't find anything. Punt. */
344 /* Open the key that we wanted */
345 res
= RegOpenKey (hKey
, foundbuf
, &hTmp
);
349 /* Don't know why this would fail, but you gotta check */
350 if (res
!= ERROR_SUCCESS
)
354 /* Get the length of the value pointed to by InstallLocation */
355 if (RegQueryValueEx (hTmp
, "InstallLocation", 0, NULL
, NULL
,
356 &maxlen
) != ERROR_SUCCESS
|| maxlen
== 0)
362 /* Allocate space for the install location */
363 foundbuf
= XNEWVEC (char, maxlen
+ strlen (executable
));
370 /* Read the install location into the buffer */
371 res
= RegQueryValueEx (hTmp
, "InstallLocation", 0, NULL
, (LPBYTE
) foundbuf
,
374 if (res
!= ERROR_SUCCESS
)
380 /* Concatenate the install location and the executable, turn all slashes
381 to backslashes, and return that. */
382 return tack_on_executable (foundbuf
, executable
);
385 /* Read the install location of msys from it's installation file and
386 rootify the executable based on that. */
388 msys_rootify (const char *executable
)
391 size_t execlen
= strlen (executable
) + 1;
396 buf
= XNEWVEC (char, bufsize
+ execlen
);
399 res
= GetPrivateProfileString ("InstallSettings", "InstallPath", NULL
,
400 buf
, bufsize
, "msys.ini");
403 if (strlen (buf
) < bufsize
)
416 return tack_on_executable (buf
, executable
);
426 spawn_script (const char *executable
, const char * const * argv
)
429 int save_errno
= errno
;
430 int fd
= _open (executable
, _O_RDONLY
);
434 char buf
[MAX_PATH
+ 5];
435 int len
= _read (fd
, buf
, sizeof (buf
) - 1);
441 eol
= strchr (buf
, '\n');
442 if (eol
&& strncmp (buf
, "#!", 2) == 0)
445 const char ** avhere
= (const char **) --argv
;
448 while (*--eol
== '\r' || *eol
== ' ' || *eol
== '\t');
449 for (executable1
= buf
+ 2; *executable1
== ' ' || *executable1
== '\t'; executable1
++)
452 backslashify (executable1
);
453 *avhere
= executable1
;
454 #ifndef USE_MINGW_MSYS
455 executable
= strrchr (executable1
, '\\') + 1;
457 executable
= executable1
;
458 pid
= _spawnvp (_P_NOWAIT
, executable
, argv
);
460 if (strchr (executable1
, '\\') == NULL
)
461 pid
= _spawnvp (_P_NOWAIT
, executable1
, argv
);
462 else if (executable1
[0] != '\\')
463 pid
= _spawnv (_P_NOWAIT
, executable1
, argv
);
466 const char *newex
= mingw_rootify (executable1
);
468 pid
= _spawnv (_P_NOWAIT
, newex
, argv
);
469 if (executable1
!= newex
)
470 free ((char *) newex
);
473 newex
= msys_rootify (executable1
);
474 if (newex
!= executable1
)
477 pid
= _spawnv (_P_NOWAIT
, newex
, argv
);
478 free ((char *) newex
);
491 /* Execute a child. */
494 pex_win32_exec_child (struct pex_obj
*obj ATTRIBUTE_UNUSED
, int flags
,
495 const char *executable
, char * const * argv
,
496 int in
, int out
, int errdes
, const char **errmsg
,
499 int org_in
, org_out
, org_errdes
;
501 const char * const * newargv
;
507 if (in
!= STDIN_FILE_NO
)
509 org_in
= _dup (STDIN_FILE_NO
);
516 if (_dup2 (in
, STDIN_FILE_NO
) < 0)
530 if (out
!= STDOUT_FILE_NO
)
532 org_out
= _dup (STDOUT_FILE_NO
);
539 if (_dup2 (out
, STDOUT_FILE_NO
) < 0)
545 if (_close (out
) < 0)
553 if (errdes
!= STDERR_FILE_NO
554 || (flags
& PEX_STDERR_TO_STDOUT
) != 0)
556 org_errdes
= _dup (STDERR_FILE_NO
);
563 if (_dup2 ((flags
& PEX_STDERR_TO_STDOUT
) != 0 ? STDOUT_FILE_NO
: errdes
,
570 if (errdes
!= STDERR_FILE_NO
)
572 if (_close (errdes
) < 0)
581 newargv
= fix_argv (argv
);
582 pid
= (((flags
& PEX_SEARCH
) != 0 ? _spawnvp
: _spawnv
)
583 (_P_NOWAIT
, executable
, newargv
));
586 pid
= spawn_script (executable
, newargv
);
591 *errmsg
= ((flags
& PEX_SEARCH
) != 0) ? "_spawnvp" : "_spawnv";
594 if (in
!= STDIN_FILE_NO
)
596 if (_dup2 (org_in
, STDIN_FILE_NO
) < 0)
602 if (_close (org_in
) < 0)
610 if (out
!= STDOUT_FILE_NO
)
612 if (_dup2 (org_out
, STDOUT_FILE_NO
) < 0)
618 if (_close (org_out
) < 0)
626 if (errdes
!= STDERR_FILE_NO
627 || (flags
& PEX_STDERR_TO_STDOUT
) != 0)
629 if (_dup2 (org_errdes
, STDERR_FILE_NO
) < 0)
635 if (_close (org_errdes
) < 0)
646 /* Wait for a child process to complete. MS CRTDLL doesn't return
647 enough information in status to decide if the child exited due to a
648 signal or not, rather it simply returns an integer with the exit
649 code of the child; eg., if the child exited with an abort() call
650 and didn't have a handler for SIGABRT, it simply returns with
651 status == 3. We fix the status code to conform to the usual WIF*
652 macros. Note that WIFSIGNALED will never be true under CRTDLL. */
655 pex_win32_wait (struct pex_obj
*obj ATTRIBUTE_UNUSED
, long pid
,
656 int *status
, struct pex_time
*time
, int done ATTRIBUTE_UNUSED
,
657 const char **errmsg
, int *err
)
662 memset (time
, 0, sizeof *time
);
664 /* FIXME: If done is non-zero, we should probably try to kill the
667 if (_cwait (&termstat
, pid
, WAIT_CHILD
) < 0)
674 /* cwait returns the child process exit code in termstat. A value
675 of 3 indicates that the child caught a signal, but not which one.
676 Since only SIGABRT, SIGFPE and SIGINT do anything, we report
682 *status
= ((termstat
& 0xff) << 8);
690 pex_win32_pipe (struct pex_obj
*obj ATTRIBUTE_UNUSED
, int *p
,
693 return _pipe (p
, 256, binary
? _O_BINARY
: _O_TEXT
);
696 /* Get a FILE pointer to read from a file descriptor. */
699 pex_win32_fdopenr (struct pex_obj
*obj ATTRIBUTE_UNUSED
, int fd
,
702 return fdopen (fd
, binary
? "rb" : "r");
709 main (int argc ATTRIBUTE_UNUSED
, char **argv
)
714 printf ("%ld\n", pex_win32_exec_child (NULL
, PEX_SEARCH
, argv
[0], argv
, 0, 1, 2, &errmsg
, &err
));