This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, libiberty] Improvements to pex functionality
- From: Mark Shinwell <shinwell at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 10 May 2006 09:41:37 +0100
- Subject: [PATCH, libiberty] Improvements to pex functionality
Hi,
Let me introduce myself as a new employee at CodeSourcery.
We have been working on patching the ELF prelinker so that it will compile
for a mingw32 host. (It is intended that this work will end up in a public
repository.)
In order to get this to work I have added a new libiberty function
pex_run_in_environment () that enables the specification of the environment
in which a child process is run. I've implemented this in pex-{win32,unix}.c
but I'm afraid I'm not sure what to do about the DOS ones...
Patch attached together with ChangeLog entries for toplevel and libiberty/
directories. Tested on x86_64 Linux and cross build to mingw32.
Mark
--
2006-05-10 Mark Shinwell <shinwell@codesourcery.com>
* include/libiberty.h: Declare pex_run_in_environment.
--
2006-05-10 Mark Shinwell <shinwell@codesourcery.com>
* pex-common.c: New function pex_run_in_environment.
* pex-common.h: Add environment parameter to exec_child.
* pex-msdos.c: Add environment parameter to pex_msdos_exec_child.
* pex-one.c: Add environment parameter to pex_djgpp_exec_child.
* pex-unix.c: Add environment parameter to pex_unix_exec_child.
(pex_unix_exec_child): Pass environment to child process.
* pex-win32.c: Add environment parameter to pex_win32_exec_child.
New function env_compare for comparing VAR=VALUE pairs.
(win32_spawn): Assemble environment block and pass to CreateProcess.
(spawn_script): Pass environment through to win32_spawn.
(pex_win32_exec_child): Pass environment through to spawn_script and
win32_spawn.
* functions.texi: Regenerate.
* pexecute.txh: Document pex_run_in_environment.
Index: pex-common.c
===================================================================
--- pex-common.c (revision 113631)
+++ pex-common.c (working copy)
@@ -142,12 +142,15 @@ temp_file (struct pex_obj *obj, int flag
return name;
}
-/* Run a program. */
+
+/* As for pex_run (), but permits the environment for the child process
+ to be specified. */
const char *
-pex_run (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, const char *orig_outname, const char *errname,
- int *err)
+pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, char * const * env,
+ const char *orig_outname, const char *errname,
+ int *err)
{
const char *errmsg;
int in, out, errdes;
@@ -296,8 +299,8 @@ pex_run (struct pex_obj *obj, int flags,
/* Run the program. */
- pid = obj->funcs->exec_child (obj, flags, executable, argv, in, out, errdes,
- &errmsg, err);
+ pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
+ in, out, errdes, &errmsg, err);
if (pid < 0)
goto error_exit;
@@ -319,6 +322,17 @@ pex_run (struct pex_obj *obj, int flags,
return errmsg;
}
+/* Run a program. */
+
+const char *
+pex_run (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, const char *orig_outname, const char *errname,
+ int *err)
+{
+ return pex_run_in_environment (obj, flags, executable, argv, NULL,
+ orig_outname, errname, err);
+}
+
/* Return a FILE pointer for a temporary file to fill with input for
the pipeline. */
FILE *
Index: pex-common.h
===================================================================
--- pex-common.h (revision 113631)
+++ pex-common.h (working copy)
@@ -104,6 +104,7 @@ struct pex_funcs
error and set *ERRMSG and *ERR. */
long (*exec_child) (struct pex_obj *, int /* flags */,
const char */* executable */, char * const * /* argv */,
+ char * const * /* env */,
int /* in */, int /* out */, int /* errdes */,
const char **/* errmsg */, int */* err */);
/* Close a descriptor. Return 0 on success, -1 on error. */
Index: pex-djgpp.c
===================================================================
--- pex-djgpp.c (revision 113631)
+++ pex-djgpp.c (working copy)
@@ -45,7 +45,8 @@ extern int errno;
static int pex_djgpp_open_read (struct pex_obj *, const char *, int);
static int pex_djgpp_open_write (struct pex_obj *, const char *, int);
static long pex_djgpp_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
+ char * const *, char * const *,
+ int, int, int,
const char **, int *);
static int pex_djgpp_close (struct pex_obj *, int);
static int pex_djgpp_wait (struct pex_obj *, long, int *, struct pex_time *,
@@ -111,7 +112,8 @@ pex_djgpp_close (struct pex_obj *obj ATT
static long
pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, int in, int out, int errdes,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes,
const char **errmsg, int *err)
{
int org_in, org_out, org_errdes;
Index: functions.texi
===================================================================
--- functions.texi (revision 113631)
+++ functions.texi (working copy)
@@ -668,14 +668,14 @@ reading and writing.
@end deftypefn
-@c pexecute.txh:231
+@c pexecute.txh:244
@deftypefn Extension void pex_free (struct pex_obj @var{obj})
Clean up and free all data associated with @var{obj}.
@end deftypefn
-@c pexecute.txh:206
+@c pexecute.txh:219
@deftypefn Extension int pex_get_status (struct pex_obj *@var{obj}, int @var{count}, int *@var{vector})
Returns the exit status of all programs run using @var{obj}.
@@ -685,7 +685,7 @@ to @code{pex_run}. Returns 0 on error,
@end deftypefn
-@c pexecute.txh:215
+@c pexecute.txh:228
@deftypefn Extension int pex_get_times (struct pex_obj *@var{obj}, int @var{count}, struct pex_time *@var{vector})
Returns the process execution times of all programs run using
@@ -734,7 +734,7 @@ temporary files; it may be @code{NULL} t
@end deftypefn
-@c pexecute.txh:133
+@c pexecute.txh:146
@deftypefn Extension {FILE *} pex_input_file (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{in_name})
Return a stream for a temporary file to pass to the first program in
@@ -752,7 +752,7 @@ binary mode; otherwise, open it in the d
@code{PEX_BINARY_OUTPUT} in @var{flags} has no effect on Unix.
@end deftypefn
-@c pexecute.txh:150
+@c pexecute.txh:163
@deftypefn Extension {FILE *} pex_input_pipe (struct pex_obj *@var{obj}, int @var{binary})
Return a stream @var{fp} for a pipe connected to the standard input of
@@ -797,7 +797,7 @@ the output pipe is you, but you are bloc
@end deftypefn
-@c pexecute.txh:237
+@c pexecute.txh:250
@deftypefn Extension {const char *} pex_one (int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{pname}, const char *@var{outname}, const char *@var{errname}, int *@var{status}, int *@var{err})
An interface to permit the easy execution of a
@@ -810,7 +810,7 @@ be set to the exit status of the program
@end deftypefn
-@c pexecute.txh:194
+@c pexecute.txh:207
@deftypefn Extension {FILE *} pex_read_output (struct pex_obj *@var{obj}, int @var{binary})
Returns a @code{FILE} pointer which may be used to read the standard
@@ -924,7 +924,21 @@ value, or to 0 if there is no relevant @
@end deftypefn
-@c pexecute.txh:249
+@c pexecute.txh:133
+@deftypefn Extension {const char *} pex_run_in_environment (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, char * const *@var{env}, int @var{env_size}, const char *@var{outname}, const char *@var{errname}, int *@var{err})
+
+Execute one program in a pipeline, permitting the environment for the
+program to be specified. Behaviour and parameters not listed below are
+as for @code{pex_run}.
+
+@var{env} is the environment for the child process, specified as an array of
+character pointers. Each element of the array should point to a string of the
+form @code{VAR=VALUE}, with the exception of the last element that must be
+@code{NULL}.
+
+@end deftypefn
+
+@c pexecute.txh:262
@deftypefn Extension int pexecute (const char *@var{program}, char * const *@var{argv}, const char *@var{this_pname}, const char *@var{temp_base}, char **@var{errmsg_fmt}, char **@var{errmsg_arg}, int flags)
This is the old interface to execute one or more programs. It is
@@ -952,7 +966,7 @@ name is unset/removed.
@end deftypefn
-@c pexecute.txh:257
+@c pexecute.txh:270
@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
Another part of the old execution interface.
Index: pexecute.txh
===================================================================
--- pexecute.txh (revision 113631)
+++ pexecute.txh (working copy)
@@ -130,6 +130,19 @@ value, or to 0 if there is no relevant @
@end deftypefn
+@deftypefn Extension {const char *} pex_run_in_environment (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, char * const *@var{env}, int @var{env_size}, const char *@var{outname}, const char *@var{errname}, int *@var{err})
+
+Execute one program in a pipeline, permitting the environment for the
+program to be specified. Behaviour and parameters not listed below are
+as for @code{pex_run}.
+
+@var{env} is the environment for the child process, specified as an array of
+character pointers. Each element of the array should point to a string of the
+form @code{VAR=VALUE}, with the exception of the last element that must be
+@code{NULL}.
+
+@end deftypefn
+
@deftypefn Extension {FILE *} pex_input_file (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{in_name})
Return a stream for a temporary file to pass to the first program in
Index: pex-unix.c
===================================================================
--- pex-unix.c (revision 113631)
+++ pex-unix.c (working copy)
@@ -270,8 +270,8 @@ static void pex_child_error (struct pex_
static int pex_unix_open_read (struct pex_obj *, const char *, int);
static int pex_unix_open_write (struct pex_obj *, const char *, int);
static long pex_unix_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
- const char **, int *);
+ char * const *, char * const *,
+ int, int, int, const char **, int *);
static int pex_unix_close (struct pex_obj *, int);
static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *,
int, const char **, int *);
@@ -352,12 +352,16 @@ pex_child_error (struct pex_obj *obj, co
/* Execute a child. */
+extern char **environ;
+
static long
pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, int in, int out, int errdes,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes,
const char **errmsg, int *err)
{
pid_t pid;
+
/* We declare these to be volatile to avoid warnings from gcc about
them being clobbered by vfork. */
volatile int sleep_interval;
@@ -409,6 +413,10 @@ pex_unix_exec_child (struct pex_obj *obj
if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
pex_child_error (obj, executable, "dup2", errno);
}
+
+ if (env)
+ environ = env;
+
if ((flags & PEX_SEARCH) != 0)
{
execvp (executable, argv);
Index: pex-msdos.c
===================================================================
--- pex-msdos.c (revision 113631)
+++ pex-msdos.c (working copy)
@@ -55,8 +55,8 @@ static int pex_msdos_open (struct pex_ob
static int pex_msdos_open (struct pex_obj *, const char *, int);
static int pex_msdos_fdindex (struct pex_msdos *, int);
static long pex_msdos_exec_child (struct pex_obj *, int, const char *,
- char * const *, int, int, int,
- const char **, int *);
+ char * const *, char * const *,
+ int, int, int, const char **, int *);
static int pex_msdos_close (struct pex_obj *, int);
static int pex_msdos_wait (struct pex_obj *, long, int *, struct pex_time *,
int, const char **, int *);
@@ -153,7 +153,7 @@ pex_msdos_close (struct pex_obj *obj, in
static long
pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
- char * const * argv, int in, int out,
+ char * const * argv, char * const * env, int in, int out,
int errdes ATTRIBUTE_UNUSED, const char **errmsg,
int *err)
{
Index: pex-win32.c
===================================================================
--- pex-win32.c (revision 113631)
+++ pex-win32.c (working copy)
@@ -36,6 +36,7 @@ Boston, MA 02110-1301, USA. */
#include <sys/wait.h>
#endif
+#include <assert.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>
@@ -76,7 +77,8 @@ backslashify (char *s)
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,
+ char * const *, char * const *,
+ 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 *,
@@ -480,20 +482,100 @@ find_executable (const char *program, BO
/* Low-level process creation function. */
+static int
+env_compare (const void *a_ptr, const void *b_ptr)
+{
+ const char *a_equals;
+ const char *b_equals;
+ char *a_var;
+ char *b_var;
+ int a_len;
+ int b_len;
+ const char **a;
+ const char **b;
+
+ 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 function. 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.) */
+
+ a_equals = strchr (a, '=');
+ b_equals = strchr (b, '=');
+
+ assert (a_equals);
+ assert (b_equals);
+
+ a_len = (int) ((size_t) a_equals) - ((size_t) a);
+ b_len = (int) ((size_t) b_equals) - ((size_t) b);
+
+ a_var = alloca (a_len + 1);
+ b_var = alloca (b_len + 1);
+
+ strncpy (a_var, a, a_len);
+ strncpy (b_var, b, b_len);
+ a_var[a_len] = '\0';
+ b_var[b_len] = '\0';
+
+ return strcasecmp (a_var, b_var);
+}
+
static long
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;
+ int var;
+ int env_size;
+ char **env_copy;
+ char *env_block = NULL;
full_executable = NULL;
cmdline = NULL;
+ assert (env);
+
+ /* 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 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 = 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 = malloc (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;
@@ -507,31 +589,41 @@ win32_spawn (const char *executable,
/*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;
}
/* Clean up. */
CloseHandle (pi->hThread);
free (full_executable);
+ if (env_block)
+ free (env_block);
return (long) pi->hProcess;
error:
+ if (env_block)
+ free (env_block);
if (cmdline)
free (cmdline);
if (full_executable)
free (full_executable);
+
return -1;
}
static long
spawn_script (const char *executable, char *const *argv,
+ char* const *env,
DWORD dwCreationFlags,
LPSTARTUPINFO si,
LPPROCESS_INFORMATION pi)
@@ -566,20 +658,20 @@ spawn_script (const char *executable, ch
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);
@@ -589,7 +681,7 @@ spawn_script (const char *executable, ch
if (newex != executable1)
{
*avhere = newex;
- pid = win32_spawn (newex, FALSE, argv,
+ pid = win32_spawn (newex, FALSE, argv, env,
dwCreationFlags, si, pi);
free ((char *) newex);
}
@@ -609,6 +701,7 @@ spawn_script (const char *executable, ch
static long
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, const char **errmsg,
int *err)
{
@@ -686,9 +779,10 @@ pex_win32_exec_child (struct pex_obj *ob
/* Create the child process. */
pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
- argv, dwCreationFlags, &si, &pi);
+ argv, env, dwCreationFlags, &si, &pi);
if (pid == -1)
- pid = spawn_script (executable, argv, dwCreationFlags, &si, &pi);
+ pid = spawn_script (executable, argv, env, dwCreationFlags,
+ &si, &pi);
if (pid == -1)
{
*err = ENOENT;
@@ -789,7 +883,7 @@ main (int argc ATTRIBUTE_UNUSED, char **
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", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
exit (0);
}
#endif