diff options
author | Robert Nagy <robert@cvs.openbsd.org> | 2009-10-12 22:32:20 +0000 |
---|---|---|
committer | Robert Nagy <robert@cvs.openbsd.org> | 2009-10-12 22:32:20 +0000 |
commit | c484c66780b875208f5cad3ba1de53083fa16019 (patch) | |
tree | 9f91b80816847ab5f2bc3233283245b58d940c66 /gnu | |
parent | 590155929e7c4ef5450f75dec02557b41fb929c8 (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-wrapper | 12 | ||||
-rw-r--r-- | gnu/lib/libiberty/include/libiberty.h | 68 | ||||
-rw-r--r-- | gnu/lib/libiberty/include/md5.h | 165 | ||||
-rw-r--r-- | gnu/lib/libiberty/include/pex-common.h | 143 | ||||
-rw-r--r-- | gnu/lib/libiberty/shlib_version | 2 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-common.c | 598 | ||||
-rw-r--r-- | gnu/lib/libiberty/src/pex-unix.c | 538 |
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 +} |