Commit a584cf65 by Ian Lance Taylor Committed by Ian Lance Taylor

pex-common.c: New file.

libiberty:
	* pex-common.c: New file.
	* pex-one.c: New file.
	* pexecute.c: New file.
	* pex-common.h: Include <stdio.h>.
	(struct pex_obj): Define.
	(struct pex_funcs): Define.
	(pex_init_common): Declare.
	* pex-unix.c: Rewrite.
	* pex-win32.c: Rewrite.
	* pex-djgpp.c: Rewrite.
	* pex-msdos.c: Rewrite.
	* testsuite/text-pexecute.c: New file.
	* pexecute.txh: Rewrite.
	* configure.ac: Check for wait3 and wait4.  Set CHECK to
	really-check rather than check-cplus-dem.
	* functions.texi: Rebuild.
	* Makefile.in: Rebuild dependencies.
	(CFILES): Add pexecute.c, pex-common.c, pex-one.c.
	(REQUIRED_OFILES): Add pexecute.o, pex-common.o, pex-one.o.
	* testsuite/Makefile.in (really-check): New target.
	(check-pexecute, test-pexecute): New targets.
	* configure: Rebuild.
include:
	* libiberty.h: Include <stdio.h>.
	(PEX_RECORD_TIMES, PEX_USE_PIPES, PEX_SAVE_TEMPS): Define.
	(PEX_LAST, PEX_SEARCH, PEX_SUFFIX, PEX_STDERR_TO_STDOUT): Define.
	(PEX_BINARY_INPUT, PEX_BINARY_OUTPUT): Define.
	(pex_init, pex_run, pex_read_output): Declare.
	(pex_get_status, pex_get_times, pex_free, pex_one): Declare.
	(struct pex_time): Define.

