/* Utilities to execute a program in a subprocess (possibly linked by pipes
with other subprocesses), and wait for it. Generic Win32 specialization.
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of the libiberty library.
#include <sys/wait.h>
#endif
+#include <assert.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <errno.h>
+#include <ctype.h>
/* mingw32 headers may not define the following. */
#define MINGW_NAME "Minimalist GNU for Windows"
#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
+extern char *stpcpy (char *dst, const char *src);
+
/* Ensure that the executable pathname uses Win32 backslashes. This
is not necessary on NT, but on W9x, forward slashes causes
failure of spawn* and exec* functions (and probably any function
static int pex_win32_open_read (struct pex_obj *, const char *, int);
static int pex_win32_open_write (struct pex_obj *, const char *, int);
-static long pex_win32_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
+static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
+ char * const *, char * const *,
+ int, int, int, int,
const char **, int *);
static int pex_win32_close (struct pex_obj *, int);
-static int pex_win32_wait (struct pex_obj *, long, int *,
+static int pex_win32_wait (struct pex_obj *, pid_t, int *,
struct pex_time *, int, const char **, int *);
static int pex_win32_pipe (struct pex_obj *, int *, int);
static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
/* The list of functions we pass to the common routines. */
pex_win32_wait,
pex_win32_pipe,
pex_win32_fdopenr,
+ pex_win32_fdopenw,
NULL /* cleanup */
};
cmdline_len += j;
cmdline_len += 3; /* for leading and trailing quotes and space */
}
- cmdline = xmalloc (cmdline_len);
+ cmdline = XNEWVEC (char, cmdline_len);
p = cmdline;
for (i = 0; argv[i]; i++)
{
return cmdline;
}
+/* We'll try the passed filename with all the known standard
+ extensions, and then without extension. We try no extension
+ last so that we don't try to run some random extension-less
+ file that might be hanging around. We try both extension
+ and no extension so that we don't need any fancy logic
+ to determine if a file has extension. */
static const char *const
std_suffixes[] = {
".com",
".exe",
".bat",
".cmd",
- 0
-};
-static const char *const
-no_suffixes[] = {
"",
0
};
const char *const *ext;
const char *p, *q;
size_t proglen = strlen (program);
- int has_extension = !!strchr (program, '.');
int has_slash = (strchr (program, '/') || strchr (program, '\\'));
HANDLE h;
if (*q == ';')
q++;
}
- fe_len = fe_len + 1 + proglen + (has_extension ? 1 : 5);
- full_executable = xmalloc (fe_len);
+ fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
+ full_executable = XNEWVEC (char, fe_len);
p = path;
do
/* At this point, e points to the terminating NUL character for
full_executable. */
- for (ext = has_extension ? no_suffixes : std_suffixes; *ext; ext++)
+ for (ext = std_suffixes; *ext; ext++)
{
/* Remove any current extension. */
*e = '\0';
return full_executable;
}
-/* Low-level process creation function. */
+/* Low-level process creation function and helper. */
-static long
+static int
+env_compare (const void *a_ptr, const void *b_ptr)
+{
+ const char *a;
+ const char *b;
+ unsigned char c1;
+ unsigned char c2;
+
+ a = *(const char **) a_ptr;
+ b = *(const char **) b_ptr;
+
+ /* a and b will be of the form: VAR=VALUE
+ We compare only the variable name part here using a case-insensitive
+ comparison algorithm. It might appear that in fact strcasecmp () can
+ take the place of this whole function, and indeed it could, save for
+ the fact that it would fail in cases such as comparing A1=foo and
+ A=bar (because 1 is less than = in the ASCII character set).
+ (Environment variables containing no numbers would work in such a
+ scenario.) */
+
+ do
+ {
+ c1 = (unsigned char) tolower (*a++);
+ c2 = (unsigned char) tolower (*b++);
+
+ if (c1 == '=')
+ c1 = '\0';
+
+ if (c2 == '=')
+ c2 = '\0';
+ }
+ while (c1 == c2 && c1 != '\0');
+
+ return c1 - c2;
+}
+
+static pid_t
win32_spawn (const char *executable,
BOOL search,
char *const *argv,
+ char *const *env, /* array of strings of the form: VAR=VALUE */
DWORD dwCreationFlags,
LPSTARTUPINFO si,
LPPROCESS_INFORMATION pi)
{
char *full_executable;
char *cmdline;
+ char **env_copy;
+ char *env_block = NULL;
full_executable = NULL;
cmdline = NULL;
+ if (env)
+ {
+ int env_size;
+
+ /* Count the number of environment bindings supplied. */
+ for (env_size = 0; env[env_size]; env_size++)
+ continue;
+
+ /* Assemble an environment block, if required. This consists of
+ VAR=VALUE strings juxtaposed (with one null character between each
+ pair) and an additional null at the end. */
+ if (env_size > 0)
+ {
+ int var;
+ int total_size = 1; /* 1 is for the final null. */
+ char *bufptr;
+
+ /* Windows needs the members of the block to be sorted by variable
+ name. */
+ env_copy = (char **) alloca (sizeof (char *) * env_size);
+ memcpy (env_copy, env, sizeof (char *) * env_size);
+ qsort (env_copy, env_size, sizeof (char *), env_compare);
+
+ for (var = 0; var < env_size; var++)
+ total_size += strlen (env[var]) + 1;
+
+ env_block = XNEWVEC (char, total_size);
+ bufptr = env_block;
+ for (var = 0; var < env_size; var++)
+ bufptr = stpcpy (bufptr, env_copy[var]) + 1;
+
+ *bufptr = '\0';
+ }
+ }
+
full_executable = find_executable (executable, search);
if (!full_executable)
goto error;
/*lpThreadAttributes=*/NULL,
/*bInheritHandles=*/TRUE,
dwCreationFlags,
- /*lpEnvironment=*/NULL,
+ (LPVOID) env_block,
/*lpCurrentDirectory=*/NULL,
si,
pi))
{
+ if (env_block)
+ free (env_block);
+
free (full_executable);
- return -1;
+
+ return (pid_t) -1;
}
/* Clean up. */
CloseHandle (pi->hThread);
free (full_executable);
+ if (env_block)
+ free (env_block);
- return (long) pi->hProcess;
+ return (pid_t) pi->hProcess;
error:
+ if (env_block)
+ free (env_block);
if (cmdline)
free (cmdline);
if (full_executable)
free (full_executable);
- return -1;
+
+ return (pid_t) -1;
}
-static long
+static pid_t
spawn_script (const char *executable, char *const *argv,
+ char* const *env,
DWORD dwCreationFlags,
LPSTARTUPINFO si,
LPPROCESS_INFORMATION pi)
{
- int pid = -1;
+ pid_t pid = (pid_t) -1;
int save_errno = errno;
int fd = _open (executable, _O_RDONLY);
executable = strrchr (executable1, '\\') + 1;
if (!executable)
executable = executable1;
- pid = win32_spawn (executable, TRUE, argv,
+ pid = win32_spawn (executable, TRUE, argv, env,
dwCreationFlags, si, pi);
#else
if (strchr (executable1, '\\') == NULL)
- pid = win32_spawn (executable1, TRUE, argv,
+ pid = win32_spawn (executable1, TRUE, argv, env,
dwCreationFlags, si, pi);
else if (executable1[0] != '\\')
- pid = win32_spawn (executable1, FALSE, argv,
+ pid = win32_spawn (executable1, FALSE, argv, env,
dwCreationFlags, si, pi);
else
{
const char *newex = mingw_rootify (executable1);
*avhere = newex;
- pid = win32_spawn (newex, FALSE, argv,
+ pid = win32_spawn (newex, FALSE, argv, env,
dwCreationFlags, si, pi);
if (executable1 != newex)
free ((char *) newex);
- if (pid < 0)
+ if ((long) pid < 0)
{
newex = msys_rootify (executable1);
if (newex != executable1)
{
*avhere = newex;
- pid = win32_spawn (newex, FALSE, argv,
+ pid = win32_spawn (newex, FALSE, argv, env,
dwCreationFlags, si, pi);
free ((char *) newex);
}
}
}
}
- if (pid < 0)
+ if ((long) pid < 0)
errno = save_errno;
return pid;
}
/* Execute a child. */
-static long
+static pid_t
pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
const char *executable, char * const * argv,
- int in, int out, int errdes, const char **errmsg,
+ char* const* env,
+ int in, int out, int errdes,
+ int toclose ATTRIBUTE_UNUSED,
+ const char **errmsg,
int *err)
{
- long pid;
+ pid_t pid;
HANDLE stdin_handle;
HANDLE stdout_handle;
HANDLE stderr_handle;
/* Create the child process. */
pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
- argv, dwCreationFlags, &si, &pi);
- if (pid == -1)
- pid = spawn_script (executable, argv, dwCreationFlags, &si, &pi);
- if (pid == -1)
+ argv, env, dwCreationFlags, &si, &pi);
+ if (pid == (pid_t) -1)
+ pid = spawn_script (executable, argv, env, dwCreationFlags,
+ &si, &pi);
+ if (pid == (pid_t) -1)
{
*err = ENOENT;
*errmsg = "CreateProcess";
macros. Note that WIFSIGNALED will never be true under CRTDLL. */
static int
-pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid,
+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)
{
return fdopen (fd, binary ? "rb" : "r");
}
+static FILE *
+pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
+ return NULL;
+ return fdopen (fd, binary ? "wb" : "w");
+}
+
#ifdef MAIN
#include <stdio.h>
char const *errmsg;
int err;
argv++;
- printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, 0, 1, 2, &errmsg, &err));
+ printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
exit (0);
}
#endif