Improve popen compatibility with glibc.

* libc/posix/popen.c (popen): The 2006-08-22 change to use
FD_CLOEXEC disagrees with other implementations; instead, use
pidlist to work even when fcntl is not available.  Meanwhile,
support the 'e' modifier to set CLOEXEC, as in glibc.  Drop
cygwin-specific code, now that cygwin has its own version.
* libc/posix/Makefile.am (CHEWOUT_FILES): Document popen.
* libc/posix/posix.tex: New file.
This commit is contained in:
Eric Blake 2009-08-18 16:43:21 +00:00
parent 56dbf99329
commit a051160962
4 changed files with 89 additions and 17 deletions

View File

@ -1,3 +1,14 @@
2009-08-18 Eric Blake <ebb9@byu.net>
Improve popen compatibility with glibc.
* libc/posix/popen.c (popen): The 2006-08-22 change to use
FD_CLOEXEC disagrees with other implementations; instead, use
pidlist to work even when fcntl is not available. Meanwhile,
support the 'e' modifier to set CLOEXEC, as in glibc. Drop
cygwin-specific code, now that cygwin has its own version.
* libc/posix/Makefile.am (CHEWOUT_FILES): Document popen.
* libc/posix/posix.tex: New file.
2009-08-17 Craig Howland <howland@LGSInnovations.com> 2009-08-17 Craig Howland <howland@LGSInnovations.com>
* libc/string/wcsncpy.c (wcsncpy): Re-write function based on small * libc/string/wcsncpy.c (wcsncpy): Re-write function based on small

View File

@ -51,7 +51,8 @@ endif # USE_LIBTOOL
include $(srcdir)/../../Makefile.shared include $(srcdir)/../../Makefile.shared
CHEWOUT_FILES = CHEWOUT_FILES = \
popen.def
SUFFIXES = .def SUFFIXES = .def
@ -63,8 +64,8 @@ CHEW = ../../doc/makedoc -f $(srcdir)/../../doc/doc.str
TARGETDOC = ../tmp.texi TARGETDOC = ../tmp.texi
# No doc for posix. doc: $(CHEWOUT_FILES)
doc: cat $(srcdir)/posix.tex >> $(TARGETDOC)
AM_CFLAGS = -D_GNU_SOURCE AM_CFLAGS = -D_GNU_SOURCE

View File

@ -32,6 +32,53 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
/*
FUNCTION
<<popen>>, <<pclose>>---tie a stream to a command string
INDEX
popen
INDEX
pclose
ANSI_SYNOPSIS
#include <stdio.h>
FILE *popen(char *<[s]>, char *<[mode]>);
int pclose(FILE *<[f]>);
DESCRIPTION
Use <<popen>> to create a stream to a child process executing a
command string <<*<[s]>>> as processed by <</bin/sh>> on your system.
The argument <[mode]> must start with either `<<r>>', where the stream
reads from the child's <<stdout>>, or `<<w>>', where the stream writes
to the child's <<stdin>>. As an extension, <[mode]> may also contain
`<<e>>' to set the close-on-exec bit of the parent's file descriptor.
The stream created by <<popen>> must be closed by <<pclose>> to avoid
resource leaks.
Streams created by prior calls to <<popen>> are not visible in
subsequent <<popen>> children, regardless of the close-on-exec bit.
Use ``<<system(NULL)>>'' to test whether your system has <</bin/sh>>
available.
RETURNS
<<popen>> returns a file stream opened with the specified <[mode]>,
or <<NULL>> if a child process could not be created. <<pclose>>
returns -1 if the stream was not created by <<popen>> or if the
application used <<wait>> or similar to steal the status; otherwise
it returns the exit status of the child which can be interpreted
in the same manner as a status obtained by <<waitpid>>.
PORTABILITY
POSIX.2 requires <<popen>> and <<pclose>>, but only specifies a mode
of just <<r>> or <<w>>. Where <<sh>> is found is left unspecified.
Supporting OS subroutines required: <<_exit>>, <<_execve>>, <<_fork_r>>,
<<_wait_r>>, <<pipe>>, <<fcntl>>, <<sbrk>>.
*/
#ifndef _NO_POPEN #ifndef _NO_POPEN
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
@ -66,14 +113,14 @@ _DEFUN(popen, (program, type),
const char *program _AND const char *program _AND
const char *type) const char *type)
{ {
struct pid *cur; struct pid *cur, *last;
FILE *iop; FILE *iop;
int pdes[2], pid; int pdes[2], pid;
if ((*type != 'r' && *type != 'w') if ((*type != 'r' && *type != 'w')
|| (type[1] || (type[1]
#ifdef __CYGWIN__ #ifdef HAVE_FCNTL
&& (type[2] || (type[1] != 'b' && type[1] != 't')) && (type[2] || (type[1] != 'e'))
#endif #endif
)) { )) {
errno = EINVAL; errno = EINVAL;
@ -111,12 +158,11 @@ _DEFUN(popen, (program, type),
} }
(void)close(pdes[1]); (void)close(pdes[1]);
} }
/* Close all fd's created by prior popen. */
for (last = NULL, cur = pidlist; cur;
last = cur, cur = cur->next)
(void)close (fileno (cur->fp));
execl(_PATH_BSHELL, "sh", "-c", program, NULL); execl(_PATH_BSHELL, "sh", "-c", program, NULL);
#ifdef __CYGWIN__
/* On cygwin32, we may not have /bin/sh. In that
case, try to find sh on PATH. */
execlp("sh", "sh", "-c", program, NULL);
#endif
_exit(127); _exit(127);
/* NOTREACHED */ /* NOTREACHED */
} }
@ -131,7 +177,8 @@ _DEFUN(popen, (program, type),
} }
#ifdef HAVE_FCNTL #ifdef HAVE_FCNTL
/* Hide pipe from future popens; assume fcntl can't fail. */ /* Mark pipe cloexec if requested. */
if (type[1] == 'e')
fcntl (fileno (iop), F_SETFD, fcntl (fileno (iop), F_SETFD,
fcntl (fileno (iop), F_GETFD, 0) | FD_CLOEXEC); fcntl (fileno (iop), F_GETFD, 0) | FD_CLOEXEC);
#endif /* HAVE_FCNTL */ #endif /* HAVE_FCNTL */

View File

@ -0,0 +1,13 @@
@node Posix
@chapter Posix Functions
This chapter groups several utility functions specified by POSIX, but
not by C. Each function documents which header to use.
@menu
* popen:: Create a stream tied to a child process
@end menu
@page
@include posix/popen.def