diff options
author | Eli Zaretskii <eliz@gnu.org> | 2013-05-03 16:24:24 +0300 |
---|---|---|
committer | Eli Zaretskii <eliz@gnu.org> | 2013-05-03 16:24:24 +0300 |
commit | 82793f85f5fbf1831dcb6a6595ca57c2242e4576 (patch) | |
tree | f5a19cf70b82b6a58164129fec260356a847252d /w32 | |
parent | a66469e003526679b793f2d4623219aab2230b2f (diff) | |
download | gunmake-82793f85f5fbf1831dcb6a6595ca57c2242e4576.tar.gz |
Fix invocation of Windows batch files with whitespace in their names.
w32/subproc/sub_proc.c: Include makeint.h. Remove a private
incompatible prototype of xmalloc.
(batch_file_with_spaces): New function, detects Windows batch
files whose names include whitespace characters.
(process_begin): If exec_name is a batch file with whitespace
characters in its name, pass NULL as the first argument to
CreateProcess. This avoids weird failures due to buggy quoting by
CreateProcess. For the details, see the discussion starting at
http://lists.gnu.org/archive/html/make-w32/2013-04/msg00008.html.
Diffstat (limited to 'w32')
-rw-r--r-- | w32/subproc/sub_proc.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c index 2c36777..68329df 100644 --- a/w32/subproc/sub_proc.c +++ b/w32/subproc/sub_proc.c @@ -23,17 +23,18 @@ this program. If not, see <http://www.gnu.org/licenses/>. */ #else # include <stdint.h> #endif +#include <string.h> #include <process.h> /* for msvc _beginthreadex, _endthreadex */ #include <signal.h> #include <windows.h> +#include "makeint.h" #include "sub_proc.h" #include "proc.h" #include "w32err.h" #include "debug.h" static char *make_command_line(char *shell_name, char *exec_path, char **argv); -extern char *xmalloc (unsigned int); typedef struct sub_process_t { intptr_t sv_stdin[2]; @@ -540,6 +541,26 @@ find_file(const char *exec_path, const char *path_var, return INVALID_HANDLE_VALUE; } +/* + * Return non-zero of FNAME specifies a batch file and its name + * includes embedded whitespace. + */ + +static int +batch_file_with_spaces(const char *fname) +{ + size_t fnlen = strlen(fname); + + return (fnlen > 4 + && (_strnicmp(fname + fnlen - 4, ".bat", 4) == 0 + || _strnicmp(fname + fnlen - 4, ".cmd", 4) == 0) + /* The set of characters in the 2nd arg to strpbrk + should be the same one used by make_command_line + below to decide whether an argv[] element needs + quoting. */ + && strpbrk(fname, " \t") != NULL); +} + /* * Description: Create the child process to be helped @@ -570,6 +591,7 @@ process_begin( STARTUPINFO startInfo; PROCESS_INFORMATION procInfo; char *envblk=NULL; + int pass_null_exec_path = 0; /* * Shell script detection... if the exec_path starts with #! then @@ -651,8 +673,28 @@ process_begin( if (file_not_found) command_line = make_command_line( shell_name, exec_path, argv); - else + else { + /* If exec_fname includes whitespace, CreateProcess + behaves erratically and unreliably, and often fails + if argv[0] also includes whitespace (and thus will + be quoted by make_command_line below). So in that + case, we don't pass exec_fname as the 1st arg to + CreateProcess, but instead replace argv[0] with + exec_fname (to keep its leading directories and + extension as found by find_file), and pass NULL to + CreateProcess as its 1st arg. This works around + the bugs in CreateProcess, which are probably + caused by its passing the command to cmd.exe with + some incorrect quoting. */ + if (!shell_name + && batch_file_with_spaces(exec_fname) + && _stricmp(exec_path, argv[0]) == 0) { + pass_null_exec_path = 1; + free (argv[0]); + argv[0] = xstrdup(exec_fname); + } command_line = make_command_line( shell_name, exec_fname, argv); + } if ( command_line == NULL ) { pproc->last_err = 0; @@ -669,7 +711,7 @@ process_begin( } } - if ((shell_name) || (file_not_found)) { + if (shell_name || file_not_found || pass_null_exec_path) { exec_path = 0; /* Search for the program in %Path% */ } else { exec_path = exec_fname; |