summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorRobert Nagy <robert@cvs.openbsd.org>2009-10-12 22:32:20 +0000
committerRobert Nagy <robert@cvs.openbsd.org>2009-10-12 22:32:20 +0000
commitc484c66780b875208f5cad3ba1de53083fa16019 (patch)
tree9f91b80816847ab5f2bc3233283245b58d940c66 /gnu
parent590155929e7c4ef5450f75dec02557b41fb929c8 (diff)
Add fopen_unlocked.c pex-unix.c pex-common.c unlink-if-ordinary.c to
the list of built files and switch the md5.h header to the libiberty one. This change is needed by gcc4 and it is a major library crank for libiberty. tested by many people on many architectures and finally ok'd by deraadt@
Diffstat (limited to 'gnu')
-rw-r--r--gnu/lib/libiberty/Makefile.bsd-wrapper12
-rw-r--r--gnu/lib/libiberty/include/libiberty.h68
-rw-r--r--gnu/lib/libiberty/include/md5.h165
-rw-r--r--gnu/lib/libiberty/include/pex-common.h143
-rw-r--r--gnu/lib/libiberty/shlib_version2
-rw-r--r--gnu/lib/libiberty/src/pex-common.c598
-rw-r--r--gnu/lib/libiberty/src/pex-unix.c538
7 files changed, 1487 insertions, 39 deletions
diff --git a/gnu/lib/libiberty/Makefile.bsd-wrapper b/gnu/lib/libiberty/Makefile.bsd-wrapper
index 54ebd2bac14..561e7bf2bff 100644
--- a/gnu/lib/libiberty/Makefile.bsd-wrapper
+++ b/gnu/lib/libiberty/Makefile.bsd-wrapper
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile.bsd-wrapper,v 1.11 2008/05/27 18:52:40 miod Exp $
+# $OpenBSD: Makefile.bsd-wrapper,v 1.12 2009/10/12 22:32:19 robert Exp $
LIB= iberty
CPPFLAGS+= -DHAVE_CONFIG_H -I$(.CURDIR)/src -I$(.CURDIR)/include -I$(.OBJDIR)
@@ -11,15 +11,15 @@ HOST_FILES!= cat $(.OBJDIR)/needed-list 2>/dev/null||true
# XXX remove oldhashtab.c once gcc 2.95 is no longer used
SRCS= argv.c choose-temp.c concat.c cplus-dem.c cp-demangle.c \
- dyn-string.c \
- fdmatch.c getopt.c getopt1.c getpwd.c getruntime.c \
+ dyn-string.c fdmatch.c fopen_unlocked.c \
+ getopt.c getopt1.c getpwd.c getruntime.c \
hashtab.c hex.c fibheap.c partition.c \
floatformat.c make-temp-file.c make-relative-prefix.c \
- objalloc.c obstack.c oldhashtab.c \
- pexecute.c regex.c safe-ctype.c spaces.c splay-tree.c \
+ md5.c objalloc.c obstack.c oldhashtab.c pex-common.c \
+ pex-unix.c pexecute.c regex.c safe-ctype.c spaces.c splay-tree.c \
strerror.c strsignal.c strverscmp.c \
xatexit.c xexit.c xmalloc.c xmemdup.c xstrerror.c xstrdup.c \
- physmem.c lbasename.c lrealpath.c \
+ physmem.c lbasename.c lrealpath.c unlink-if-ordinary.c \
$(HOST_FILES)
# XXX -- These files are generated during the PREREQ variable assignment.
diff --git a/gnu/lib/libiberty/include/libiberty.h b/gnu/lib/libiberty/include/libiberty.h
index 1e07013bb33..e69aeb2837b 100644
--- a/gnu/lib/libiberty/include/libiberty.h
+++ b/gnu/lib/libiberty/include/libiberty.h
@@ -342,6 +342,28 @@ 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);
+
/* Definitions used by the pexecute routine. */
#define PEXECUTE_FIRST 1
@@ -350,6 +372,44 @@ extern void hex_init (void);
#define PEXECUTE_SEARCH 4
#define PEXECUTE_VERBOSE 8
+/* 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
+
+/* 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);
+
/* Execute a program. */
extern int pexecute (const char *, char * const *, const char *,
@@ -359,6 +419,14 @@ extern int pexecute (const char *, char * const *, const char *,
extern int pwait (int, int *, int);
+struct pex_time
+{
+ unsigned long user_seconds;
+ unsigned long user_microseconds;
+ unsigned long system_seconds;
+ unsigned long system_microseconds;
+};
+
#if !HAVE_DECL_ASPRINTF
/* Like sprintf but provides a pointer to malloc'd storage, which must
be freed by the caller. */
diff --git a/gnu/lib/libiberty/include/md5.h b/gnu/lib/libiberty/include/md5.h
index e992789c45c..e8eedb96d60 100644
--- a/gnu/lib/libiberty/include/md5.h
+++ b/gnu/lib/libiberty/include/md5.h
@@ -1,40 +1,141 @@
-/* $OpenBSD: md5.h,v 1.2 2003/11/25 21:20:32 espie Exp $ */
-#ifndef LIBIBERTY_MD5_H
-#define LIBIBERTY_MD5_H
+/* md5.h - Declaration of functions and data types used for MD5 sum
+ computing library functions.
+ Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+#include "ansidecl.h"
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+typedef uintptr_t md5_uintptr;
+#else
+# define INT_MAX_32_BITS 2147483647
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+ This should be valid for all systems GNU cares about because
+ that doesn't include 16-bit systems, and only modern systems
+ (that certainly have <limits.h>) have 64+-bit integral types. */
+
+# ifndef INT_MAX
+# define INT_MAX INT_MAX_32_BITS
+# endif
+
+# if INT_MAX == INT_MAX_32_BITS
+ typedef unsigned int md5_uint32;
+# else
+# if SHRT_MAX == INT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
+# else
+# if LONG_MAX == INT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error.
+ Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+# endif
+/* We have to make a guess about the integer type equivalent in size
+ to pointers which should always be correct. */
+typedef unsigned long int md5_uintptr;
+#endif
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128] ATTRIBUTE_ALIGNED_ALIGNOF(md5_uint32);
+};
/*
- * Copyright (c) 2003 Marc Espie.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
- * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
*/
-/* md5 wrapper for libc functions */
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void md5_init_ctx (struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void md5_process_block (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void md5_process_bytes (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf);
+
-/* go grab the same file name under /usr/include */
-#include "/usr/include/md5.h"
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+extern int md5_stream (FILE *stream, void *resblock);
-#define md5_ctx MD5Context
-#define md5_process_bytes(a, b, c) MD5Update(c, (const unsigned char *)a, b)
-#define md5_finish_ctx(a, b) MD5Final(b, a)
-#define md5_init_ctx MD5Init
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *md5_buffer (const char *buffer, size_t len, void *resblock);
#endif
diff --git a/gnu/lib/libiberty/include/pex-common.h b/gnu/lib/libiberty/include/pex-common.h
new file mode 100644
index 00000000000..0e88c355ffc
--- /dev/null
+++ b/gnu/lib/libiberty/include/pex-common.h
@@ -0,0 +1,143 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it. Shared logic.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 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., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#ifndef PEX_COMMON_H
+#define PEX_COMMON_H
+
+#include "config.h"
+#include "libiberty.h"
+#include <stdio.h>
+
+#define install_error_msg "installation problem, cannot exec `%s'"
+
+/* stdin file number. */
+#define STDIN_FILE_NO 0
+
+/* stdout file number. */
+#define STDOUT_FILE_NO 1
+
+/* stderr file number. */
+#define STDERR_FILE_NO 2
+
+/* value of `pipe': port index for reading. */
+#define READ_PORT 0
+
+/* 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 malloc. */
+ 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_input_file. */
+ FILE *input_file;
+ /* 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, TOCLOSE are all descriptors, from
+ open_read, open_write, or pipe, or they are one of STDIN_FILE_NO,
+ STDOUT_FILE_NO or STDERR_FILE_NO; if IN, OUT, and ERRDES are not
+ STD*_FILE_NO, they should be closed. If the descriptor TOCLOSE
+ is not -1, and the system supports pipes, TOCLOSE should be
+ closed in the child process. 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 */,
+ char * const * /* env */,
+ int /* in */, int /* out */, int /* errdes */,
+ int /* toclose */, 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 /* child */, 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
+ descriptors in P[0] and P[1]. 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 */);
+ /* 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 *);
+};
+
+extern struct pex_obj *pex_init_common (int, const char *, const char *,
+ const struct pex_funcs *);
+
+#endif
diff --git a/gnu/lib/libiberty/shlib_version b/gnu/lib/libiberty/shlib_version
index 1c5d96eb2aa..c10074d52ae 100644
--- a/gnu/lib/libiberty/shlib_version
+++ b/gnu/lib/libiberty/shlib_version
@@ -1,2 +1,2 @@
-major=9
+major=10
minor=0
diff --git a/gnu/lib/libiberty/src/pex-common.c b/gnu/lib/libiberty/src/pex-common.c
new file mode 100644
index 00000000000..bb127f2ed77
--- /dev/null
+++ b/gnu/lib/libiberty/src/pex-common.c
@@ -0,0 +1,598 @@
+/* Common code for executing a program in a sub-process.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@airs.com>.
+
+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 "config.h"
+#include "libiberty.h"
+#include "pex-common.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern int mkstemps (char *, int);
+
+/* This file contains subroutines for the program execution routines
+ (pex_init, pex_run, etc.). This file is compiled on all
+ systems. */
+
+static void pex_add_remove (struct pex_obj *, const char *, int);
+static int pex_get_status_and_time (struct pex_obj *, int, const char **,
+ int *);
+
+/* Initialize a pex_obj structure. */
+
+struct pex_obj *
+pex_init_common (int flags, const char *pname, const char *tempbase,
+ const struct pex_funcs *funcs)
+{
+ struct pex_obj *obj;
+
+ obj = XNEW (struct pex_obj);
+ obj->flags = flags;
+ obj->pname = pname;
+ obj->tempbase = tempbase;
+ obj->next_input = STDIN_FILE_NO;
+ obj->next_input_name = NULL;
+ obj->next_input_name_allocated = 0;
+ obj->count = 0;
+ obj->children = NULL;
+ obj->status = NULL;
+ obj->time = NULL;
+ obj->number_waited = 0;
+ obj->input_file = NULL;
+ obj->read_output = NULL;
+ obj->remove_count = 0;
+ obj->remove = NULL;
+ obj->funcs = funcs;
+ obj->sysdep = NULL;
+ return obj;
+}
+
+/* Add a file to be removed when we are done. */
+
+static void
+pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
+{
+ char *add;
+
+ ++obj->remove_count;
+ obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
+ if (allocated)
+ add = (char *) name;
+ else
+ add = xstrdup (name);
+ obj->remove[obj->remove_count - 1] = add;
+}
+
+/* Generate a temporary file name based on OBJ, FLAGS, and NAME.
+ Return NULL if we were unable to reserve a temporary filename.
+
+ If non-NULL, the result is either allocated with malloc, or the
+ same pointer as NAME. */
+static char *
+temp_file (struct pex_obj *obj, int flags, char *name)
+{
+ if (name == NULL)
+ {
+ if (obj->tempbase == NULL)
+ {
+ name = make_temp_file (NULL);
+ }
+ else
+ {
+ int len = strlen (obj->tempbase);
+ int out;
+
+ if (len >= 6
+ && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
+ name = xstrdup (obj->tempbase);
+ else
+ name = concat (obj->tempbase, "XXXXXX", NULL);
+
+ out = mkstemps (name, 0);
+ if (out < 0)
+ {
+ free (name);
+ return NULL;
+ }
+
+ /* This isn't obj->funcs->close because we got the
+ descriptor from mkstemps, not from a function in
+ obj->funcs. Calling close here is just like what
+ make_temp_file does. */
+ close (out);
+ }
+ }
+ else if ((flags & PEX_SUFFIX) != 0)
+ {
+ if (obj->tempbase == NULL)
+ name = make_temp_file (name);
+ else
+ name = concat (obj->tempbase, name, NULL);
+ }
+
+ return name;
+}
+
+
+/* As for pex_run (), but permits the environment for the child process
+ to be specified. */
+
+const char *
+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;
+ char *outname;
+ int outname_allocated;
+ int p[2];
+ int toclose;
+ long pid;
+
+ in = -1;
+ out = -1;
+ errdes = -1;
+ outname = (char *) orig_outname;
+ outname_allocated = 0;
+
+ /* If the user called pex_input_file, close the file now. */
+ if (obj->input_file)
+ {
+ if (fclose (obj->input_file) == EOF)
+ {
+ errmsg = "closing pipeline input file";
+ goto error_exit;
+ }
+ obj->input_file = NULL;
+ }
+
+ /* Set IN. */
+
+ if (obj->next_input_name != NULL)
+ {
+ /* We have to make sure that the previous process has completed
+ before we try to read the file. */
+ if (!pex_get_status_and_time (obj, 0, &errmsg, err))
+ goto error_exit;
+
+ in = obj->funcs->open_read (obj, obj->next_input_name,
+ (flags & PEX_BINARY_INPUT) != 0);
+ if (in < 0)
+ {
+ *err = errno;
+ errmsg = "open temporary file";
+ goto error_exit;
+ }
+ if (obj->next_input_name_allocated)
+ {
+ free (obj->next_input_name);
+ obj->next_input_name_allocated = 0;
+ }
+ obj->next_input_name = NULL;
+ }
+ else
+ {
+ in = obj->next_input;
+ if (in < 0)
+ {
+ *err = 0;
+ errmsg = "pipeline already complete";
+ goto error_exit;
+ }
+ }
+
+ /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME. */
+
+ if ((flags & PEX_LAST) != 0)
+ {
+ if (outname == NULL)
+ out = STDOUT_FILE_NO;
+ else if ((flags & PEX_SUFFIX) != 0)
+ {
+ outname = concat (obj->tempbase, outname, NULL);
+ outname_allocated = 1;
+ }
+ obj->next_input = -1;
+ }
+ else if ((obj->flags & PEX_USE_PIPES) == 0)
+ {
+ outname = temp_file (obj, flags, outname);
+ if (! outname)
+ {
+ *err = 0;
+ errmsg = "could not create temporary file";
+ goto error_exit;
+ }
+
+ if (outname != orig_outname)
+ outname_allocated = 1;
+
+ if ((obj->flags & PEX_SAVE_TEMPS) == 0)
+ {
+ pex_add_remove (obj, outname, outname_allocated);
+ outname_allocated = 0;
+ }
+
+ /* Hand off ownership of outname to the next stage. */
+ obj->next_input_name = outname;
+ obj->next_input_name_allocated = outname_allocated;
+ outname_allocated = 0;
+ }
+ else
+ {
+ if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
+ {
+ *err = errno;
+ errmsg = "pipe";
+ goto error_exit;
+ }
+
+ out = p[WRITE_PORT];
+ obj->next_input = p[READ_PORT];
+ }
+
+ if (out < 0)
+ {
+ out = obj->funcs->open_write (obj, outname,
+ (flags & PEX_BINARY_OUTPUT) != 0);
+ if (out < 0)
+ {
+ *err = errno;
+ errmsg = "open temporary output file";
+ goto error_exit;
+ }
+ }
+
+ if (outname_allocated)
+ {
+ free (outname);
+ outname_allocated = 0;
+ }
+
+ /* Set ERRDES. */
+
+ if (errname == NULL)
+ errdes = STDERR_FILE_NO;
+ else
+ {
+ /* We assume that stderr is in text mode--it certainly shouldn't
+ be controlled by PEX_BINARY_OUTPUT. If necessary, we can add
+ a PEX_BINARY_STDERR flag. */
+ errdes = obj->funcs->open_write (obj, errname, 0);
+ if (errdes < 0)
+ {
+ *err = errno;
+ errmsg = "open error file";
+ goto error_exit;
+ }
+ }
+
+ /* If we are using pipes, the child process has to close the next
+ input pipe. */
+
+ if ((obj->flags & PEX_USE_PIPES) == 0)
+ toclose = -1;
+ else
+ toclose = obj->next_input;
+
+ /* Run the program. */
+
+ pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
+ in, out, errdes, toclose, &errmsg, err);
+ if (pid < 0)
+ goto error_exit;
+
+ ++obj->count;
+ obj->children = XRESIZEVEC (long, obj->children, obj->count);
+ obj->children[obj->count - 1] = pid;
+
+ return NULL;
+
+ error_exit:
+ if (in >= 0 && in != STDIN_FILE_NO)
+ obj->funcs->close (obj, in);
+ if (out >= 0 && out != STDOUT_FILE_NO)
+ obj->funcs->close (obj, out);
+ if (errdes >= 0 && errdes != STDERR_FILE_NO)
+ obj->funcs->close (obj, errdes);
+ if (outname_allocated)
+ free (outname);
+ 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 *
+pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
+{
+ char *name = (char *) in_name;
+ FILE *f;
+
+ /* This must be called before the first pipeline stage is run, and
+ there must not have been any other input selected. */
+ if (obj->count != 0
+ || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ || obj->next_input_name)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ name = temp_file (obj, flags, name);
+ if (! name)
+ return NULL;
+
+ f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
+ if (! f)
+ {
+ free (name);
+ return NULL;
+ }
+
+ obj->input_file = f;
+ obj->next_input_name = name;
+ obj->next_input_name_allocated = (name != in_name);
+
+ return f;
+}
+
+/* Return a stream for a pipe connected to the standard input of the
+ first stage of the pipeline. */
+FILE *
+pex_input_pipe (struct pex_obj *obj, int binary)
+{
+ int p[2];
+ FILE *f;
+
+ /* You must call pex_input_pipe 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;
+
+ f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
+ if (! f)
+ {
+ 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 f;
+
+ usage_error:
+ errno = EINVAL;
+ return NULL;
+}
+
+/* Return a FILE pointer for the output of the last program
+ executed. */
+
+FILE *
+pex_read_output (struct pex_obj *obj, int binary)
+{
+ if (obj->next_input_name != NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ /* We have to make sure that the process has completed before we
+ try to read the file. */
+ if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+ {
+ errno = err;
+ return NULL;
+ }
+
+ obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
+
+ if (obj->next_input_name_allocated)
+ {
+ free (obj->next_input_name);
+ obj->next_input_name_allocated = 0;
+ }
+ obj->next_input_name = NULL;
+ }
+ else
+ {
+ int o;
+
+ o = obj->next_input;
+ if (o < 0 || o == STDIN_FILE_NO)
+ return NULL;
+ obj->read_output = obj->funcs->fdopenr (obj, o, binary);
+ obj->next_input = -1;
+ }
+
+ return obj->read_output;
+}
+
+/* Get the exit status and, if requested, the resource time for all
+ the child processes. Return 0 on failure, 1 on success. */
+
+static int
+pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
+ int *err)
+{
+ int ret;
+ int i;
+
+ if (obj->number_waited == obj->count)
+ return 1;
+
+ obj->status = XRESIZEVEC (int, obj->status, obj->count);
+ if ((obj->flags & PEX_RECORD_TIMES) != 0)
+ obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
+
+ ret = 1;
+ for (i = obj->number_waited; i < obj->count; ++i)
+ {
+ if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
+ obj->time == NULL ? NULL : &obj->time[i],
+ done, errmsg, err) < 0)
+ ret = 0;
+ }
+ obj->number_waited = i;
+
+ return ret;
+}
+
+/* Get exit status of executed programs. */
+
+int
+pex_get_status (struct pex_obj *obj, int count, int *vector)
+{
+ if (obj->status == NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+ return 0;
+ }
+
+ if (count > obj->count)
+ {
+ memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
+ count = obj->count;
+ }
+
+ memcpy (vector, obj->status, count * sizeof (int));
+
+ return 1;
+}
+
+/* Get process times of executed programs. */
+
+int
+pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
+{
+ if (obj->status == NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+ return 0;
+ }
+
+ if (obj->time == NULL)
+ return 0;
+
+ if (count > obj->count)
+ {
+ memset (vector + obj->count, 0,
+ (count - obj->count) * sizeof (struct pex_time));
+ count = obj->count;
+ }
+
+ memcpy (vector, obj->time, count * sizeof (struct pex_time));
+
+ return 1;
+}
+
+/* Free a pex_obj structure. */
+
+void
+pex_free (struct pex_obj *obj)
+{
+ if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ obj->funcs->close (obj, obj->next_input);
+
+ /* If the caller forgot to wait for the children, we do it here, to
+ avoid zombies. */
+ if (obj->status == NULL)
+ {
+ const char *errmsg;
+ int err;
+
+ obj->flags &= ~ PEX_RECORD_TIMES;
+ pex_get_status_and_time (obj, 1, &errmsg, &err);
+ }
+
+ if (obj->next_input_name_allocated)
+ free (obj->next_input_name);
+ if (obj->children != NULL)
+ free (obj->children);
+ if (obj->status != NULL)
+ free (obj->status);
+ if (obj->time != NULL)
+ free (obj->time);
+ if (obj->read_output != NULL)
+ fclose (obj->read_output);
+
+ if (obj->remove_count > 0)
+ {
+ int i;
+
+ for (i = 0; i < obj->remove_count; ++i)
+ {
+ remove (obj->remove[i]);
+ free (obj->remove[i]);
+ }
+ free (obj->remove);
+ }
+
+ if (obj->funcs->cleanup != NULL)
+ obj->funcs->cleanup (obj);
+
+ free (obj);
+}
diff --git a/gnu/lib/libiberty/src/pex-unix.c b/gnu/lib/libiberty/src/pex-unix.c
new file mode 100644
index 00000000000..c5fa984817e
--- /dev/null
+++ b/gnu/lib/libiberty/src/pex-unix.c
@@ -0,0 +1,538 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it. Generic Unix version
+ (also used for UWIN and VMS).
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 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., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "libiberty.h"
+#include "pex-common.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+
+#ifdef vfork /* Autoconf may define this to fork for us. */
+# define VFORK_STRING "fork"
+#else
+# define VFORK_STRING "vfork"
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+#ifdef VMS
+#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
+ lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
+#endif /* VMS */
+
+
+/* File mode to use for private and world-readable files. */
+
+#if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
+#define PUBLIC_MODE \
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
+#else
+#define PUBLIC_MODE 0666
+#endif
+
+/* Get the exit status of a particular process, and optionally get the
+ time that it took. This is simple if we have wait4, slightly
+ harder if we have waitpid, and is a pain if we only have wait. */
+
+static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
+
+#ifdef HAVE_WAIT4
+
+static pid_t
+pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
+ struct pex_time *time)
+{
+ pid_t ret;
+ struct rusage r;
+
+#ifdef HAVE_WAITPID
+ if (time == NULL)
+ return waitpid (pid, status, 0);
+#endif
+
+ ret = wait4 (pid, status, 0, &r);
+
+ if (time != NULL)
+ {
+ time->user_seconds = r.ru_utime.tv_sec;
+ time->user_microseconds= r.ru_utime.tv_usec;
+ time->system_seconds = r.ru_stime.tv_sec;
+ time->system_microseconds= r.ru_stime.tv_usec;
+ }
+
+ return ret;
+}
+
+#else /* ! defined (HAVE_WAIT4) */
+
+#ifdef HAVE_WAITPID
+
+#ifndef HAVE_GETRUSAGE
+
+static pid_t
+pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
+ struct pex_time *time)
+{
+ if (time != NULL)
+ memset (time, 0, sizeof (struct pex_time));
+ return waitpid (pid, status, 0);
+}
+
+#else /* defined (HAVE_GETRUSAGE) */
+
+static pid_t
+pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
+ struct pex_time *time)
+{
+ struct rusage r1, r2;
+ pid_t ret;
+
+ if (time == NULL)
+ return waitpid (pid, status, 0);
+
+ getrusage (RUSAGE_CHILDREN, &r1);
+
+ ret = waitpid (pid, status, 0);
+ if (ret < 0)
+ return ret;
+
+ getrusage (RUSAGE_CHILDREN, &r2);
+
+ time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
+ time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
+ if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
+ {
+ --time->user_seconds;
+ time->user_microseconds += 1000000;
+ }
+
+ time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
+ time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
+ if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
+ {
+ --time->system_seconds;
+ time->system_microseconds += 1000000;
+ }
+
+ return ret;
+}
+
+#endif /* defined (HAVE_GETRUSAGE) */
+
+#else /* ! defined (HAVE_WAITPID) */
+
+struct status_list
+{
+ struct status_list *next;
+ pid_t pid;
+ int status;
+ struct pex_time time;
+};
+
+static pid_t
+pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
+{
+ struct status_list **pp;
+
+ for (pp = (struct status_list **) &obj->sysdep;
+ *pp != NULL;
+ pp = &(*pp)->next)
+ {
+ if ((*pp)->pid == pid)
+ {
+ struct status_list *p;
+
+ p = *pp;
+ *status = p->status;
+ if (time != NULL)
+ *time = p->time;
+ *pp = p->next;
+ free (p);
+ return pid;
+ }
+ }
+
+ while (1)
+ {
+ pid_t cpid;
+ struct status_list *psl;
+ struct pex_time pt;
+#ifdef HAVE_GETRUSAGE
+ struct rusage r1, r2;
+#endif
+
+ if (time != NULL)
+ {
+#ifdef HAVE_GETRUSAGE
+ getrusage (RUSAGE_CHILDREN, &r1);
+#else
+ memset (&pt, 0, sizeof (struct pex_time));
+#endif
+ }
+
+ cpid = wait (status);
+
+#ifdef HAVE_GETRUSAGE
+ if (time != NULL && cpid >= 0)
+ {
+ getrusage (RUSAGE_CHILDREN, &r2);
+
+ pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
+ pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
+ if (pt.user_microseconds < 0)
+ {
+ --pt.user_seconds;
+ pt.user_microseconds += 1000000;
+ }
+
+ pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
+ pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
+ if (pt.system_microseconds < 0)
+ {
+ --pt.system_seconds;
+ pt.system_microseconds += 1000000;
+ }
+ }
+#endif
+
+ if (cpid < 0 || cpid == pid)
+ {
+ if (time != NULL)
+ *time = pt;
+ return cpid;
+ }
+
+ psl = XNEW (struct status_list);
+ psl->pid = cpid;
+ psl->status = *status;
+ if (time != NULL)
+ psl->time = pt;
+ psl->next = (struct status_list *) obj->sysdep;
+ obj->sysdep = (void *) psl;
+ }
+}
+
+#endif /* ! defined (HAVE_WAITPID) */
+#endif /* ! defined (HAVE_WAIT4) */
+
+static void pex_child_error (struct pex_obj *, const char *, const char *, int)
+ ATTRIBUTE_NORETURN;
+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 *, char * const *,
+ int, 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 *);
+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. */
+
+const struct pex_funcs funcs =
+{
+ pex_unix_open_read,
+ pex_unix_open_write,
+ pex_unix_exec_child,
+ pex_unix_close,
+ pex_unix_wait,
+ pex_unix_pipe,
+ pex_unix_fdopenr,
+ pex_unix_fdopenw,
+ pex_unix_cleanup
+};
+
+/* Return a newly initialized pex_obj structure. */
+
+struct pex_obj *
+pex_init (int flags, const char *pname, const char *tempbase)
+{
+ return pex_init_common (flags, pname, tempbase, &funcs);
+}
+
+/* Open a file for reading. */
+
+static int
+pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary ATTRIBUTE_UNUSED)
+{
+ return open (name, O_RDONLY);
+}
+
+/* Open a file for writing. */
+
+static int
+pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
+ int binary ATTRIBUTE_UNUSED)
+{
+ /* 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, PUBLIC_MODE);
+}
+
+/* Close a file. */
+
+static int
+pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
+{
+ return close (fd);
+}
+
+/* Report an error from a child process. We don't use stdio routines,
+ because we might be here due to a vfork call. */
+
+static void
+pex_child_error (struct pex_obj *obj, const char *executable,
+ const char *errmsg, int err)
+{
+#define writeerr(s) write (STDERR_FILE_NO, s, strlen (s))
+ writeerr (obj->pname);
+ writeerr (": error trying to exec '");
+ writeerr (executable);
+ writeerr ("': ");
+ writeerr (errmsg);
+ writeerr (": ");
+ writeerr (xstrerror (err));
+ writeerr ("\n");
+ _exit (-1);
+}
+
+/* Execute a child. */
+
+extern char **environ;
+
+static long
+pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
+ char * const * argv, char * const * env,
+ int in, int out, int errdes,
+ int toclose, 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;
+ volatile int retries;
+
+ sleep_interval = 1;
+ pid = -1;
+ for (retries = 0; retries < 4; ++retries)
+ {
+ pid = vfork ();
+ if (pid >= 0)
+ break;
+ sleep (sleep_interval);
+ sleep_interval *= 2;
+ }
+
+ switch (pid)
+ {
+ case -1:
+ *err = errno;
+ *errmsg = VFORK_STRING;
+ return -1;
+
+ case 0:
+ /* Child process. */
+ if (in != STDIN_FILE_NO)
+ {
+ if (dup2 (in, STDIN_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ if (close (in) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if (out != STDOUT_FILE_NO)
+ {
+ if (dup2 (out, STDOUT_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ if (close (out) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if (errdes != STDERR_FILE_NO)
+ {
+ if (dup2 (errdes, STDERR_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ if (close (errdes) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if (toclose >= 0)
+ {
+ if (close (toclose) < 0)
+ pex_child_error (obj, executable, "close", errno);
+ }
+ if ((flags & PEX_STDERR_TO_STDOUT) != 0)
+ {
+ if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
+ pex_child_error (obj, executable, "dup2", errno);
+ }
+
+ if (env)
+ environ = (char**) env;
+
+ if ((flags & PEX_SEARCH) != 0)
+ {
+ execvp (executable, argv);
+ pex_child_error (obj, executable, "execvp", errno);
+ }
+ else
+ {
+ execv (executable, argv);
+ pex_child_error (obj, executable, "execv", errno);
+ }
+
+ /* NOTREACHED */
+ return -1;
+
+ default:
+ /* Parent process. */
+ if (in != STDIN_FILE_NO)
+ {
+ if (close (in) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return -1;
+ }
+ }
+ if (out != STDOUT_FILE_NO)
+ {
+ if (close (out) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return -1;
+ }
+ }
+ if (errdes != STDERR_FILE_NO)
+ {
+ if (close (errdes) < 0)
+ {
+ *err = errno;
+ *errmsg = "close";
+ return -1;
+ }
+ }
+
+ return (long) pid;
+ }
+}
+
+/* Wait for a child process to complete. */
+
+static int
+pex_unix_wait (struct pex_obj *obj, long pid, int *status,
+ struct pex_time *time, int done, const char **errmsg,
+ int *err)
+{
+ /* If we are cleaning up when the caller didn't retrieve process
+ status for some reason, encourage the process to go away. */
+ if (done)
+ kill (pid, SIGTERM);
+
+ if (pex_wait (obj, pid, status, time) < 0)
+ {
+ *err = errno;
+ *errmsg = "wait";
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Create a pipe. */
+
+static int
+pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
+ int binary ATTRIBUTE_UNUSED)
+{
+ return pipe (p);
+}
+
+/* Get a FILE pointer to read from a file descriptor. */
+
+static FILE *
+pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary ATTRIBUTE_UNUSED)
+{
+ 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)
+{
+#if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
+ while (obj->sysdep != NULL)
+ {
+ struct status_list *this;
+ struct status_list *next;
+
+ this = (struct status_list *) obj->sysdep;
+ next = this->next;
+ free (this);
+ obj->sysdep = (void *) next;
+ }
+#endif
+}