From 014a8caf46e8c0a25de0df38d859652ad6533f04 Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Thu, 1 Jun 2006 14:57:50 +0000 Subject: [PATCH] merge from gcc --- include/libiberty.h | 17 +++++++ libiberty/ChangeLog | 18 ++++++++ libiberty/functions.texi | 32 ++++++++++---- libiberty/pex-common.c | 26 ++++++++--- libiberty/pex-common.h | 1 + libiberty/pex-djgpp.c | 14 ++++-- libiberty/pex-msdos.c | 6 +-- libiberty/pex-unix.c | 14 ++++-- libiberty/pex-win32.c | 113 ++++++++++++++++++++++++++++++++++++++++++----- libiberty/pexecute.txh | 13 ++++++ 10 files changed, 218 insertions(+), 36 deletions(-) diff --git a/include/libiberty.h b/include/libiberty.h index 6bd318e..1328d3e 100644 --- a/include/libiberty.h +++ b/include/libiberty.h @@ -448,6 +448,23 @@ extern const char *pex_run (struct pex_obj *obj, int flags, const char *outname, const char *errname, int *err); +/* As for pex_run (), but takes an extra parameter to enable the + environment for the child process to be specified. + + ENV 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 VAR=VALUE, + with the exception of the last element which must be + a null pointer. +*/ + +extern const char *pex_run_in_environment (struct pex_obj *obj, int flags, + const char *executable, + char * const *argv, + char * const *env, + const char *outname, + const char *errname, int *err); + /* Return a `FILE' pointer FP for the standard input of the first program in the pipeline; FP is opened for writing. You must have passed `PEX_USE_PIPES' to the `pex_init' call that returned OBJ. diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 192ba30..e2899c0 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,21 @@ +2006-06-01 Mark Shinwell + + * 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-djgpp.c: Add environment parameter to pex_djgpp_exec_child. + (pex_djgpp_exec_child): Pass environment to child process. + * 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. + 2006-05-28 Mark Shinwell * mkstemps.c: Open temporary files in binary mode. diff --git a/libiberty/functions.texi b/libiberty/functions.texi index fa92d70..68c0648 100644 --- a/libiberty/functions.texi +++ b/libiberty/functions.texi @@ -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, 1 on success. @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} to use a randomly chosen name. @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 default mode. Including @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 blocked on the input pipe. @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 @code{errno}. @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. diff --git a/libiberty/pex-common.c b/libiberty/pex-common.c index ebe8c43..3daa638 100644 --- a/libiberty/pex-common.c +++ b/libiberty/pex-common.c @@ -142,12 +142,15 @@ temp_file (struct pex_obj *obj, int flags, char *name) 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, const char *executable, /* 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, const char *executable, 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 * diff --git a/libiberty/pex-common.h b/libiberty/pex-common.h index 8ded138..520f26a 100644 --- a/libiberty/pex-common.h +++ b/libiberty/pex-common.h @@ -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. */ diff --git a/libiberty/pex-djgpp.c b/libiberty/pex-djgpp.c index 17fbf2c..acaa4c4 100644 --- a/libiberty/pex-djgpp.c +++ b/libiberty/pex-djgpp.c @@ -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 ATTRIBUTE_UNUSED, int fd) 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; @@ -196,8 +198,12 @@ pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable, } } - status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv) - (P_WAIT, executable, (char * const *) argv)); + if (env) + status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve) + (P_WAIT, executable, argv, env)); + else + status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv) + (P_WAIT, executable, argv)); if (status == -1) { diff --git a/libiberty/pex-msdos.c b/libiberty/pex-msdos.c index db22337..bcad93d 100644 --- a/libiberty/pex-msdos.c +++ b/libiberty/pex-msdos.c @@ -55,8 +55,8 @@ static int pex_msdos_open (struct pex_obj *, const char *, int); 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, int fd) 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) { diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c index c92a429..91619af 100644 --- a/libiberty/pex-unix.c +++ b/libiberty/pex-unix.c @@ -270,8 +270,8 @@ static void pex_child_error (struct pex_obj *, const char *, const char *, int) 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, const char *executable, /* 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, int flags, const char *executable, 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); diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c index 046f393..4572545 100644 --- a/libiberty/pex-win32.c +++ b/libiberty/pex-win32.c @@ -36,12 +36,14 @@ Boston, MA 02110-1301, USA. */ #include #endif +#include #include #include #include #include #include #include +#include /* mingw32 headers may not define the following. */ @@ -59,6 +61,8 @@ Boston, MA 02110-1301, USA. */ #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 @@ -76,7 +80,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 *, @@ -478,22 +483,96 @@ find_executable (const char *program, BOOL search) return full_executable; } -/* Low-level process creation function. */ +/* Low-level process creation function and helper. */ + +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 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; + 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 = 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 +586,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 +655,20 @@ spawn_script (const char *executable, char *const *argv, 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 +678,7 @@ spawn_script (const char *executable, char *const *argv, 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 +698,7 @@ spawn_script (const char *executable, char *const *argv, 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 +776,10 @@ pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags, /* 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 +880,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv) 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 diff --git a/libiberty/pexecute.txh b/libiberty/pexecute.txh index 7d45576..d85ee59 100644 --- a/libiberty/pexecute.txh +++ b/libiberty/pexecute.txh @@ -130,6 +130,19 @@ value, or to 0 if there is no relevant @code{errno}. @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 -- 2.7.4