diff options
author | Mark Mitchell <mark@codesourcery.com> | 2006-03-31 01:17:06 +0000 |
---|---|---|
committer | Mark Mitchell <mark@codesourcery.com> | 2006-03-31 01:17:06 +0000 |
commit | 0ad151e1126c675e6f1ddd877c154011e862f19f (patch) | |
tree | 6667bc7f6dbbc59ad4188025f00b9bc7d76496be | |
parent | 075ca7ec4e94f3691541141551269e7a98f912b5 (diff) | |
download | gdb-0ad151e1126c675e6f1ddd877c154011e862f19f.tar.gz |
* libiberty/configure.ac: Add cygpath for mingw hosts.
* libiberty.configure: Rebuilt.
* libiberty/Makefile.in: Add cygpath.
* libiberty/cygpath.c: New.
* include/libiberty.h (pex_write_input): New declaration.
* libiberty/pex-common.c (pex_write_input): New function.
* libiberty/pexecute.txh (pex_write_input): Document it.
* libiberty/pex-common.h (struct pex_funcs): New function ptr fdopenw.
* libiberty/pex-unix.c (pex_unix_fdopenw): New function.
(funcs): List it as our fdopenw function.
* libiberty/pex-win32.c (pex_win32_fdopenw): New function.
(funcs): List it as our fdopenw function.
* libiberty/pex-djgpp.c (funcs): Leave fdopenw null.
* libiberty/pex-msdos (funcs): Same.
* libiberty/functions.texi: Regenerated.
* libiberty/pex-common.h (struct pex_obj): Doc fixes.
* libiberty/functions.texi: Regenerate.
-rw-r--r-- | ChangeLog.csl | 26 | ||||
-rw-r--r-- | include/libiberty.h | 27 | ||||
-rw-r--r-- | libiberty/Makefile.in | 10 | ||||
-rwxr-xr-x | libiberty/configure | 14 | ||||
-rw-r--r-- | libiberty/configure.ac | 7 | ||||
-rw-r--r-- | libiberty/cygpath.c | 270 | ||||
-rw-r--r-- | libiberty/functions.texi | 67 | ||||
-rw-r--r-- | libiberty/pex-common.c | 50 | ||||
-rw-r--r-- | libiberty/pex-common.h | 5 | ||||
-rw-r--r-- | libiberty/pex-djgpp.c | 1 | ||||
-rw-r--r-- | libiberty/pex-msdos.c | 1 | ||||
-rw-r--r-- | libiberty/pex-unix.c | 11 | ||||
-rw-r--r-- | libiberty/pex-win32.c | 14 | ||||
-rw-r--r-- | libiberty/pexecute.txh | 29 |
14 files changed, 521 insertions, 11 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl index 739f40f07c4..b139379d734 100644 --- a/ChangeLog.csl +++ b/ChangeLog.csl @@ -1,3 +1,29 @@ +2006-03-30 Mark Mitchell <mark@codesourcery.com> + + * libiberty/configure.ac: Add cygpath for mingw hosts. + * libiberty.configure: Rebuilt. + * libiberty/Makefile.in: Add cygpath. + * libiberty/cygpath.c: New. + +2006-03-30 Jim Blandy <jimb@codesourcery.com> + + * include/libiberty.h (pex_write_input): New declaration. + + * libiberty/pex-common.c (pex_write_input): New function. + * libiberty/pexecute.txh (pex_write_input): Document it. + * libiberty/pex-common.h (struct pex_funcs): New function ptr fdopenw. + * libiberty/pex-unix.c (pex_unix_fdopenw): New function. + (funcs): List it as our fdopenw function. + * libiberty/pex-win32.c (pex_win32_fdopenw): New function. + (funcs): List it as our fdopenw function. + * libiberty/pex-djgpp.c (funcs): Leave fdopenw null. + * libiberty/pex-msdos (funcs): Same. + * libiberty/functions.texi: Regenerated. + + * libiberty/pex-common.h (struct pex_obj): Doc fixes. + + * libiberty/functions.texi: Regenerate. + 2006-03-27 Mark Mitchell <mark@codesourcery.com> * libiberty/pex-win32.c (pex_win32_exec_child): Close stdout/stderr diff --git a/include/libiberty.h b/include/libiberty.h index c264cb2ab0e..6fdc6e9d0c8 100644 --- a/include/libiberty.h +++ b/include/libiberty.h @@ -448,6 +448,33 @@ extern const char *pex_run (struct pex_obj *obj, int flags, 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. + You must close FP yourself with `fclose' to indicate that the + pipeline's input is complete. + + The file descriptor underlying FP is marked not to be inherited by + child processes. + + This call is not supported on systems which do not support pipes; + it returns with an error. (We could implement it by writing a + temporary file, but then you would need to write all your data and + close FP before your first call to `pex_run' -- and that wouldn't + work on systems that do support pipes: the pipe would fill up, and + you would block. So there isn't any easy way to conceal the + differences between the two types of systems.) + + If you call both `pex_write_input' and `pex_read_output', be + careful to avoid deadlock. If the output pipe fills up, so that + each program in the pipeline is waiting for the next to read more + data, and you fill the input pipe by writing more data to FP, then + there is no way to make progress: the only process that could read + data from the output pipe is you, but you are blocked on the input + pipe. */ + +extern FILE *pex_write_input (struct pex_obj *obj, int binary); + /* Read the standard output of the last program to be executed. pex_run can not be called after this. BINARY should be non-zero if the file should be opened in binary mode; this is ignored on Unix. diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in index dcd5ebd86d1..77848ad5928 100644 --- a/libiberty/Makefile.in +++ b/libiberty/Makefile.in @@ -129,7 +129,7 @@ COMPILE.c = $(CC) -c @DEFS@ $(LIBCFLAGS) -I. -I$(INCDIR) $(HDEFINES) @ac_libiber CFILES = alloca.c argv.c asprintf.c atexit.c \ basename.c bcmp.c bcopy.c bsearch.c bzero.c \ calloc.c choose-temp.c clock.c concat.c cp-demangle.c \ - cp-demint.c cplus-dem.c \ + cp-demint.c cplus-dem.c cygpath.c \ dyn-string.c \ fdmatch.c ffs.c fibheap.c floatformat.c fnmatch.c \ fopen_unlocked.c \ @@ -186,7 +186,7 @@ REQUIRED_OFILES = ./regex.o ./cplus-dem.o ./cp-demangle.o ./md5.o \ # maint-missing" and "make check". CONFIGURED_OFILES = ./asprintf.o ./atexit.o \ ./basename.o ./bcmp.o ./bcopy.o ./bsearch.o ./bzero.o \ - ./calloc.o ./clock.o ./copysign.o \ + ./calloc.o ./clock.o ./copysign.o ./cygpath.o \ ./_doprnt.o \ ./ffs.o \ ./getcwd.o ./getpagesize.o ./gettimeofday.o \ @@ -548,6 +548,12 @@ $(CONFIGURED_OFILES): stamp-picdir else true; fi $(COMPILE.c) $(srcdir)/cplus-dem.c $(OUTPUT_OPTION) +./cygpath.o: $(srcdir)/cygpath.c $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/cygpath.c -o pic/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/cygpath.c $(OUTPUT_OPTION) + ./dyn-string.o: $(srcdir)/dyn-string.c config.h $(INCDIR)/ansidecl.h \ $(INCDIR)/dyn-string.h $(INCDIR)/libiberty.h if [ x"$(PICFLAG)" != x ]; then \ diff --git a/libiberty/configure b/libiberty/configure index 59633d520fc..8a866d89f89 100755 --- a/libiberty/configure +++ b/libiberty/configure @@ -8205,6 +8205,20 @@ case "${host}" in esac +# On MinGW, add support for Cygwin paths. +case "${host}" in + *-*-mingw*) + case $LIBOBJS in + "cygpath.$ac_objext" | \ + *" cygpath.$ac_objext" | \ + "cygpath.$ac_objext "* | \ + *" cygpath.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS cygpath.$ac_objext" ;; +esac + + ;; +esac + if test x$gcc_no_link = xyes; then if test "x${ac_cv_func_mmap_fixed_mapped+set}" != xset; then ac_cv_func_mmap_fixed_mapped=no diff --git a/libiberty/configure.ac b/libiberty/configure.ac index a57685a14ec..9c1eed9bbed 100644 --- a/libiberty/configure.ac +++ b/libiberty/configure.ac @@ -618,6 +618,13 @@ case "${host}" in esac AC_SUBST(pexecute) +# On MinGW, add support for Cygwin paths. +case "${host}" in + *-*-mingw*) + AC_LIBOBJ([cygpath]) + ;; +esac + libiberty_AC_FUNC_STRNCMP # Install a library built with a cross compiler in $(tooldir) rather diff --git a/libiberty/cygpath.c b/libiberty/cygpath.c new file mode 100644 index 00000000000..2e7b4c9c968 --- /dev/null +++ b/libiberty/cygpath.c @@ -0,0 +1,270 @@ +/* Support Cygwin paths under MinGW. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by CodeSourcery. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or modify it +under the terms of the GNU Library General Public License as published +by the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If not, write +to the Free Software Foundation, Inc., 51 Franklin Street - Fifth +Floor, Boston, MA 02110-1301, USA. */ + +#include <windows.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <io.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include "libiberty.h" + +/* If non-zero, we have attempted to use cygpath. CYGPATH_PEX may + still be NULL, if cygpath is unavailable. */ +static int cygpath_initialized; + +/* If non-NULL, an instance of cygpath connected via a pipe. */ +static struct pex_obj *cygpath_pex; + +/* The input to cygpath. */ +static FILE *cygpath_in; + +/* The output from cygpath. */ +static FILE *cygpath_out; + +/* CYG_PATH is a pointer to a Cygwin path. This function converts the + Cygwin path to a Windows path, storing the result in + WIN32_PATH. Returns true if the conversion was successful; false + otherwise. */ +static bool +cygpath (const char *cyg_path, char win32_path[MAX_PATH + 1]) +{ + bool ok; + + if (!cygpath_initialized) + { + const char *argv[] = { "cygpath", "-w", "-f", "-", NULL }; + const char *cygpath_path; + int err; + + /* If we are unable to invoke cygpath, we do not want to try + again. So, we set the initialized flag at this point; if + errors occur during the invocation, it will remain set. */ + cygpath_initialized = 1; + /* Check to see if the user wants cygpath support. */ + cygpath_path = getenv ("CYGPATH"); + if (!cygpath_path) + /* The user doesn't need to support Cygwin paths. */ + goto error; + /* If the environment variable is set to a non-empty string, use + that string as the path to cygpath. */ + if (cygpath_path[0] != '\0') + argv[0] = cygpath_path; + /* Create the pex object. */ + cygpath_pex = pex_init (PEX_SEARCH | PEX_USE_PIPES, + "cygpath", NULL); + if (!cygpath_pex) + goto error; + /* Get the FILE we will use to write to the child. */ + cygpath_in = pex_write_input (cygpath_pex, /*binary=*/0); + if (!cygpath_in) + goto error; + /* Start the child process. */ + if (pex_run (cygpath_pex, PEX_SEARCH | PEX_USE_PIPES, + argv[0], (char**) argv, + NULL, NULL, + &err) != NULL) + goto error; + /* Get the FILE we will use to read from the child. */ + cygpath_out = pex_read_output (cygpath_pex, /*binary=*/1); + if (!cygpath_out) + goto error; + } + else if (!cygpath_pex) + /* We previously tried to use cygpath, but something went wrong. */ + return false; + + /* Write CYG_PATH to the child, on a line by itself. */ + if (fprintf (cygpath_in, "%s\n", cyg_path) < 0) + goto error; + /* Flush the output. (We cannot set the stream into line-buffered + mode with setvbuf because Windows treats _IOLBF as a synonym for + _IOFBF.) */ + fflush (cygpath_in); + /* Read the output. */ + ok = true; + while (1) + { + size_t pathlen; + if (!fgets (win32_path, MAX_PATH, cygpath_out)) + goto error; + pathlen = strlen (win32_path); + if (pathlen == 0 && ok) + /* This isn't a well-formed response from cygpath. */ + goto error; + if (win32_path[pathlen - 1] == '\n') + { + win32_path[pathlen - 1] = '\0'; + break; + } + /* We didn't reach the end of the line. There's no point in + trying to use this output, since we know the length of + paths are limited to MAX_PATH characters, but we read the + entire line so that we are still in sync with + cygpath. */ + ok = false; + } + + return ok; + + error: + + /* Free resources. */ + if (cygpath_out) + { + fclose (cygpath_out); + cygpath_out = NULL; + } + if (cygpath_in) + { + fclose (cygpath_in); + cygpath_in = NULL; + } + if (cygpath_pex) + { + pex_free (cygpath_pex); + cygpath_pex = NULL; + } + + return false; +} + +/* Returns the handle for the MVCRT DLL, or NULL if it is not + available. */ +static HANDLE +msvcrt_dll (void) +{ + static HANDLE dll = INVALID_HANDLE_VALUE; + + /* After we call LoadLibrary, DLL will be either a valid handle or + NULL, so this check ensures that we only try to load the library + once. */ + if (dll == INVALID_HANDLE_VALUE) + dll = LoadLibrary ("msvcrt.dll"); + + return dll; +} + +/* Call the underlying MSVCRT fopen with PATH and MODE, and return + what it returns. */ +static FILE * +msvcrt_fopen (const char *path, const char *mode) +{ + typedef FILE *(fopen_type)(const char *path, + const char *mode); + + static fopen_type *f = NULL; + + /* Get the address of "fopen". */ + if (!f) + { + HANDLE dll = msvcrt_dll (); + if (!dll) + { + errno = ENOSYS; + return NULL; + } + f = (fopen_type *) GetProcAddress (dll, "fopen"); + if (!f) + { + errno = ENOSYS; + return NULL; + } + } + + /* Call fopen. */ + return (*f)(path, mode); +} + +FILE * +fopen (const char *path, const char *mode) +{ + FILE *f; + char win32_path[MAX_PATH + 1]; + + /* Assume PATH is a Windows path. */ + f = msvcrt_fopen (path, mode); + if (f || errno != ENOENT) + return f; + /* Perhaps it is a Cygwin path? */ + if (cygpath (path, win32_path)) + f = msvcrt_fopen (win32_path, mode); + return f; +} + +int +open (const char *path, int oflag, ...) +{ + int fd; + char win32_path[MAX_PATH + 1]; + int pmode = 0; + + if ((oflag & _O_CREAT)) + { + va_list ap; + va_start (ap, oflag); + pmode = va_arg (ap, int); + va_end (ap); + } + + /* Assume PATH is a Windows path. */ + fd = _open (path, oflag, pmode); + if (fd != -1 || errno != ENOENT) + return fd; + /* Perhaps it is a Cygwin path? */ + if (cygpath (path, win32_path)) + fd = _open (win32_path, oflag, pmode); + return fd; +} + +int +stat (const char *path, struct stat *buffer) +{ + int r; + char win32_path[MAX_PATH + 1]; + + /* Assume PATH is a Windows path. */ + r = _stat (path, (struct _stat *) buffer); + if (r != -1 || errno != ENOENT) + return r; + /* Perhaps it is a Cygwin path? */ + if (cygpath (path, win32_path)) + r = _stat (win32_path, (struct _stat *) buffer); + return r; +} + +int +access (const char *path, int mode) +{ + int r; + char win32_path[MAX_PATH + 1]; + + /* Assume PATH is a Windows path. */ + r = _access (path, mode); + if (r != -1 || errno != ENOENT) + return r; + /* Perhaps it is a Cygwin path? */ + if (cygpath (path, win32_path)) + r = _access (win32_path, mode); + return r; +} diff --git a/libiberty/functions.texi b/libiberty/functions.texi index a09e2075fe1..af03e93f3a9 100644 --- a/libiberty/functions.texi +++ b/libiberty/functions.texi @@ -234,6 +234,26 @@ operating system to free the memory when the program exits. @end deftypefn +@c argv.c:293 +@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp}) + +The @var{argcp} and @code{argvp} arguments are pointers to the usual +@code{argc} and @code{argv} arguments to @code{main}. This function +looks for arguments that begin with the character @samp{@@}. Any such +arguments are interpreted as ``response files''. The contents of the +response file are interpreted as additional command line options. In +particular, the file is separated into whitespace-separated strings; +each such string is taken as a command-line option. The new options +are inserted in place of the option naming the response file, and +@code{*argcp} and @code{*argvp} will be updated. If the value of +@code{*argvp} is modified by this function, then the new value has +been dynamically allocated and can be deallocated by the caller with +@code{freeargv}. However, most callers will simply call +@code{expandargv} near the beginning of @code{main} and allow the +operating system to free the memory when the program exits. + +@end deftypefn + @c fdmatch.c:23 @deftypefn Extension int fdmatch (int @var{fd1}, int @var{fd2}) @@ -668,14 +688,14 @@ reading and writing. @end deftypefn -@c pexecute.txh:169 +@c pexecute.txh:198 @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:144 +@c pexecute.txh:173 @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 +705,7 @@ to @code{pex_run}. Returns 0 on error, 1 on success. @end deftypefn -@c pexecute.txh:153 +@c pexecute.txh:182 @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 @@ -702,7 +722,7 @@ process times, all the fields will be set to @code{0}. @end deftypefn -@c pexecute.txh:1 +@c pexecute.txh:2 @deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase}) Prepare to execute one or more programs, with standard output of each @@ -734,7 +754,7 @@ temporary files; it may be @code{NULL} to use a randomly chosen name. @end deftypefn -@c pexecute.txh:175 +@c pexecute.txh:204 @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 @@ -747,7 +767,7 @@ be set to the exit status of the program. @end deftypefn -@c pexecute.txh:132 +@c pexecute.txh:161 @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 @@ -760,7 +780,7 @@ it will be closed by @code{pex_free}. @end deftypefn -@c pexecute.txh:32 +@c pexecute.txh:33 @deftypefn Extension {const char *} pex_run (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{outname}, const char *@var{errname}, int *@var{err}) Execute one program in a pipeline. On success this returns @@ -861,7 +881,36 @@ value, or to 0 if there is no relevant @code{errno}. @end deftypefn -@c pexecute.txh:187 +@c pexecute.txh:133 +@deftypefn Extension {FILE *} pex_write_input (struct pex_obj *@var{obj}, int @var{binary}) + +Return a @code{FILE} pointer @var{fp} for the standard input of the +first program in the pipeline; @var{fp} is opened for writing. You +must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call that +returned @var{obj}. You must close @var{fp} yourself with +@code{fclose} to indicate that the pipeline's input is complete. + +The file descriptor underlying @var{fp} is marked not to be inherited +by child processes. + +This call is not supported on systems which do not support pipes; it +returns with an error. (We could implement it by writing a temporary +file, but then you would need to write all your data and close +@var{fp} before your first call to @code{pex_run} --- and that +wouldn't work on systems that do support pipes: the pipe would fill +up, and you would block. So there isn't any easy way to conceal the +differences between the two types of systems.) + +If you call both @code{pex_write_input} and @code{pex_read_output}, be +careful to avoid deadlock. If the output pipe fills up, so that each +program in the pipeline is waiting for the next to read more data, and +you fill the input pipe by writing more data to @var{fp}, then there +is no way to make progress: the only process that could read data from +the output pipe is you, but you are blocked on the input pipe. + +@end deftypefn + +@c pexecute.txh:216 @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 @@ -889,7 +938,7 @@ name is unset/removed. @end deftypefn -@c pexecute.txh:195 +@c pexecute.txh:224 @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 b2ca6e08ce2..fd0c6b22e9b 100644 --- a/libiberty/pex-common.c +++ b/libiberty/pex-common.c @@ -108,6 +108,8 @@ pex_run (struct pex_obj *obj, int flags, const char *executable, in = -1; out = -1; errdes = -1; + p[READ_PORT] = -1; + p[WRITE_PORT] = -1; outname = (char *) orig_outname; outname_allocated = 0; @@ -276,6 +278,8 @@ pex_run (struct pex_obj *obj, int flags, const char *executable, pid = obj->funcs->exec_child (obj, flags, executable, argv, in, out, errdes, &errmsg, err); + if (p[WRITE_PORT] != -1) + obj->funcs->close (obj, p[WRITE_PORT]); if (pid < 0) goto error_exit; @@ -297,6 +301,52 @@ pex_run (struct pex_obj *obj, int flags, const char *executable, return errmsg; } +/* Return a FILE pointer for the input of the first program + executed. */ + +FILE * +pex_write_input (struct pex_obj *obj, int binary) +{ + int p[2]; + FILE *write_input; + + /* You must call pex_write_input before the first pex_run or pex_one. */ + if (obj->count > 0) + goto usage_error; + + /* You must be using pipes. Implementations that don't support + pipes clear this flag before calling pex_init_common. */ + if (! (obj->flags & PEX_USE_PIPES)) + goto usage_error; + + /* If we have somehow already selected other input, that's a + mistake. */ + if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO) + || obj->next_input_name) + goto usage_error; + + if (obj->funcs->pipe (obj, p, binary != 0) < 0) + return NULL; + + write_input = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0); + if (! write_input) + { + int saved_errno = errno; + obj->funcs->close (obj, p[READ_PORT]); + obj->funcs->close (obj, p[WRITE_PORT]); + errno = saved_errno; + return NULL; + } + + obj->next_input = p[READ_PORT]; + + return write_input; + + usage_error: + errno = EINVAL; + return NULL; +} + /* Return a FILE pointer for the output of the last program executed. */ diff --git a/libiberty/pex-common.h b/libiberty/pex-common.h index b70b38d9736..13ec98149ea 100644 --- a/libiberty/pex-common.h +++ b/libiberty/pex-common.h @@ -121,6 +121,11 @@ struct pex_funcs PEX_USE_PIPES is set). If BINARY is non-zero, open in binary mode. Return pointer on success, NULL on error. */ FILE * (*fdopenr) (struct pex_obj *, int /* fd */, int /* binary */); + /* Get a FILE pointer to write to the file descriptor FD (only + called if PEX_USE_PIPES is set). If BINARY is non-zero, open in + binary mode. Arrange for FD not to be inherited by the child + processes. Return pointer on success, NULL on error. */ + FILE * (*fdopenw) (struct pex_obj *, int /* fd */, int /* binary */); /* Free any system dependent data associated with OBJ. May be NULL if there is nothing to do. */ void (*cleanup) (struct pex_obj *); diff --git a/libiberty/pex-djgpp.c b/libiberty/pex-djgpp.c index 6e58e3fd8dc..17fbf2cc7e4 100644 --- a/libiberty/pex-djgpp.c +++ b/libiberty/pex-djgpp.c @@ -62,6 +62,7 @@ const struct pex_funcs funcs = pex_djgpp_wait, NULL, /* pipe */ NULL, /* fdopenr */ + NULL, /* fdopenw */ NULL /* cleanup */ }; diff --git a/libiberty/pex-msdos.c b/libiberty/pex-msdos.c index 2256117d1bb..db22337aa2a 100644 --- a/libiberty/pex-msdos.c +++ b/libiberty/pex-msdos.c @@ -73,6 +73,7 @@ const struct pex_funcs funcs = pex_msdos_wait, NULL, /* pipe */ NULL, /* fdopenr */ + NULL, /* fdopenw */ pex_msdos_cleanup }; diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c index 35a545cb17b..c92a4297971 100644 --- a/libiberty/pex-unix.c +++ b/libiberty/pex-unix.c @@ -277,6 +277,7 @@ static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *, int, const char **, int *); static int pex_unix_pipe (struct pex_obj *, int *, int); static FILE *pex_unix_fdopenr (struct pex_obj *, int, int); +static FILE *pex_unix_fdopenw (struct pex_obj *, int, int); static void pex_unix_cleanup (struct pex_obj *); /* The list of functions we pass to the common routines. */ @@ -290,6 +291,7 @@ const struct pex_funcs funcs = pex_unix_wait, pex_unix_pipe, pex_unix_fdopenr, + pex_unix_fdopenw, pex_unix_cleanup }; @@ -495,6 +497,15 @@ pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, return fdopen (fd, "r"); } +static FILE * +pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, + int binary ATTRIBUTE_UNUSED) +{ + if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) + return NULL; + return fdopen (fd, "w"); +} + static void pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED) { diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c index 3a75c5be004..046f393c6d9 100644 --- a/libiberty/pex-win32.c +++ b/libiberty/pex-win32.c @@ -83,6 +83,7 @@ static int pex_win32_wait (struct pex_obj *, long, 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. */ @@ -95,6 +96,7 @@ const struct pex_funcs funcs = pex_win32_wait, pex_win32_pipe, pex_win32_fdopenr, + pex_win32_fdopenw, NULL /* cleanup */ }; @@ -766,6 +768,18 @@ pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, 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> diff --git a/libiberty/pexecute.txh b/libiberty/pexecute.txh index 461ff33d018..2bfad0c8b75 100644 --- a/libiberty/pexecute.txh +++ b/libiberty/pexecute.txh @@ -1,3 +1,4 @@ +@c -*- mode: texinfo -*- @deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase}) Prepare to execute one or more programs, with standard output of each @@ -129,6 +130,34 @@ value, or to 0 if there is no relevant @code{errno}. @end deftypefn +@deftypefn Extension {FILE *} pex_write_input (struct pex_obj *@var{obj}, int @var{binary}) + +Return a @code{FILE} pointer @var{fp} for the standard input of the +first program in the pipeline; @var{fp} is opened for writing. You +must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call that +returned @var{obj}. You must close @var{fp} yourself with +@code{fclose} to indicate that the pipeline's input is complete. + +The file descriptor underlying @var{fp} is marked not to be inherited +by child processes. + +This call is not supported on systems which do not support pipes; it +returns with an error. (We could implement it by writing a temporary +file, but then you would need to write all your data and close +@var{fp} before your first call to @code{pex_run} --- and that +wouldn't work on systems that do support pipes: the pipe would fill +up, and you would block. So there isn't any easy way to conceal the +differences between the two types of systems.) + +If you call both @code{pex_write_input} and @code{pex_read_output}, be +careful to avoid deadlock. If the output pipe fills up, so that each +program in the pipeline is waiting for the next to read more data, and +you fill the input pipe by writing more data to @var{fp}, then there +is no way to make progress: the only process that could read data from +the output pipe is you, but you are blocked on the input pipe. + +@end deftypefn + @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 |