Formerly posix/pipestream.c.~6~
[kopensolaris-gnu/glibc.git] / sysdeps / posix / pipestream.c
1 /* Copyright (C) 1991, 1992 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     /* It is important that the first member of this structure be an `int' that
37        is the file descriptor.  This is because the `fileno' function assumes
38        that __cookie(STREAM) points to the file descriptor.  */
39     int fd;
40     pid_t pid;
41   };
42
43 /* Open a new stream that is a one-way pipe to a
44    child process running the given shell command.  */
45 FILE *
46 DEFUN(popen, (command, mode), CONST char *command AND CONST char *mode)
47 {
48   pid_t pid;
49   int pipedes[2];
50   FILE *stream;
51   struct child *child;
52
53   if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
54     {
55       errno = EINVAL;
56       return NULL;
57     }
58
59   /* Create the pipe.  */
60   if (pipe(pipedes) < 0)
61     return NULL;
62
63   /* Fork off the child.  */
64   pid = __vfork ();
65   if (pid == (pid_t) -1)
66     {
67       /* The fork failed.  */
68       (void) close (pipedes[0]);
69       (void) close (pipedes[1]);
70       return NULL;
71     }
72   else if (pid == (pid_t) 0)
73     {
74       /* We are the child side.  Make the write side of
75          the pipe be stdin or the read side be stdout.  */
76
77       CONST char *new_argv[4];
78
79       if ((*mode == 'w' ? dup2(pipedes[STDIN_FILENO], STDIN_FILENO) :
80           dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO)) < 0)
81         _exit(127);
82
83       /* Close the pipe descriptors.  */
84       (void) close(pipedes[STDIN_FILENO]);
85       (void) close(pipedes[STDOUT_FILENO]);
86
87       /* Exec the shell.  */
88       new_argv[0] = SH_NAME;
89       new_argv[1] = "-c";
90       new_argv[2] = command;
91       new_argv[3] = NULL;
92       (void) execve(SH_PATH, (char *CONST *) new_argv, environ);
93       /* Die if it failed.  */
94       _exit(127);
95     }
96
97   /* We are the parent side.  */
98
99   /* Close the irrelevant side of the pipe and open the relevant side as a
100      new stream.  Mark our side of the pipe to close on exec, so new children
101      won't see it.  */
102   if (*mode == 'r')
103     {
104       (void) close(pipedes[STDOUT_FILENO]);
105       (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
106       stream = fdopen(pipedes[STDIN_FILENO], mode);
107     }
108   else
109     {
110       (void) close(pipedes[STDIN_FILENO]);
111       (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
112       stream = fdopen(pipedes[STDOUT_FILENO], mode);
113     }
114
115   if (stream == NULL)
116     goto error;
117
118   child = (struct child *) malloc(sizeof(struct child));
119   if (child == NULL)
120     goto error;
121   child->fd = fileno(stream);
122   child->pid = pid;
123   stream->__cookie = (PTR) child;
124   stream->__ispipe = 1;
125   return stream;
126
127  error:;
128   {
129     /* The stream couldn't be opened or the child structure couldn't be
130        allocated.  Kill the child and close the other side of the pipe.  */
131     int save = errno;
132     (void) kill(pid, SIGKILL);
133     if (stream == NULL)
134       (void) close(pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
135     else
136       (void) fclose(stream);
137 #ifndef NO_WAITPID
138     (void) waitpid(pid, (int *) NULL, 0);
139 #else
140     {
141       pid_t dead;
142       do
143         dead = wait ((int *) NULL);
144       while (dead > 0 && dead != pid);
145     }
146 #endif
147     errno = save;
148     return NULL;
149   }
150 }
151 \f
152 /* Close a stream opened by popen and return its status.
153    Returns -1 if the stream was not opened by popen.  */
154 int
155 DEFUN(pclose, (stream), register FILE *stream)
156 {
157   pid_t pid, dead;
158   int status;
159
160   if (!__validfp(stream) || !stream->__ispipe)
161     {
162       errno = EINVAL;
163       return -1;
164     }
165
166   pid = ((struct child *) stream->__cookie)->pid;
167   free(stream->__cookie);
168   stream->__cookie = (PTR) &stream->__fileno;
169   stream->__ispipe = 0;
170   if (fclose(stream))
171     return -1;
172
173 #ifndef NO_WAITPID
174   dead = waitpid (pid, &status, 0);
175 #else
176   do
177     dead = wait (&status);
178   while (dead > 0 && dead != pid);
179 #endif
180   if (dead != pid)
181     status = -1;
182
183   return status;
184 }