Mon Jun 24 19:57:01 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / sysdeps / posix / pipestream.c
1 /* Copyright (C) 1991, 1992, 1993 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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
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>
29
30 #define SH_PATH "/bin/sh"       /* Shell to run.  */
31 #define SH_NAME "sh"            /* Name to give it.  */
32
33 /* Structure describing a popen child.  */
34 struct child
35   {
36     pid_t pid;                  /* PID of the child.  */
37     __ptr_t cookie;             /* Original cookie from fdopen.  */
38     __io_functions funcs;       /* Original functions from fdopen.  */
39   };
40
41 /* io_functions for pipe streams.
42    These all simply call the corresponding
43    original function with the original cookie.  */
44
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     }                                                                         \
53   }
54
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))
65
66 static const __io_functions child_funcs
67   = { child_read, child_write, child_seek, child_close, child_fileno };
68 \f
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)
73 {
74   pid_t pid;
75   int pipedes[2];
76   FILE *stream;
77   struct child *child;
78
79   if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
80     {
81       errno = EINVAL;
82       return NULL;
83     }
84
85   /* Create the pipe.  */
86   if (pipe(pipedes) < 0)
87     return NULL;
88
89   /* Fork off the child.  */
90   pid = __vfork ();
91   if (pid == (pid_t) -1)
92     {
93       /* The fork failed.  */
94       (void) close (pipedes[0]);
95       (void) close (pipedes[1]);
96       return NULL;
97     }
98   else if (pid == (pid_t) 0)
99     {
100       /* We are the child side.  Make the write side of
101          the pipe be stdin or the read side be stdout.  */
102
103       CONST char *new_argv[4];
104
105       if ((*mode == 'w' ? dup2(pipedes[STDIN_FILENO], STDIN_FILENO) :
106           dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO)) < 0)
107         _exit(127);
108
109       /* Close the pipe descriptors.  */
110       (void) close(pipedes[STDIN_FILENO]);
111       (void) close(pipedes[STDOUT_FILENO]);
112
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);
121     }
122
123   /* We are the parent side.  */
124
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')
129     {
130       (void) close (pipedes[STDOUT_FILENO]);
131       (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
132       stream = fdopen (pipedes[STDIN_FILENO], mode);
133     }
134   else
135     {
136       (void) close (pipedes[STDIN_FILENO]);
137       (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
138       stream = fdopen (pipedes[STDOUT_FILENO], mode);
139     }
140
141   if (stream == NULL)
142     goto error;
143
144   child = (struct child *) malloc (sizeof (struct child));
145   if (child == NULL)
146     goto error;
147
148   {
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);
153   }
154
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;
162
163  error:
164   {
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
176     {
177       pid_t dead;
178       do
179         dead = wait ((int *) NULL);
180       while (dead > 0 && dead != pid);
181     }
182 #endif
183     errno = save;
184     return NULL;
185   }
186 }
187 \f
188 /* Close a stream opened by popen and return its status.
189    Returns -1 if the stream was not opened by popen.  */
190 int
191 DEFUN(pclose, (stream), register FILE *stream)
192 {
193   struct child *c;
194   pid_t pid, dead;
195   int status;
196
197   if (!__validfp(stream) || !stream->__ispipe)
198     {
199       errno = EINVAL;
200       return -1;
201     }
202
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;
211
212 #ifndef NO_WAITPID
213   dead = waitpid (pid, &status, 0);
214 #else
215   do
216     dead = wait (&status);
217   while (dead > 0 && dead != pid);
218 #endif
219   if (dead != pid)
220     status = -1;
221
222   return status;
223 }