Mon Feb 19 15:30:26 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
[glibc/history.git] / sysdeps / posix / pipestream.c
blob53595f5b54dfe437eb7b39374f092ca2180191fa
1 /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #include <ansidecl.h>
20 #include <errno.h>
21 #include <stddef.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include <fcntl.h>
30 #define SH_PATH "/bin/sh" /* Shell to run. */
31 #define SH_NAME "sh" /* Name to give it. */
33 /* Structure describing a popen child. */
34 struct child
36 pid_t pid; /* PID of the child. */
37 __ptr_t cookie; /* Original cookie from fdopen. */
38 __io_functions funcs; /* Original functions from fdopen. */
41 /* io_functions for pipe streams.
42 These all simply call the corresponding
43 original function with the original cookie. */
45 #define FUNC(type, name, args) \
46 static type DEFUN(__CONCAT(child_,name), args, __CONCAT(name,decl)) \
47 { \
48 struct child *c = (struct child *) cookie; \
49 { \
50 __ptr_t cookie = c->cookie; \
51 return (*c->funcs.__CONCAT(__,name)) args; \
52 } \
55 #define readdecl PTR cookie AND register char *buf AND register size_t n
56 FUNC (int, read, (cookie, buf, n))
57 #define writedecl PTR cookie AND register CONST char *buf AND register size_t n
58 FUNC (int, write, (cookie, buf, n))
59 #define seekdecl PTR cookie AND fpos_t *pos AND int whence
60 FUNC (int, seek, (cookie, pos, whence))
61 #define closedecl PTR cookie
62 FUNC (int, close, (cookie))
63 #define filenodecl PTR cookie
64 FUNC (int, fileno, (cookie))
66 static const __io_functions child_funcs
67 = { child_read, child_write, child_seek, child_close, child_fileno };
69 /* Open a new stream that is a one-way pipe to a
70 child process running the given shell command. */
71 FILE *
72 DEFUN(popen, (command, mode), CONST char *command AND CONST char *mode)
74 pid_t pid;
75 int pipedes[2];
76 FILE *stream;
77 struct child *child;
79 if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
81 errno = EINVAL;
82 return NULL;
85 /* Create the pipe. */
86 if (pipe(pipedes) < 0)
87 return NULL;
89 /* Fork off the child. */
90 pid = __vfork ();
91 if (pid == (pid_t) -1)
93 /* The fork failed. */
94 (void) close (pipedes[0]);
95 (void) close (pipedes[1]);
96 return NULL;
98 else if (pid == (pid_t) 0)
100 /* We are the child side. Make the write side of
101 the pipe be stdin or the read side be stdout. */
103 CONST char *new_argv[4];
105 if ((*mode == 'w' ? dup2(pipedes[STDIN_FILENO], STDIN_FILENO) :
106 dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO)) < 0)
107 _exit(127);
109 /* Close the pipe descriptors. */
110 (void) close(pipedes[STDIN_FILENO]);
111 (void) close(pipedes[STDOUT_FILENO]);
113 /* Exec the shell. */
114 new_argv[0] = SH_NAME;
115 new_argv[1] = "-c";
116 new_argv[2] = command;
117 new_argv[3] = NULL;
118 (void) execve(SH_PATH, (char *CONST *) new_argv, environ);
119 /* Die if it failed. */
120 _exit(127);
123 /* We are the parent side. */
125 /* Close the irrelevant side of the pipe and open the relevant side as a
126 new stream. Mark our side of the pipe to close on exec, so new children
127 won't see it. */
128 if (*mode == 'r')
130 (void) close (pipedes[STDOUT_FILENO]);
131 (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
132 stream = fdopen (pipedes[STDIN_FILENO], mode);
134 else
136 (void) close (pipedes[STDIN_FILENO]);
137 (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
138 stream = fdopen (pipedes[STDOUT_FILENO], mode);
141 if (stream == NULL)
142 goto error;
144 child = (struct child *) malloc (sizeof (struct child));
145 if (child == NULL)
146 goto error;
149 /* Make sure STREAM has its functions set before
150 we try to squirrel them away in CHILD. */
151 extern void __stdio_check_funcs __P ((FILE *));
152 __stdio_check_funcs (stream);
155 child->pid = pid;
156 child->cookie = stream->__cookie;
157 child->funcs = stream->__io_funcs;
158 stream->__cookie = (PTR) child;
159 stream->__io_funcs = child_funcs;
160 stream->__ispipe = 1;
161 return stream;
163 error:
165 /* The stream couldn't be opened or the child structure couldn't be
166 allocated. Kill the child and close the other side of the pipe. */
167 int save = errno;
168 (void) kill (pid, SIGKILL);
169 if (stream == NULL)
170 (void) close (pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
171 else
172 (void) fclose (stream);
173 #ifndef NO_WAITPID
174 (void) waitpid (pid, (int *) NULL, 0);
175 #else
177 pid_t dead;
179 dead = wait ((int *) NULL);
180 while (dead > 0 && dead != pid);
182 #endif
183 errno = save;
184 return NULL;
188 /* Close a stream opened by popen and return its status.
189 Returns -1 if the stream was not opened by popen. */
191 DEFUN(pclose, (stream), register FILE *stream)
193 struct child *c;
194 pid_t pid, dead;
195 int status;
197 if (!__validfp(stream) || !stream->__ispipe)
199 errno = EINVAL;
200 return -1;
203 c = (struct child *) stream->__cookie;
204 pid = c->pid;
205 stream->__cookie = c->cookie;
206 stream->__io_funcs = c->funcs;
207 free ((PTR) c);
208 stream->__ispipe = 0;
209 if (fclose (stream))
210 return -1;
212 #ifndef NO_WAITPID
213 dead = waitpid (pid, &status, 0);
214 #else
216 dead = wait (&status);
217 while (dead > 0 && dead != pid);
218 #endif
219 if (dead != pid)
220 status = -1;
222 return status;