Formerly posix/pipestream.c.~8~
[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   child->pid = pid;
148   child->cookie = stream->__cookie;
149   child->funcs = stream->__io_funcs;
150   stream->__cookie = (PTR) child;
151   stream->__io_funcs = child_funcs;
152   stream->__ispipe = 1;
153   return stream;
154
155  error:;
156   {
157     /* The stream couldn't be opened or the child structure couldn't be
158        allocated.  Kill the child and close the other side of the pipe.  */
159     int save = errno;
160     (void) kill(pid, SIGKILL);
161     if (stream == NULL)
162       (void) close(pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
163     else
164       (void) fclose(stream);
165 #ifndef NO_WAITPID
166     (void) waitpid(pid, (int *) NULL, 0);
167 #else
168     {
169       pid_t dead;
170       do
171         dead = wait ((int *) NULL);
172       while (dead > 0 && dead != pid);
173     }
174 #endif
175     errno = save;
176     return NULL;
177   }
178 }
179 \f
180 /* Close a stream opened by popen and return its status.
181    Returns -1 if the stream was not opened by popen.  */
182 int
183 DEFUN(pclose, (stream), register FILE *stream)
184 {
185   struct child *c;
186   pid_t pid, dead;
187   int status;
188
189   if (!__validfp(stream) || !stream->__ispipe)
190     {
191       errno = EINVAL;
192       return -1;
193     }
194
195   c = (struct child *) stream->__cookie;
196   pid = c->pid;
197   stream->__cookie = c->cookie;
198   stream->__io_funcs = c->funcs;
199   free(stream->__cookie);
200   stream->__ispipe = 0;
201   if (fclose(stream))
202     return -1;
203
204 #ifndef NO_WAITPID
205   dead = waitpid (pid, &status, 0);
206 #else
207   do
208     dead = wait (&status);
209   while (dead > 0 && dead != pid);
210 #endif
211   if (dead != pid)
212     status = -1;
213
214   return status;
215 }