Update from db 2.4.14.
[kopensolaris-gnu/glibc.git] / libio / iopopen.c
1 /* Copyright (C) 1993, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU IO Library.
3    Written by Per Bothner <bothner@cygnus.com>.
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2, or (at
8    your option) any later version.
9
10    This library is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this library; see the file COPYING.  If not, write to
17    the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
18    MA 02111-1307, USA.
19
20    As a special exception, if you link this library with files
21    compiled with a GNU compiler to produce an executable, this does
22    not cause the resulting executable to be covered by the GNU General
23    Public License.  This exception does not however invalidate any
24    other reasons why the executable file might be covered by the GNU
25    General Public License.  */
26
27 #ifndef _POSIX_SOURCE
28 # define _POSIX_SOURCE
29 #endif
30 #include "libioP.h"
31 #if _IO_HAVE_SYS_WAIT
32 #include <signal.h>
33 #include <unistd.h>
34 #ifdef __STDC__
35 #include <stdlib.h>
36 #endif
37 #ifdef _LIBC
38 # include <unistd.h>
39 #endif
40 #include <sys/types.h>
41 #include <sys/wait.h>
42
43 #ifndef _IO_fork
44 #define _IO_fork vfork /* defined in libiberty, if needed */
45 extern _IO_pid_t _IO_fork __P ((void));
46 #endif
47
48 #endif /* _IO_HAVE_SYS_WAIT */
49
50 #ifndef _IO_pipe
51 #define _IO_pipe pipe
52 extern int _IO_pipe __P ((int des[2]));
53 #endif
54
55 #ifndef _IO_dup2
56 #define _IO_dup2 dup2
57 extern int _IO_dup2 __P ((int fd, int fd2));
58 #endif
59
60 #ifndef _IO_waitpid
61 #define _IO_waitpid waitpid
62 #endif
63
64 #ifndef _IO_execl
65 #define _IO_execl execl
66 #endif
67 #ifndef _IO__exit
68 #define _IO__exit _exit
69 #endif
70
71 #ifndef _IO_close
72 #define _IO_close close
73 #endif
74
75 struct _IO_proc_file
76 {
77   struct _IO_FILE_plus file;
78   /* Following fields must match those in class procbuf (procbuf.h) */
79   _IO_pid_t pid;
80   struct _IO_proc_file *next;
81 };
82 typedef struct _IO_proc_file _IO_proc_file;
83
84 static struct _IO_proc_file *proc_file_chain = NULL;
85
86 _IO_FILE *
87 _IO_proc_open (fp, command, mode)
88      _IO_FILE *fp;
89      const char *command;
90      const char *mode;
91 {
92 #if _IO_HAVE_SYS_WAIT
93   volatile int read_or_write;
94   volatile int parent_end, child_end;
95   int pipe_fds[2];
96   _IO_pid_t child_pid;
97   if (_IO_file_is_open (fp))
98     return NULL;
99   if (_IO_pipe (pipe_fds) < 0)
100     return NULL;
101   if (mode[0] == 'r' && mode[1] == '\0')
102     {
103       parent_end = pipe_fds[0];
104       child_end = pipe_fds[1];
105       read_or_write = _IO_NO_WRITES;
106     }
107   else if (mode[0] == 'w' && mode[1] == '\0')
108     {
109       parent_end = pipe_fds[1];
110       child_end = pipe_fds[0];
111       read_or_write = _IO_NO_READS;
112     }
113   else
114     {
115       __set_errno (EINVAL);
116       return NULL;
117     }
118   ((_IO_proc_file *) fp)->pid = child_pid = _IO_fork ();
119   if (child_pid == 0)
120     {
121       int child_std_end = mode[0] == 'r' ? 1 : 0;
122       _IO_close (parent_end);
123       if (child_end != child_std_end)
124         {
125           _IO_dup2 (child_end, child_std_end);
126           _IO_close (child_end);
127         }
128       /* POSIX.2:  "popen() shall ensure that any streams from previous
129          popen() calls that remain open in the parent process are closed
130          in the new child process." */
131       while (proc_file_chain)
132         {
133           _IO_close (_IO_fileno ((_IO_FILE *) proc_file_chain));
134           proc_file_chain = proc_file_chain->next;
135         }
136
137       _IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0);
138       _IO__exit (127);
139     }
140   _IO_close (child_end);
141   if (child_pid < 0)
142     {
143       _IO_close (parent_end);
144       return NULL;
145     }
146   _IO_fileno (fp) = parent_end;
147
148   /* Link into proc_file_chain. */
149   ((_IO_proc_file *) fp)->next = proc_file_chain;
150   proc_file_chain = (_IO_proc_file *) fp;
151
152   _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
153   return fp;
154 #else /* !_IO_HAVE_SYS_WAIT */
155   return NULL;
156 #endif
157 }
158
159 _IO_FILE *
160 _IO_popen (command, mode)
161      const char *command;
162      const char *mode;
163 {
164   struct locked_FILE
165   {
166     struct _IO_proc_file fpx;
167 #ifdef _IO_MTSAFE_IO
168     _IO_lock_t lock;
169 #endif
170   } *new_f;
171   _IO_FILE *fp;
172
173   new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
174   if (new_f == NULL)
175     return NULL;
176 #ifdef _IO_MTSAFE_IO
177   new_f->fpx.file.file._lock = &new_f->lock;
178 #endif
179   fp = (_IO_FILE*)&new_f->fpx;
180   _IO_init (fp, 0);
181   _IO_JUMPS (fp) = &_IO_proc_jumps;
182   _IO_file_init (fp);
183 #if  !_IO_UNIFIED_JUMPTABLES
184   ((struct _IO_FILE_plus *) fp)->vtable = NULL;
185 #endif
186   if (_IO_proc_open (fp, command, mode) != NULL)
187     return fp;
188   free (new_f);
189   return NULL;
190 }
191
192 #ifdef strong_alias
193 strong_alias (_IO_popen, popen);
194 #endif
195
196 int
197 _IO_proc_close (fp)
198      _IO_FILE *fp;
199 {
200   /* This is not name-space clean. FIXME! */
201 #if _IO_HAVE_SYS_WAIT
202   int wstatus;
203   _IO_proc_file **ptr = &proc_file_chain;
204   _IO_pid_t wait_pid;
205   int status = -1;
206
207   /* Unlink from proc_file_chain. */
208   for ( ; *ptr != NULL; ptr = &(*ptr)->next)
209     {
210       if (*ptr == (_IO_proc_file *) fp)
211         {
212           *ptr = (*ptr)->next;
213           status = 0;
214           break;
215         }
216     }
217
218   if (status < 0 || _IO_close (_IO_fileno(fp)) < 0)
219     return -1;
220   /* POSIX.2 Rationale:  "Some historical implementations either block
221      or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
222      for the child process to terminate.  Since this behavior is not
223      described in POSIX.2, such implementations are not conforming." */
224   do
225     {
226       wait_pid = _IO_waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
227     }
228   while (wait_pid == -1 && errno == EINTR);
229   if (wait_pid == -1)
230     return -1;
231   return wstatus;
232 #else /* !_IO_HAVE_SYS_WAIT */
233   return -1;
234 #endif
235 }
236
237 struct _IO_jump_t _IO_proc_jumps = {
238   JUMP_INIT_DUMMY,
239   JUMP_INIT(finish, _IO_file_finish),
240   JUMP_INIT(overflow, _IO_file_overflow),
241   JUMP_INIT(underflow, _IO_file_underflow),
242   JUMP_INIT(uflow, _IO_default_uflow),
243   JUMP_INIT(pbackfail, _IO_default_pbackfail),
244   JUMP_INIT(xsputn, _IO_file_xsputn),
245   JUMP_INIT(xsgetn, _IO_default_xsgetn),
246   JUMP_INIT(seekoff, _IO_file_seekoff),
247   JUMP_INIT(seekpos, _IO_default_seekpos),
248   JUMP_INIT(setbuf, _IO_file_setbuf),
249   JUMP_INIT(sync, _IO_file_sync),
250   JUMP_INIT(doallocate, _IO_file_doallocate),
251   JUMP_INIT(read, _IO_file_read),
252   JUMP_INIT(write, _IO_file_write),
253   JUMP_INIT(seek, _IO_file_seek),
254   JUMP_INIT(close, _IO_proc_close),
255   JUMP_INIT(stat, _IO_file_stat),
256   JUMP_INIT(showmanyc, _IO_default_showmanyc),
257   JUMP_INIT(imbue, _IO_default_imbue)
258 };