Update.
[glibc.git] / sysdeps / posix / pipestream.c
blob31348b8976cf542ccb99da45d8660a947388c9ad
1 /* Copyright (C) 1991, 1992, 1993, 1996, 1997 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 not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
19 #include <errno.h>
20 #include <stddef.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include <fcntl.h>
29 #define SH_PATH "/bin/sh" /* Shell to run. */
30 #define SH_NAME "sh" /* Name to give it. */
32 /* Structure describing a popen child. */
33 struct child
35 pid_t pid; /* PID of the child. */
36 __ptr_t cookie; /* Original cookie from fdopen. */
37 __io_functions funcs; /* Original functions from fdopen. */
40 /* io_functions for pipe streams.
41 These all simply call the corresponding
42 original function with the original cookie. */
44 #define FUNC(type, name, proto, args) \
45 static type __CONCAT(child_,name) proto \
46 { \
47 struct child *c = (struct child *) cookie; \
48 { \
49 __ptr_t cookie = c->cookie; \
50 return (*c->funcs.__CONCAT(__,name)) args; \
51 } \
54 FUNC (int, read, (void *cookie, char *buf, size_t n), (cookie, buf, n))
55 FUNC (int, write, (void *cookie, const char *buf, size_t n), (cookie, buf, n))
56 FUNC (int, seek, (void *cookie, fpos_t *pos, int whence),
57 (cookie, pos, whence))
58 FUNC (int, close, (void *cookie), (cookie))
59 FUNC (int, fileno, (void *cookie), (cookie))
61 static const __io_functions child_funcs
62 = { child_read, child_write, child_seek, child_close, child_fileno };
64 /* Open a new stream that is a one-way pipe to a
65 child process running the given shell command. */
66 FILE *
67 popen (command, mode)
68 const char *command;
69 const char *mode;
71 pid_t pid;
72 int pipedes[2];
73 FILE *stream;
74 struct child *child;
76 if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
78 __set_errno (EINVAL);
79 return NULL;
82 /* Create the pipe. */
83 if (pipe (pipedes) < 0)
84 return NULL;
86 /* Fork off the child. */
87 pid = __vfork ();
88 if (pid == (pid_t) -1)
90 /* The fork failed. */
91 (void) close (pipedes[0]);
92 (void) close (pipedes[1]);
93 return NULL;
95 else if (pid == (pid_t) 0)
97 /* We are the child side. Make the write side of
98 the pipe be stdin or the read side be stdout. */
100 const char *new_argv[4];
102 if ((*mode == 'w' ? dup2(pipedes[STDIN_FILENO], STDIN_FILENO) :
103 dup2 (pipedes[STDOUT_FILENO], STDOUT_FILENO)) < 0)
104 _exit (127);
106 /* Close the pipe descriptors. */
107 (void) close (pipedes[STDIN_FILENO]);
108 (void) close (pipedes[STDOUT_FILENO]);
110 /* Exec the shell. */
111 new_argv[0] = SH_NAME;
112 new_argv[1] = "-c";
113 new_argv[2] = command;
114 new_argv[3] = NULL;
115 (void) execve (SH_PATH, (char *const *) new_argv, environ);
116 /* Die if it failed. */
117 _exit (127);
120 /* We are the parent side. */
122 /* Close the irrelevant side of the pipe and open the relevant side as a
123 new stream. Mark our side of the pipe to close on exec, so new children
124 won't see it. */
125 if (*mode == 'r')
127 (void) close (pipedes[STDOUT_FILENO]);
128 (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
129 stream = fdopen (pipedes[STDIN_FILENO], mode);
131 else
133 (void) close (pipedes[STDIN_FILENO]);
134 (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
135 stream = fdopen (pipedes[STDOUT_FILENO], mode);
138 if (stream == NULL)
139 goto error;
141 child = (struct child *) malloc (sizeof (struct child));
142 if (child == NULL)
143 goto error;
146 /* Make sure STREAM has its functions set before
147 we try to squirrel them away in CHILD. */
148 extern void __stdio_check_funcs __P ((FILE *));
149 __stdio_check_funcs (stream);
152 child->pid = pid;
153 child->cookie = stream->__cookie;
154 child->funcs = stream->__io_funcs;
155 stream->__cookie = (void *) child;
156 stream->__io_funcs = child_funcs;
157 stream->__ispipe = 1;
158 return stream;
160 error:
162 /* The stream couldn't be opened or the child structure couldn't be
163 allocated. Kill the child and close the other side of the pipe. */
164 int save = errno;
165 (void) kill (pid, SIGKILL);
166 if (stream == NULL)
167 (void) close (pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
168 else
169 (void) fclose (stream);
170 #ifndef NO_WAITPID
171 (void) waitpid (pid, (int *) NULL, 0);
172 #else
174 pid_t dead;
176 dead = wait ((int *) NULL);
177 while (dead > 0 && dead != pid);
179 #endif
180 __set_errno (save);
181 return NULL;
185 /* Close a stream opened by popen and return its status.
186 Returns -1 if the stream was not opened by popen. */
188 pclose (stream)
189 register FILE *stream;
191 struct child *c;
192 pid_t pid, dead;
193 int status;
195 if (!__validfp (stream) || !stream->__ispipe)
197 __set_errno (EINVAL);
198 return -1;
201 c = (struct child *) stream->__cookie;
202 pid = c->pid;
203 stream->__cookie = c->cookie;
204 stream->__io_funcs = c->funcs;
205 free ((void *) c);
206 stream->__ispipe = 0;
207 if (fclose (stream))
208 return -1;
210 #ifndef NO_WAITPID
211 dead = waitpid (pid, &status, 0);
212 #else
214 dead = wait (&status);
215 while (dead > 0 && dead != pid);
216 #endif
217 if (dead != pid)
218 status = -1;
220 return status;