From-SVN: r97148
parent f78c1452
2005-03-28 Ian Lance Taylor <ian@airs.com>
* libiberty.h: Include <stdio.h>.
(PEX_RECORD_TIMES, PEX_USE_PIPES, PEX_SAVE_TEMPS): Define.
(PEX_LAST, PEX_SEARCH, PEX_SUFFIX, PEX_STDERR_TO_STDOUT): Define.
(PEX_BINARY_INPUT, PEX_BINARY_OUTPUT): Define.
(pex_init, pex_run, pex_read_output): Declare.
(pex_get_status, pex_get_times, pex_free, pex_one): Declare.
(struct pex_time): Define.
2005-03-28 Mark Mitchell <mark@codesourcery.com>
* libiberty.h (ffs): Declare, if necessary.
......
/* Function declarations for libiberty.
Copyright 2001, 2002 Free Software Foundation, Inc.
Copyright 2001, 2002, 2005 Free Software Foundation, Inc.
Note - certain prototypes declared in this header file are for
functions whoes implementation copyright does not belong to the
......@@ -46,6 +46,8 @@ extern "C" {
/* Get a definition for va_list. */
#include <stdarg.h>
#include <stdio.h>
/* Build an argument vector from a string. Allocates memory using
malloc. Use freeargv to free the vector. */
......@@ -314,6 +316,166 @@ extern void hex_init (void);
the argument being performed exactly once. */
#define hex_value(c) ((unsigned int) _hex_value[(unsigned char) (c)])
/* Flags for pex_init. These are bits to be or'ed together. */
/* Record subprocess times, if possible. */
#define PEX_RECORD_TIMES 0x1
/* Use pipes for communication between processes, if possible. */
#define PEX_USE_PIPES 0x2
/* Save files used for communication between processes. */
#define PEX_SAVE_TEMPS 0x4
/* Prepare to execute one or more programs, with standard output of
each program fed to standard input of the next.
FLAGS As above.
PNAME The name of the program to report in error messages.
TEMPBASE A base name to use for temporary files; may be NULL to
use a random name.
Returns NULL on error. */
extern struct pex_obj *pex_init (int flags, const char *pname,
const char *tempbase);
/* Flags for pex_run. These are bits to be or'ed together. */
/* Last program in pipeline. Standard output of program goes to
OUTNAME, or, if OUTNAME is NULL, to standard output of caller. Do
not set this if you want to call pex_read_output. After this is
set, pex_run may no longer be called with the same struct
pex_obj. */
#define PEX_LAST 0x1
/* Search for program in executable search path. */
#define PEX_SEARCH 0x2
/* OUTNAME is a suffix. */
#define PEX_SUFFIX 0x4
/* Send program's standard error to standard output. */
#define PEX_STDERR_TO_STDOUT 0x8
/* Input file should be opened in binary mode. This flag is ignored
on Unix. */
#define PEX_BINARY_INPUT 0x10
/* Output file should be opened in binary mode. This flag is ignored
on Unix. For proper behaviour PEX_BINARY_INPUT and
PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using
PEX_BINARY_OUTPUT should be followed by a call using
PEX_BINARY_INPUT. */
#define PEX_BINARY_OUTPUT 0x20
/* Execute one program. Returns NULL on success. On error returns an
error string (typically just the name of a system call); the error
string is statically allocated.
OBJ Returned by pex_init.
FLAGS As above.
EXECUTABLE The program to execute.
ARGV NULL terminated array of arguments to pass to the program.
OUTNAME Sets the output file name as follows:
PEX_SUFFIX set (OUTNAME may not be NULL):
TEMPBASE parameter to pex_init not NULL:
Output file name is the concatenation of TEMPBASE
and OUTNAME.
TEMPBASE is NULL:
Output file name is a random file name ending in
OUTNAME.
PEX_SUFFIX not set:
OUTNAME not NULL:
Output file name is OUTNAME.
OUTNAME NULL, TEMPBASE not NULL:
Output file name is randomly chosen using
TEMPBASE.
OUTNAME NULL, TEMPBASE NULL:
Output file name is randomly chosen.
If PEX_LAST is not set, the output file name is the
name to use for a temporary file holding stdout, if
any (there will not be a file if PEX_USE_PIPES is set
and the system supports pipes). If a file is used, it
will be removed when no longer needed unless
PEX_SAVE_TEMPS is set.
If PEX_LAST is set, and OUTNAME is not NULL, standard
output is written to the output file name. The file
will not be removed. If PEX_LAST and PEX_SUFFIX are
both set, TEMPBASE may not be NULL.
ERRNAME If not NULL, this is the name of a file to which
standard error is written. If NULL, standard error of
the program is standard error of the caller.
ERR On an error return, *ERR is set to an errno value, or
to 0 if there is no relevant errno.
*/
extern const char *pex_run (struct pex_obj *obj, int flags,
const char *executable, char * const *argv,
const char *outname, const char *errname,
int *err);
/* 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.
Returns NULL on error. Don't call fclose on the returned FILE; it
will be closed by pex_free. */
extern FILE *pex_read_output (struct pex_obj *, int binary);
/* Return exit status of all programs in VECTOR. COUNT indicates the
size of VECTOR. The status codes in the vector are in the order of
the calls to pex_run. Returns 0 on error, 1 on success. */
extern int pex_get_status (struct pex_obj *, int count, int *vector);
/* Return times of all programs in VECTOR. COUNT indicates the size
of VECTOR. struct pex_time is really just struct timeval, but that
is not portable to all systems. Returns 0 on error, 1 on
success. */
struct pex_time
{
unsigned long user_seconds;
unsigned long user_microseconds;
unsigned long system_seconds;
unsigned long system_microseconds;
};
extern int pex_get_times (struct pex_obj *, int count,
struct pex_time *vector);
/* Clean up a pex_obj. */
extern void pex_free (struct pex_obj *);
/* Just execute one program. Return value is as for pex_run.
FLAGS Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT.
EXECUTABLE As for pex_run.
ARGV As for pex_run.
PNAME As for pex_init.
OUTNAME As for pex_run when PEX_LAST is set.
ERRNAME As for pex_run.
STATUS Set to exit status on success.
ERR As for pex_run.
*/
extern const char *pex_one (int flags, const char *executable,
char * const *argv, const char *pname,
const char *outname, const char *errname,
int *status, int *err);
/* pexecute and pwait are the old pexecute interface, still here for
backward compatibility. Don't use these for new code. Instead,
use pex_init/pex_run/pex_get_status/pex_free, or pex_one. */
/* Definitions used by the pexecute routine. */
#define PEXECUTE_FIRST 1
......
2005-03-28 Ian Lance Taylor <ian@airs.com>
* pex-common.c: New file.
* pex-one.c: New file.
* pexecute.c: New file.
* pex-common.h: Include <stdio.h>.
(struct pex_obj): Define.
(struct pex_funcs): Define.
(pex_init_common): Declare.
* pex-unix.c: Rewrite.
* pex-win32.c: Rewrite.
* pex-djgpp.c: Rewrite.
* pex-msdos.c: Rewrite.
* testsuite/text-pexecute.c: New file.
* pexecute.txh: Rewrite.
* configure.ac: Check for wait3 and wait4. Set CHECK to
really-check rather than check-cplus-dem.
* functions.texi: Rebuild.
* Makefile.in: Rebuild dependencies.
(CFILES): Add pexecute.c, pex-common.c, pex-one.c.
(REQUIRED_OFILES): Add pexecute.o, pex-common.o, pex-one.o.
* testsuite/Makefile.in (really-check): New target.
(check-pexecute, test-pexecute): New targets.
* configure: Rebuild.
2005-03-28 Mark Kettenis <kettenis@gnu.org>
* unlink-if-ordinary.c: Include <sys/types.h>.
......
......@@ -142,8 +142,8 @@ CFILES = alloca.c argv.c asprintf.c atexit.c \
make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmove.c \
mempcpy.c memset.c mkstemps.c \
objalloc.c obstack.c \
partition.c \
pex-djgpp.c pex-msdos.c \
partition.c pexecute.c \
pex-common.c pex-djgpp.c pex-msdos.c pex-one.c \
pex-unix.c pex-win32.c \
physmem.c putenv.c \
random.c regex.c rename.c rindex.c \
......@@ -170,7 +170,8 @@ REQUIRED_OFILES = ./regex.o ./cplus-dem.o ./cp-demangle.o ./md5.o \
./lbasename.o ./lrealpath.o \
./make-relative-prefix.o ./make-temp-file.o \
./objalloc.o ./obstack.o \
./partition.o ./physmem.o @pexecute@ \
./partition.o ./pexecute.o ./physmem.o \
./pex-common.o ./pex-one.o @pexecute@ \
./safe-ctype.o ./sort.o ./spaces.o ./splay-tree.o ./strerror.o \
./strsignal.o \
./ternary.o \
......@@ -756,6 +757,13 @@ $(CONFIGURED_OFILES): stamp-picdir
else true; fi
$(COMPILE.c) $(srcdir)/partition.c $(OUTPUT_OPTION)
./pex-common.o: $(srcdir)/pex-common.c config.h $(INCDIR)/ansidecl.h \
$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/pex-common.c -o pic/$@; \
else true; fi
$(COMPILE.c) $(srcdir)/pex-common.c $(OUTPUT_OPTION)
./pex-djgpp.o: $(srcdir)/pex-djgpp.c config.h $(INCDIR)/ansidecl.h \
$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
if [ x"$(PICFLAG)" != x ]; then \
......@@ -771,6 +779,13 @@ $(CONFIGURED_OFILES): stamp-picdir
else true; fi
$(COMPILE.c) $(srcdir)/pex-msdos.c $(OUTPUT_OPTION)
./pex-one.o: $(srcdir)/pex-one.c config.h $(INCDIR)/ansidecl.h \
$(INCDIR)/libiberty.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/pex-one.c -o pic/$@; \
else true; fi
$(COMPILE.c) $(srcdir)/pex-one.c $(OUTPUT_OPTION)
./pex-unix.o: $(srcdir)/pex-unix.c config.h $(INCDIR)/ansidecl.h \
$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
if [ x"$(PICFLAG)" != x ]; then \
......@@ -785,6 +800,13 @@ $(CONFIGURED_OFILES): stamp-picdir
else true; fi
$(COMPILE.c) $(srcdir)/pex-win32.c $(OUTPUT_OPTION)
./pexecute.o: $(srcdir)/pexecute.c config.h $(INCDIR)/ansidecl.h \
$(INCDIR)/libiberty.h
if [ x"$(PICFLAG)" != x ]; then \
$(COMPILE.c) $(PICFLAG) $(srcdir)/pexecute.c -o pic/$@; \
else true; fi
$(COMPILE.c) $(srcdir)/pexecute.c $(OUTPUT_OPTION)
./physmem.o: $(srcdir)/physmem.c config.h $(INCDIR)/ansidecl.h \
$(INCDIR)/libiberty.h
if [ x"$(PICFLAG)" != x ]; then \
......
......@@ -4818,7 +4818,7 @@ vars="sys_errlist sys_nerr sys_siglist"
checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
checkfuncs="$checkfuncs getsysinfo table sysctl"
checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4"
# These are neither executed nor required, but they help keep
# autoheader happy without adding a bunch of text to acconfig.h.
......@@ -4895,7 +4895,7 @@ for ac_func in asprintf atexit basename bcmp bcopy bsearch bzero calloc clock \
strtod strtol strtoul tmpnam vasprintf vfprintf vprintf \
vsprintf waitpid getrusage on_exit psignal strerror strsignal \
sysconf times sbrk gettimeofday ffs snprintf vsnprintf \
pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl \
pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl wait3 wait4 \
realpath canonicalize_file_name
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
......@@ -5133,7 +5133,7 @@ fi;
else
# Not a target library, so we set things up to run the test suite.
CHECK=check-cplus-dem
CHECK=really-check
fi
......
......@@ -268,7 +268,7 @@ vars="sys_errlist sys_nerr sys_siglist"
checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
checkfuncs="$checkfuncs getsysinfo table sysctl"
checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4"
# These are neither executed nor required, but they help keep
# autoheader happy without adding a bunch of text to acconfig.h.
......@@ -280,7 +280,7 @@ if test "x" = "y"; then
strtod strtol strtoul tmpnam vasprintf vfprintf vprintf \
vsprintf waitpid getrusage on_exit psignal strerror strsignal \
sysconf times sbrk gettimeofday ffs snprintf vsnprintf \
pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl \
pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl wait3 wait4 \
realpath canonicalize_file_name)
AC_DEFINE(HAVE_SYS_ERRLIST, 1, [Define if you have the sys_errlist variable.])
AC_DEFINE(HAVE_SYS_NERR, 1, [Define if you have the sys_nerr variable.])
......@@ -357,7 +357,7 @@ if test -n "${with_target_subdir}"; then
else
# Not a target library, so we set things up to run the test suite.
CHECK=check-cplus-dem
CHECK=really-check
fi
......
......@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "libiberty.h"
#include <stdio.h>
#define install_error_msg "installation problem, cannot exec `%s'"
......@@ -42,4 +43,87 @@ Boston, MA 02111-1307, USA. */
/* value of `pipe': port index for writing. */
#define WRITE_PORT 1
/* The structure used by pex_init and friends. */
struct pex_obj
{
/* Flags. */
int flags;
/* Name of calling program, for error messages. */
const char *pname;
/* Base name to use for temporary files. */
const char *tempbase;
/* Pipe to use as stdin for next process. */
int next_input;
/* File name to use as stdin for next process. */
char *next_input_name;
/* Whether next_input_name was allocated using malloc. */
int next_input_name_allocated;
/* Number of child processes. */
int count;
/* PIDs of child processes; array allocated using maloc. */
long *children;
/* Exit statuses of child processes; array allocated using malloc. */
int *status;
/* Time used by child processes; array allocated using malloc. */
struct pex_time *time;
/* Number of children we have already waited for. */
int number_waited;
/* FILE created by pex_read_output. */
FILE *read_output;
/* Number of temporary files to remove. */
int remove_count;
/* List of temporary files to remove; array allocated using malloc
of strings allocated using malloc. */
char **remove;
/* Pointers to system dependent functions. */
const struct pex_funcs *funcs;
/* For use by system dependent code. */
void *sysdep;
};
/* Functions passed to pex_run_common. */
struct pex_funcs
{
/* Open file NAME for reading. If BINARY is non-zero, open in
binary mode. Return >= 0 on success, -1 on error. */
int (*open_read) (struct pex_obj *, const char *name, int binary);
/* Open file NAME for writing. If BINARY is non-zero, open in
binary mode. Return >= 0 on success, -1 on error. */
int (*open_write) (struct pex_obj *, const char *name, int binary);
/* Execute a child process. FLAGS, EXECUTABLE, ARGV, ERR are from
pex_run. IN, OUT, ERRDES are each a descriptor, from open_read,
open_write, or pipe, or they are one of STDIN_FILE_NO,
STDOUT_FILE_NO or STDERR_FILE_NO; if not STD*_FILE_NO, they
should be closed. The function should handle the
PEX_STDERR_TO_STDOUT flag. Return >= 0 on success, or -1 on
error and set *ERRMSG and *ERR. */
long (*exec_child) (struct pex_obj *, int flags, const char *executable,
char * const * argv, int in, int out, int errdes,
const char **errmsg, int *err);
/* Close a descriptor. Return 0 on success, -1 on error. */
int (*close) (struct pex_obj *, int);
/* Wait for a child to complete, returning exit status in *STATUS
and time in *TIME (if it is not null). CHILD is from fork. DONE
is 1 if this is called via pex_free. ERRMSG and ERR are as in
fork. Return 0 on success, -1 on error. */
int (*wait) (struct pex_obj *, long, int *status, struct pex_time *time,
int done, const char **errmsg, int *err);
/* Create a pipe (only called if PEX_USE_PIPES is set) storing two
descriptin in *P. If BINARY is non-zero, open in binary mode.
Return 0 on success, -1 on error. */
int (*pipe) (struct pex_obj *, int *p, int binary);
/* Get a FILE pointer to read from a file descriptor (only called if
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);
/* Free any system dependent data associated with OBJ. May be
NULL if there is nothing to do. */
void (*cleanup) (struct pex_obj *);
};
extern struct pex_obj *pex_init_common (int, const char *, const char *,
const struct pex_funcs *);
#endif
/* 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.
......@@ -38,59 +38,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. */
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 *);
/* For communicating information from pexecute to pwait. */
static int last_pid = 0;
static int last_status = 0;
static int last_reaped = 0;
/* The list of functions we pass to the common routines. */
int
pexecute (const char *program, char * const *argv, const char *this_pname,
const char *temp_base, char **errmsg_fmt,
char **errmsg_arg, int flags)
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 /* 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. */
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);
}
/* Close a file. */
/* Tuck the status away for pwait, and return a "pid". */
last_status = rc << 8;
return last_pid;
static int
pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
{
return close (fd);
}
int
pwait (int pid, int *status, int flags)
/* 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)
{
/* On MSDOS each pexecute must be followed by its associated pwait. */
if (pid != last_pid
/* Called twice for the same child? */
|| pid == last_reaped)
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)
{
int e;
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;
}
}
}
status = (((flags & PEX_SEARCH) != 0 ? _spawnvp : _spawnv)
(P_WAIT, program, (const char **) 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)
{
errno = PWAIT_ERROR;
return -1;
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;
}
}
/* ??? Here's an opportunity to canonicalize the values in STATUS.
Needed? */
*status = (last_status >> 8);
last_reaped = last_pid;
return last_pid;
/* 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 = xrealloc (statuses, (obj->count + 1) * sizeof (int));
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, const char **errmsg,
int *err)
{
int *statuses;
if (time != NULL)
memset (time, 0, sizeof *time);
statuses = (int *) obj->sysdep;
*status = statuses[pid];
return 0;
}
/* Utilities to execute a program in a subprocess (possibly linked by pipes
with other subprocesses), and wait for it. Generic MSDOS 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.
......@@ -36,105 +36,281 @@ extern int errno;
#include "safe-ctype.h"
#include <process.h>
/* 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. */
/* The structure we keep in obj->sysdep. */
/* For communicating information from pexecute to pwait. */
static int last_pid = 0;
static int last_status = 0;
static int last_reaped = 0;
#define PEX_MSDOS_FILE_COUNT 3
int
pexecute (const char *program, char * const *argv, const char *this_pname,
const char *temp_base, char **errmsg_fmt, char **errmsg_arg,
int flags)
#define PEX_MSDOS_FD_OFFSET 10
struct pex_msdos
{
int rc;
char *scmd, *rf;
FILE *argfile;
int i, el = flags & PEXECUTE_SEARCH ? 4 : 0;
/* An array of file names. We refer to these using file descriptors
of 10 + array index. */
const char *files[PEX_MSDOS_FILE_COUNT];
/* Exit statuses of programs which have been run. */
int *statuses;
};
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 *);
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 *);
static void pex_msdos_cleanup (struct pex_obj *);
/* The list of functions we pass to the common routines. */
const struct pex_funcs funcs =
{
pex_msdos_open,
pex_msdos_open,
pex_msdos_exec_child,
pex_msdos_close,
pex_msdos_wait,
NULL, /* pipe */
NULL, /* fdopenr */
pex_msdos_cleanup
};
/* Return a newly initialized pex_obj structure. */
struct pex_obj *
pex_init (int flags, const char *pname, const char *tempbase)
{
struct pex_obj *ret;
int i;
/* MSDOS does not support pipes. */
flags &= ~ PEX_USE_PIPES;
last_pid++;
if (last_pid < 0)
last_pid = 1;
ret = pex_init_common (flags, pname, tempbase, funcs);
if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
ret->sysdep = xmalloc (sizeof (struct pex_msdos));
for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
ret->files[i] = NULL;
ret->statuses = NULL;
return ret;
}
/* Open a file. FIXME: We ignore the binary argument, since we have
no way to handle it. */
static int
pex_msdos_open (struct pex_obj *obj, const char *name,
int binary ATTRIBUTE_UNUSED)
{
struct pex_msdos *ms;
int i;
ms = (struct pex_msdos *) obj->sysdep;
for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
{
if (ms->files[i] == NULL)
{
ms->files[i] = xstrdup (name);
return i + PEX_MSDOS_FD_OFFSET;
}
}
abort ();
}
/* Get the index into msdos->files associated with an open file
descriptor. */
static int
pex_msdos_fdindex (struct pex_msdos *ms, int fd)
{
fd -= PEX_MSDOS_FD_OFFSET;
if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
abort ();
return fd;
}
/* Close a file. */
static int
pex_msdos_close (struct pex_obj *obj, int fd)
{
struct pex_msdos *ms;
int fdinex;
ms = (struct pex_msdos *) obj->sysdep;
fdindex = pe_msdos_fdindex (ms, fd);
free (ms->files[fdindex]);
ms->files[fdindex] = NULL;
}
/* Execute a child. */
static long
pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
char * const * argv, int in, int out,
int errdes ATTRIBUTE_UNUSED, const char **errmsg,
int *err)
{
struct pex_msdos *ms;
char *temp_base;
int temp_base_allocated;
char *rf;
int inindex;
char *infile;
int outindex;
char *outfile;
char *scmd;
FILE *argfile;
int i;
int status;
ms = (struct pex_msdos *) obj->sysdep;
/* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
and PEX_STDERR_TO_STDOUT. */
temp_base = obj->temp_base;
if (temp_base != NULL)
temp_base_allocated = 0;
else
{
temp_base = choose_temp_base ();
temp_base_allocated = 1;
}
rf = concat (temp_base, ".gp", NULL);
if (temp_base_allocated)
free (temp_base);
if (in == STDIN_FILE_NO)
{
inindex = -1;
infile = "";
}
else
{
inindex = pex_msdos_fdindex (ms, in);
infile = ms->files[inindex];
}
if (out == STDOUT_FILE_NO)
{
outindex = -1;
outfile = "";
}
else
{
outindex = pex_msdos_fdindex (ms, out);
outfile = ms->files[outindex];
}
scmd = xmalloc (strlen (program)
+ ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
+ strlen (rf)
+ strlen (infile)
+ strlen (outfile)
+ 10);
sprintf (scmd, "%s%s @%s%s%s%s%s",
program,
(flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
rf,
inindex != -1 ? " <" : "",
infile,
outindex != -1 ? " >" : "",
outfile);
if (temp_base == 0)
temp_base = choose_temp_base ();
scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el);
rf = scmd + strlen(program) + 2 + el;
sprintf (scmd, "%s%s @%s.gp", program,
(flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base);
argfile = fopen (rf, "w");
if (argfile == 0)
if (argfile == NULL)
{
int errno_save = errno;
*err = errno;
free (scmd);
errno = errno_save;
*errmsg_fmt = "cannot open `%s.gp'";
*errmsg_arg = temp_base;
free (rf);
*errmsg = "cannot open temporary command file";
return -1;
}
for (i=1; argv[i]; i++)
for (i = 1; argv[i] != NULL; ++i)
{
char *cp;
for (cp = argv[i]; *cp; cp++)
char *p;
for (p = argv[i]; *p != '\0'; ++p)
{
if (*cp == '"' || *cp == '\'' || *cp == '\\' || ISSPACE (*cp))
fputc ('\\', argfile);
fputc (*cp, argfile);
if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
putc ('\\', argfile);
putc (*p, argfile);
}
fputc ('\n', argfile);
putc ('\n', argfile);
}
fclose (argfile);
rc = system (scmd);
fclose (argfile);
{
int errno_save = errno;
remove (rf);
free (scmd);
errno = errno_save;
}
status = system (scmd);
if (rc == -1)
if (status == -1)
{
*errmsg_fmt = install_error_msg;
*errmsg_arg = (char *)program;
*err = errno;
remove (rf);
free (scmd);
free (rf);
*errmsg = "system";
return -1;
}
/* Tuck the status away for pwait, and return a "pid". */
last_status = rc << 8;
return last_pid;
remove (rf);
free (scmd);
free (rf);
/* Save the exit status for later. When we are called, obj->count
is the number of children which have executed before this
one. */
ms->statuses = xrealloc (ms->statuses, (obj->count + 1) * sizeof (int));
ms->statuses[obj->count] = status;
return obj->count;
}
/* Use ECHILD if available, otherwise use EINVAL. */
#ifdef ECHILD
#define PWAIT_ERROR ECHILD
#else
#define PWAIT_ERROR EINVAL
#endif
/* Wait for a child process to complete. Actually the child process
has already completed, and we just need to return the exit
status. */
int
pwait (int pid, int *status, int flags)
static int
pex_msdos_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)
{
/* On MSDOS each pexecute must be followed by its associated pwait. */
if (pid != last_pid
/* Called twice for the same child? */
|| pid == last_reaped)
{
errno = PWAIT_ERROR;
return -1;
}
/* ??? Here's an opportunity to canonicalize the values in STATUS.
Needed? */
*status = last_status;
last_reaped = last_pid;
return last_pid;
struct pex_msdos *ms;
ms = (struct pex_msdos *) obj->sysdep;
if (time != NULL)
memset (time, 0, sizeof *time);
*status = ms->statuses[pid];
return 0;
}
/* Clean up the pex_msdos structure. */
static void
pex_msdos_cleanup (struct pex_obj *obj)
{
struct pex_msdos *ms;
int i;
ms = (struct pex_msdos *) obj->sysdep;
for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
if (msdos->files[i] != NULL)
free (msdos->files[i]);
if (msdos->statuses != NULL)
free (msdos->statuses);
free (msdos);
obj->sysdep = NULL;
}
/* Execute a program and wait for a result.
Copyright (C) 2005 Free Software Foundation, Inc.
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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "libiberty.h"
const char *
pex_one (int flags, const char *executable, char * const *argv,
const char *pname, const char *outname, const char *errname,
int *status, int *err)
{
struct pex_obj *obj;
const char *errmsg;
obj = pex_init (0, pname, NULL);
errmsg = pex_run (obj, flags, executable, argv, outname, errname, err);
if (errmsg == NULL)
{
if (!pex_get_status (obj, 1, status))
{
*err = 0;
errmsg = "pex_get_status failed";
}
}
pex_free (obj);
return errmsg;
}
/* Utilities to execute a program in a subprocess (possibly linked by pipes
with other subprocesses), and wait for it.
Copyright (C) 2004 Free Software Foundation, Inc.
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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* pexecute is an old routine. This implementation uses the newer
pex_init/pex_run/pex_get_status/pex_free routines. Don't use
pexecute in new code. Use the newer routines instead. */
#include "config.h"
#include "libiberty.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* We only permit a single pexecute chain to execute at a time. This
was always true anyhow, though it wasn't documented. */
static struct pex_obj *pex;
static int idx;
int
pexecute (const char *program, char * const *argv, const char *pname,
const char *temp_base, char **errmsg_fmt, char **errmsg_arg,
int flags)
{
const char *errmsg;
int err;
if ((flags & PEXECUTE_FIRST) != 0)
{
if (pex != NULL)
{
*errmsg_fmt = "pexecute already in progress";
*errmsg_arg = NULL;
return -1;
}
pex = pex_init (PEX_USE_PIPES, pname, temp_base);
idx = 0;
}
else
{
if (pex == NULL)
{
*errmsg_fmt = "pexecute not in progress";
*errmsg_arg = NULL;
return -1;
}
}
errmsg = pex_run (pex,
(((flags & PEXECUTE_LAST) != 0 ? PEX_LAST : 0)
| ((flags & PEXECUTE_SEARCH) != 0 ? PEX_SEARCH : 0)),
program, argv, NULL, NULL, &err);
if (errmsg != NULL)
{
*errmsg_fmt = (char *) errmsg;
*errmsg_arg = NULL;
return -1;
}
/* Instead of a PID, we just return a one-based index into the
status values. We avoid zero just because the old pexecute would
never return it. */
return ++idx;
}
int
pwait (int pid, int *status, int flags ATTRIBUTE_UNUSED)
{
/* The PID returned by pexecute is one-based. */
--pid;
if (pex == NULL || pid < 0 || pid >= idx)
return -1;
if (pid == 0 && idx == 1)
{
if (!pex_get_status (pex, 1, status))
return -1;
}
else
{
int *vector;
vector = xmalloc (idx * sizeof (int));
if (!pex_get_status (pex, idx, vector))
return -1;
*status = vector[pid];
free (vector);
}
/* Assume that we are done after the caller has retrieved the last
exit status. The original implementation did not require that
the exit statuses be retrieved in order, but this implementation
does. */
if (pid + 1 == idx)
{
pex_free (pex);
pex = NULL;
idx = 0;
}
return pid + 1;
}
......@@ -42,17 +42,28 @@ INCDIR=$(srcdir)/../$(MULTISRCTOP)../include
all:
# CHECK is set to "really_check" or the empty string by configure.
check: @CHECK@
really-check: check-cplus-dem check-pexecute
# Run some tests of the demangler.
check-cplus-dem: test-demangle $(srcdir)/demangle-expected
./test-demangle < $(srcdir)/demangle-expected
# Check the pexecute code.
check-pexecute: test-pexecute
./test-pexecute
TEST_COMPILE = $(CC) @DEFS@ $(LIBCFLAGS) -I.. -I$(INCDIR) $(HDEFINES)
test-demangle: $(srcdir)/test-demangle.c ../libiberty.a
$(TEST_COMPILE) -o test-demangle \
$(srcdir)/test-demangle.c ../libiberty.a
test-pexecute: $(srcdir)/test-pexecute.c ../libiberty.a
$(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-pexecute \
$(srcdir)/test-pexecute.c ../libiberty.a
# Standard (either GNU or Cygnus) rules we don't use.
info install-info clean-info dvi install etags tags installcheck:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment