- New function Buf_Append(), which is given a pointer to a string to
[dragonfly.git] / contrib / 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 #include "libioP.h"
28 #if _IO_HAVE_SYS_WAIT
29 #include <signal.h>
30 #include <unistd.h>
31 #ifdef __STDC__
32 #include <stdlib.h>
33 #endif
34 #ifdef _LIBC
35 # include <unistd.h>
36 #endif
37 #include <sys/types.h>
38 #include <sys/wait.h>
39
40 #ifndef _IO_fork
41 #define _IO_fork vfork /* defined in libiberty, if needed */
42 extern _IO_pid_t _IO_fork __P ((void));
43 #endif
44
45 #endif /* _IO_HAVE_SYS_WAIT */
46
47 #ifndef _IO_pipe
48 #define _IO_pipe pipe
49 extern int _IO_pipe __P ((int des[2]));
50 #endif
51
52 #ifndef _IO_dup2
53 #define _IO_dup2 dup2
54 extern int _IO_dup2 __P ((int fd, int fd2));
55 #endif
56
57 #ifndef _IO_waitpid
58 #define _IO_waitpid waitpid
59 #endif
60
61 #ifndef _IO_execl
62 #define _IO_execl execl
63 #endif
64 #ifndef _IO__exit
65 #define _IO__exit _exit
66 #endif
67
68 #ifndef _IO_close
69 #define _IO_close close
70 #endif
71
72 struct _IO_proc_file
73 {
74   struct _IO_FILE_plus file;
75   /* Following fields must match those in class procbuf (procbuf.h) */
76   _IO_pid_t pid;
77   struct _IO_proc_file *next;
78 };
79 typedef struct _IO_proc_file _IO_proc_file;
80
81 static struct _IO_proc_file *proc_file_chain = NULL;
82
83 _IO_FILE *
84 _IO_proc_open (fp, command, mode)
85      _IO_FILE *fp;
86      const char *command;
87      const char *mode;
88 {
89 #if _IO_HAVE_SYS_WAIT
90   volatile int read_or_write;
91   volatile int parent_end, child_end;
92   int pipe_fds[2];
93   _IO_pid_t child_pid;
94   if (_IO_file_is_open (fp))
95     return NULL;
96   if (_IO_pipe (pipe_fds) < 0)
97     return NULL;
98   if (mode[0] == 'r')
99     {
100       parent_end = pipe_fds[0];
101       child_end = pipe_fds[1];
102       read_or_write = _IO_NO_WRITES;
103     }
104   else
105     {
106       parent_end = pipe_fds[1];
107       child_end = pipe_fds[0];
108       read_or_write = _IO_NO_READS;
109     }
110   ((_IO_proc_file *) fp)->pid = child_pid = _IO_fork ();
111   if (child_pid == 0)
112     {
113       int child_std_end = mode[0] == 'r' ? 1 : 0;
114       _IO_close (parent_end);
115       if (child_end != child_std_end)
116         {
117           _IO_dup2 (child_end, child_std_end);
118           _IO_close (child_end);
119         }
120       /* POSIX.2:  "popen() shall ensure that any streams from previous
121          popen() calls that remain open in the parent process are closed
122          in the new child process." */
123       while (proc_file_chain)
124         {
125           _IO_close (_IO_fileno ((_IO_FILE *) proc_file_chain));
126           proc_file_chain = proc_file_chain->next;
127         }
128
129       _IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0);
130       _IO__exit (127);
131     }
132   _IO_close (child_end);
133   if (child_pid < 0)
134     {
135       _IO_close (parent_end);
136       return NULL;
137     }
138   _IO_fileno (fp) = parent_end;
139
140   /* Link into proc_file_chain. */
141   ((_IO_proc_file *) fp)->next = proc_file_chain;
142   proc_file_chain = (_IO_proc_file *) fp;
143
144   _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
145   return fp;
146 #else /* !_IO_HAVE_SYS_WAIT */
147   return NULL;
148 #endif
149 }
150
151 _IO_FILE *
152 _IO_popen (command, mode)
153      const char *command;
154      const char *mode;
155 {
156   struct locked_FILE
157   {
158     struct _IO_proc_file fpx;
159 #ifdef _IO_MTSAFE_IO
160     _IO_lock_t lock;
161 #endif
162   } *new_f;
163   _IO_FILE *fp;
164
165   new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
166   if (new_f == NULL)
167     return NULL;
168 #ifdef _IO_MTSAFE_IO
169   new_f->fpx.file.file._lock = &new_f->lock;
170 #endif
171   fp = (_IO_FILE*)&new_f->fpx;
172   _IO_init (fp, 0);
173   _IO_JUMPS (fp) = &_IO_proc_jumps;
174   _IO_file_init (fp);
175 #if  !_IO_UNIFIED_JUMPTABLES
176   ((struct _IO_FILE_plus *) fp)->vtable = NULL;
177 #endif
178   if (_IO_proc_open (fp, command, mode) != NULL)
179     return fp;
180   free (new_f);
181   return NULL;
182 }
183
184 #ifdef strong_alias
185 strong_alias (_IO_popen, popen);
186 #endif
187
188 int
189 _IO_proc_close (fp)
190      _IO_FILE *fp;
191 {
192   /* This is not name-space clean. FIXME! */
193 #if _IO_HAVE_SYS_WAIT
194   int wstatus;
195   _IO_proc_file **ptr = &proc_file_chain;
196   _IO_pid_t wait_pid;
197   int status = -1;
198
199   /* Unlink from proc_file_chain. */
200   for ( ; *ptr != NULL; ptr = &(*ptr)->next)
201     {
202       if (*ptr == (_IO_proc_file *) fp)
203         {
204           *ptr = (*ptr)->next;
205           status = 0;
206           break;
207         }
208     }
209
210   if (status < 0 || _IO_close (_IO_fileno(fp)) < 0)
211     return -1;
212   /* POSIX.2 Rationale:  "Some historical implementations either block
213      or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
214      for the child process to terminate.  Since this behavior is not
215      described in POSIX.2, such implementations are not conforming." */
216   do
217     {
218       wait_pid = _IO_waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
219     }
220   while (wait_pid == -1 && errno == EINTR);
221   if (wait_pid == -1)
222     return -1;
223   return wstatus;
224 #else /* !_IO_HAVE_SYS_WAIT */
225   return -1;
226 #endif
227 }
228
229 struct _IO_jump_t _IO_proc_jumps = {
230   JUMP_INIT_DUMMY,
231   JUMP_INIT(finish, _IO_file_finish),
232   JUMP_INIT(overflow, _IO_file_overflow),
233   JUMP_INIT(underflow, _IO_file_underflow),
234   JUMP_INIT(uflow, _IO_default_uflow),
235   JUMP_INIT(pbackfail, _IO_default_pbackfail),
236   JUMP_INIT(xsputn, _IO_file_xsputn),
237   JUMP_INIT(xsgetn, _IO_default_xsgetn),
238   JUMP_INIT(seekoff, _IO_file_seekoff),
239   JUMP_INIT(seekpos, _IO_default_seekpos),
240   JUMP_INIT(setbuf, _IO_file_setbuf),
241   JUMP_INIT(sync, _IO_file_sync),
242   JUMP_INIT(doallocate, _IO_file_doallocate),
243   JUMP_INIT(read, _IO_file_read),
244   JUMP_INIT(write, _IO_file_write),
245   JUMP_INIT(seek, _IO_file_seek),
246   JUMP_INIT(close, _IO_proc_close),
247   JUMP_INIT(stat, _IO_file_stat)
248 };