Update.
[platform/upstream/glibc.git] / sysdeps / posix / pipestream.c
1 /* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
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.  */
18
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>
28
29 #define SH_PATH "/bin/sh"       /* Shell to run.  */
30 #define SH_NAME "sh"            /* Name to give it.  */
31
32 /* Structure describing a popen child.  */
33 struct child
34   {
35     pid_t pid;                  /* PID of the child.  */
36     __ptr_t cookie;             /* Original cookie from fdopen.  */
37     __io_functions funcs;       /* Original functions from fdopen.  */
38   };
39
40 /* io_functions for pipe streams.
41    These all simply call the corresponding
42    original function with the original cookie.  */
43
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     }                                                                         \
52   }
53
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))
60
61 static const __io_functions child_funcs
62   = { child_read, child_write, child_seek, child_close, child_fileno };
63 \f
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;
70 {
71   pid_t pid;
72   int pipedes[2];
73   FILE *stream;
74   struct child *child;
75
76   if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
77     {
78       __set_errno (EINVAL);
79       return NULL;
80     }
81
82   /* Create the pipe.  */
83   if (pipe (pipedes) < 0)
84     return NULL;
85
86   /* Fork off the child.  */
87   pid = __vfork ();
88   if (pid == (pid_t) -1)
89     {
90       /* The fork failed.  */
91       (void) close (pipedes[0]);
92       (void) close (pipedes[1]);
93       return NULL;
94     }
95   else if (pid == (pid_t) 0)
96     {
97       /* We are the child side.  Make the write side of
98          the pipe be stdin or the read side be stdout.  */
99
100       const char *new_argv[4];
101
102       if ((*mode == 'w' ? dup2(pipedes[STDIN_FILENO], STDIN_FILENO) :
103           dup2 (pipedes[STDOUT_FILENO], STDOUT_FILENO)) < 0)
104         _exit (127);
105
106       /* Close the pipe descriptors.  */
107       (void) close (pipedes[STDIN_FILENO]);
108       (void) close (pipedes[STDOUT_FILENO]);
109
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);
118     }
119
120   /* We are the parent side.  */
121
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')
126     {
127       (void) close (pipedes[STDOUT_FILENO]);
128       (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
129       stream = fdopen (pipedes[STDIN_FILENO], mode);
130     }
131   else
132     {
133       (void) close (pipedes[STDIN_FILENO]);
134       (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
135       stream = fdopen (pipedes[STDOUT_FILENO], mode);
136     }
137
138   if (stream == NULL)
139     goto error;
140
141   child = (struct child *) malloc (sizeof (struct child));
142   if (child == NULL)
143     goto error;
144
145   {
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);
150   }
151
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;
159
160  error:
161   {
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
173     {
174       pid_t dead;
175       do
176         dead = wait ((int *) NULL);
177       while (dead > 0 && dead != pid);
178     }
179 #endif
180     __set_errno (save);
181     return NULL;
182   }
183 }
184 \f
185 /* Close a stream opened by popen and return its status.
186    Returns -1 if the stream was not opened by popen.  */
187 int
188 pclose (stream)
189      register FILE *stream;
190 {
191   struct child *c;
192   pid_t pid, dead;
193   int status;
194
195   if (!__validfp (stream) || !stream->__ispipe)
196     {
197       __set_errno (EINVAL);
198       return -1;
199     }
200
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;
209
210 #ifndef NO_WAITPID
211   dead = waitpid (pid, &status, 0);
212 #else
213   do
214     dead = wait (&status);
215   while (dead > 0 && dead != pid);
216 #endif
217   if (dead != pid)
218     status = -1;
219
220   return status;
221 }