-/* Copyright (C) 1991 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
/* Structure describing a popen child. */
struct child
{
- /* It is important that the first member of this structure be an `int' that
- is the file descriptor. This is because the `fileno' function assumes
- that __cookie(STREAM) points to the file descriptor. */
- int fd;
- pid_t pid;
+ pid_t pid; /* PID of the child. */
+ __ptr_t cookie; /* Original cookie from fdopen. */
+ __io_functions funcs; /* Original functions from fdopen. */
};
-#ifndef FORK
-#define FORK fork
-#endif
+/* io_functions for pipe streams.
+ These all simply call the corresponding
+ original function with the original cookie. */
+
+#define FUNC(type, name, args) \
+ static type DEFUN(__CONCAT(child_,name), args, __CONCAT(name,decl)) \
+ { \
+ struct child *c = (struct child *) cookie; \
+ { \
+ __ptr_t cookie = c->cookie; \
+ return (*c->funcs.__CONCAT(__,name)) args; \
+ } \
+ }
+#define readdecl PTR cookie AND register char *buf AND register size_t n
+FUNC (int, read, (cookie, buf, n))
+#define writedecl PTR cookie AND register CONST char *buf AND register size_t n
+FUNC (int, write, (cookie, buf, n))
+#define seekdecl PTR cookie AND fpos_t *pos AND int whence
+FUNC (int, seek, (cookie, pos, whence))
+#define closedecl PTR cookie
+FUNC (int, close, (cookie))
+#define filenodecl PTR cookie
+FUNC (int, fileno, (cookie))
+
+static const __io_functions child_funcs
+ = { child_read, child_write, child_seek, child_close, child_fileno };
+\f
/* Open a new stream that is a one-way pipe to a
child process running the given shell command. */
FILE *
return NULL;
/* Fork off the child. */
- pid = FORK();
+ pid = __vfork ();
if (pid == (pid_t) -1)
{
/* The fork failed. */
- (void) close(pipedes[0]);
- (void) close(pipedes[1]);
+ (void) close (pipedes[0]);
+ (void) close (pipedes[1]);
return NULL;
}
else if (pid == (pid_t) 0)
won't see it. */
if (*mode == 'r')
{
- (void) close(pipedes[STDOUT_FILENO]);
+ (void) close (pipedes[STDOUT_FILENO]);
(void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
- stream = fdopen(pipedes[STDIN_FILENO], mode);
+ stream = fdopen (pipedes[STDIN_FILENO], mode);
}
else
{
- (void) close(pipedes[STDIN_FILENO]);
+ (void) close (pipedes[STDIN_FILENO]);
(void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
- stream = fdopen(pipedes[STDOUT_FILENO], mode);
+ stream = fdopen (pipedes[STDOUT_FILENO], mode);
}
if (stream == NULL)
goto error;
- child = (struct child *) malloc(sizeof(struct child));
+ child = (struct child *) malloc (sizeof (struct child));
if (child == NULL)
goto error;
- child->fd = fileno(stream);
+
+ {
+ /* Make sure STREAM has its functions set before
+ we try to squirrel them away in CHILD. */
+ extern void __stdio_check_funcs __P ((FILE *));
+ __stdio_check_funcs (stream);
+ }
+
child->pid = pid;
+ child->cookie = stream->__cookie;
+ child->funcs = stream->__io_funcs;
stream->__cookie = (PTR) child;
+ stream->__io_funcs = child_funcs;
stream->__ispipe = 1;
return stream;
- error:;
+ error:
{
/* The stream couldn't be opened or the child structure couldn't be
allocated. Kill the child and close the other side of the pipe. */
int save = errno;
- (void) kill(pid, SIGKILL);
+ (void) kill (pid, SIGKILL);
if (stream == NULL)
- (void) close(pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
+ (void) close (pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
else
- (void) fclose(stream);
+ (void) fclose (stream);
#ifndef NO_WAITPID
- (void) waitpid(pid, (int *) NULL, 0);
+ (void) waitpid (pid, (int *) NULL, 0);
#else
{
pid_t dead;
int
DEFUN(pclose, (stream), register FILE *stream)
{
+ struct child *c;
pid_t pid, dead;
int status;
return -1;
}
- pid = ((struct child *) stream->__cookie)->pid;
- free(stream->__cookie);
- stream->__cookie = (PTR) &stream->__fileno;
+ c = (struct child *) stream->__cookie;
+ pid = c->pid;
+ stream->__cookie = c->cookie;
+ stream->__io_funcs = c->funcs;
+ free ((PTR) c);
stream->__ispipe = 0;
- if (fclose(stream))
+ if (fclose (stream))
return -1;
#ifndef NO_WAITPID