diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2010-10-19 21:13:25 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2010-10-19 21:13:25 +0000 |
| commit | 7a815afd9b5121ee0f65dc1e1de1c0de6de97679 (patch) | |
| tree | f61b968a46c92e81f6de581582cb064bf9dca27d /libiberty/pex-djgpp.c | |
| parent | 42f6b9ffef1927d55d15075d9e810435c590c404 (diff) | |
Notes
Diffstat (limited to 'libiberty/pex-djgpp.c')
| -rw-r--r-- | libiberty/pex-djgpp.c | 292 |
1 files changed, 238 insertions, 54 deletions
diff --git a/libiberty/pex-djgpp.c b/libiberty/pex-djgpp.c index 968e78412151..17fbf2cc7e44 100644 --- a/libiberty/pex-djgpp.c +++ b/libiberty/pex-djgpp.c @@ -1,6 +1,6 @@ /* Utilities to execute a program in a subprocess (possibly linked by pipes with other subprocesses), and wait for it. DJGPP specialization. - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. This file is part of the libiberty library. @@ -16,8 +16,8 @@ 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., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ #include "pex-common.h" @@ -29,6 +29,10 @@ extern int errno; #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> #include <process.h> /* Use ECHILD if available, otherwise use EINVAL. */ @@ -38,66 +42,246 @@ extern int errno; #define PWAIT_ERROR EINVAL #endif -/* MSDOS doesn't multitask, but for the sake of a consistent interface - the code behaves like it does. pexecute runs the program, tucks the - exit code away, and returns a "pid". pwait must be called to fetch the - exit code. */ - -/* For communicating information from pexecute to pwait. */ -static int last_pid = 0; -static int last_status = 0; -static int last_reaped = 0; - -int -pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags) - const char *program; - char * const *argv; - const char *this_pname; - const char *temp_base; - char **errmsg_fmt, **errmsg_arg; - int flags; +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, + 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 *, + int, const char **, int *); + +/* The list of functions we pass to the common routines. */ + +const struct pex_funcs funcs = { - int rc; + pex_djgpp_open_read, + pex_djgpp_open_write, + pex_djgpp_exec_child, + pex_djgpp_close, + pex_djgpp_wait, + NULL, /* pipe */ + NULL, /* fdopenr */ + NULL, /* fdopenw */ + NULL /* cleanup */ +}; - last_pid++; - if (last_pid < 0) - last_pid = 1; +/* Return a newly initialized pex_obj structure. */ - if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE) - abort (); +struct pex_obj * +pex_init (int flags, const char *pname, const char *tempbase) +{ + /* DJGPP does not support pipes. */ + flags &= ~ PEX_USE_PIPES; + return pex_init_common (flags, pname, tempbase, &funcs); +} - /* ??? What are the possible return values from spawnv? */ - rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (P_WAIT, program, argv); +/* Open a file for reading. */ - if (rc == -1) - { - *errmsg_fmt = install_error_msg; - *errmsg_arg = (char *)program; - return -1; - } +static int +pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, + const char *name, int binary) +{ + return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT)); +} + +/* Open a file for writing. */ - /* Tuck the status away for pwait, and return a "pid". */ - last_status = rc << 8; - return last_pid; +static int +pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, + const char *name, int binary) +{ + /* Note that we can't use O_EXCL here because gcc may have already + created the temporary file via make_temp_file. */ + return open (name, + (O_WRONLY | O_CREAT | O_TRUNC + | (binary ? O_BINARY : O_TEXT)), + S_IRUSR | S_IWUSR); } -int -pwait (pid, status, flags) - int pid; - int *status; - int flags; +/* Close a file. */ + +static int +pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) { - /* On MSDOS each pexecute must be followed by its associated pwait. */ - if (pid != last_pid - /* Called twice for the same child? */ - || pid == last_reaped) + return close (fd); +} + +/* Execute a child. */ + +static long +pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable, + char * const * argv, int in, int out, int errdes, + const char **errmsg, int *err) +{ + int org_in, org_out, org_errdes; + int status; + int *statuses; + + org_in = -1; + org_out = -1; + org_errdes = -1; + + if (in != STDIN_FILE_NO) + { + org_in = dup (STDIN_FILE_NO); + if (org_in < 0) + { + *err = errno; + *errmsg = "dup"; + return -1; + } + if (dup2 (in, STDIN_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return -1; + } + if (close (in) < 0) + { + *err = errno; + *errmsg = "close"; + return -1; + } + } + + if (out != STDOUT_FILE_NO) + { + org_out = dup (STDOUT_FILE_NO); + if (org_out < 0) + { + *err = errno; + *errmsg = "dup"; + return -1; + } + if (dup2 (out, STDOUT_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return -1; + } + if (close (out) < 0) + { + *err = errno; + *errmsg = "close"; + return -1; + } + } + + if (errdes != STDERR_FILE_NO + || (flags & PEX_STDERR_TO_STDOUT) != 0) { - errno = PWAIT_ERROR; - return -1; + org_errdes = dup (STDERR_FILE_NO); + if (org_errdes < 0) + { + *err = errno; + *errmsg = "dup"; + return -1; + } + if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes, + STDERR_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return -1; + } + if (errdes != STDERR_FILE_NO) + { + if (close (errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return -1; + } + } } - /* ??? Here's an opportunity to canonicalize the values in STATUS. - Needed? */ - *status = (last_status >> 8); - last_reaped = last_pid; - return last_pid; + + status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv) + (P_WAIT, executable, (char * const *) argv)); + + if (status == -1) + { + *err = errno; + *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv"; + } + + if (in != STDIN_FILE_NO) + { + if (dup2 (org_in, STDIN_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return -1; + } + if (close (org_in) < 0) + { + *err = errno; + *errmsg = "close"; + return -1; + } + } + + if (out != STDOUT_FILE_NO) + { + if (dup2 (org_out, STDOUT_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return -1; + } + if (close (org_out) < 0) + { + *err = errno; + *errmsg = "close"; + return -1; + } + } + + if (errdes != STDERR_FILE_NO + || (flags & PEX_STDERR_TO_STDOUT) != 0) + { + if (dup2 (org_errdes, STDERR_FILE_NO) < 0) + { + *err = errno; + *errmsg = "dup2"; + return -1; + } + if (close (org_errdes) < 0) + { + *err = errno; + *errmsg = "close"; + return -1; + } + } + + /* Save the exit status for later. When we are called, obj->count + is the number of children which have executed before this + one. */ + statuses = (int *) obj->sysdep; + statuses = XRESIZEVEC (int, statuses, obj->count + 1); + statuses[obj->count] = status; + obj->sysdep = (void *) statuses; + + return obj->count; +} + +/* Wait for a child process to complete. Actually the child process + has already completed, and we just need to return the exit + status. */ + +static int +pex_djgpp_wait (struct pex_obj *obj, long pid, int *status, + struct pex_time *time, int done ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED, + int *err ATTRIBUTE_UNUSED) +{ + int *statuses; + + if (time != NULL) + memset (time, 0, sizeof *time); + + statuses = (int *) obj->sysdep; + *status = statuses[pid]; + + return 0; } |
