xref: /haiku/src/system/libroot/posix/glibc/libio/iopopen.c (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 /* Copyright (C) 1993, 1997-2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Written by Per Bothner <bothner@cygnus.com>.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.
19 
20    As a special exception, if you link the code in this file with
21    files compiled with a GNU compiler to produce an executable,
22    that does not cause the resulting executable to be covered by
23    the GNU Lesser General Public License.  This exception does not
24    however invalidate any other reasons why the executable file
25    might be covered by the GNU Lesser General Public License.
26    This exception applies to code released by its copyright holders
27    in files containing the exception.  */
28 
29 #ifndef _POSIX_SOURCE
30 # define _POSIX_SOURCE
31 #endif
32 
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include "libioP.h"
36 #if _IO_HAVE_SYS_WAIT
37 #include <signal.h>
38 #include <unistd.h>
39 #ifdef __STDC__
40 #include <stdlib.h>
41 #endif
42 #ifdef _LIBC
43 # include <unistd.h>
44 # include <shlib-compat.h>
45 #endif
46 
47 #endif /* _IO_HAVE_SYS_WAIT */
48 
49 #ifndef _IO_close
50 #	define _IO_close close
51 #endif
52 
53 struct _IO_proc_file
54 {
55   struct _IO_FILE_plus file;
56   /* Following fields must match those in class procbuf (procbuf.h) */
57   _IO_pid_t pid;
58   struct _IO_proc_file *next;
59 };
60 typedef struct _IO_proc_file _IO_proc_file;
61 
62 static struct _IO_jump_t _IO_proc_jumps;
63 static struct _IO_jump_t _IO_wproc_jumps;
64 
65 static struct _IO_proc_file *proc_file_chain;
66 
67 #ifdef _IO_MTSAFE_IO
68 static _IO_lock_t proc_file_chain_lock = _IO_lock_initializer;
69 
70 #if 0
71 static void
72 unlock (void *not_used)
73 {
74   _IO_lock_unlock (proc_file_chain_lock);
75 }
76 #endif
77 #endif
78 
79 _IO_FILE *
80 _IO_new_proc_open (fp, command, mode)
81      _IO_FILE *fp;
82      const char *command;
83      const char *mode;
84 {
85 #if _IO_HAVE_SYS_WAIT
86   volatile int read_or_write;
87   volatile int parent_end, child_end;
88   int pipe_fds[2];
89   _IO_pid_t child_pid;
90   if (_IO_file_is_open (fp))
91     return NULL;
92   if (pipe(pipe_fds) < 0)
93     return NULL;
94   if (mode[0] == 'r' && mode[1] == '\0')
95     {
96       parent_end = pipe_fds[0];
97       child_end = pipe_fds[1];
98       read_or_write = _IO_NO_WRITES;
99     }
100   else if (mode[0] == 'w' && mode[1] == '\0')
101     {
102       parent_end = pipe_fds[1];
103       child_end = pipe_fds[0];
104       read_or_write = _IO_NO_READS;
105     }
106   else
107     {
108       _IO_close (pipe_fds[0]);
109       _IO_close (pipe_fds[1]);
110       __set_errno (EINVAL);
111       return NULL;
112     }
113   ((_IO_proc_file *) fp)->pid = child_pid = fork();
114   if (child_pid == 0)
115     {
116       int child_std_end = mode[0] == 'r' ? 1 : 0;
117       struct _IO_proc_file *p;
118 
119       _IO_close (parent_end);
120       if (child_end != child_std_end)
121 	{
122 	  dup2(child_end, child_std_end);
123 	  _IO_close (child_end);
124 	}
125       /* POSIX.2:  "popen() shall ensure that any streams from previous
126          popen() calls that remain open in the parent process are closed
127 	 in the new child process." */
128       for (p = proc_file_chain; p; p = p->next)
129 	_IO_close (_IO_fileno ((_IO_FILE *) p));
130 
131       execl("/bin/sh", "sh", "-c", command, (char *)0);
132       _exit(127);
133     }
134   _IO_close (child_end);
135   if (child_pid < 0)
136     {
137       _IO_close (parent_end);
138       return NULL;
139     }
140   _IO_fileno (fp) = parent_end;
141 
142   /* Link into proc_file_chain. */
143 #ifdef _IO_MTSAFE_IO
144   _IO_cleanup_region_start_noarg (unlock);
145   _IO_lock_lock (proc_file_chain_lock);
146 #endif
147   ((_IO_proc_file *) fp)->next = proc_file_chain;
148   proc_file_chain = (_IO_proc_file *) fp;
149 #ifdef _IO_MTSAFE_IO
150   _IO_lock_unlock (proc_file_chain_lock);
151   _IO_cleanup_region_end (0);
152 #endif
153 
154   _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
155   return fp;
156 #else /* !_IO_HAVE_SYS_WAIT */
157   return NULL;
158 #endif
159 }
160 
161 _IO_FILE *
162 _IO_new_popen (command, mode)
163      const char *command;
164      const char *mode;
165 {
166   struct locked_FILE
167   {
168     struct _IO_proc_file fpx;
169 #ifdef _IO_MTSAFE_IO
170     _IO_lock_t lock;
171 #endif
172     struct _IO_wide_data wd;
173   } *new_f;
174   _IO_FILE *fp;
175 
176   new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
177   if (new_f == NULL)
178     return NULL;
179 #ifdef _IO_MTSAFE_IO
180   new_f->fpx.file.file._lock = &new_f->lock;
181 #endif
182   fp = &new_f->fpx.file.file;
183   _IO_no_init (fp, 0, 0, &new_f->wd, &_IO_wproc_jumps);
184   _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps;
185   _IO_new_file_init (&new_f->fpx.file);
186 #if  !_IO_UNIFIED_JUMPTABLES
187   new_f->fpx.file.vtable = NULL;
188 #endif
189   if (_IO_new_proc_open (fp, command, mode) != NULL)
190     return (_IO_FILE *) &new_f->fpx.file;
191   INTUSE(_IO_un_link) (&new_f->fpx.file);
192   free (new_f);
193   return NULL;
194 }
195 
196 int
197 _IO_new_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 #ifdef _IO_MTSAFE_IO
209   _IO_cleanup_region_start_noarg (unlock);
210   _IO_lock_lock (proc_file_chain_lock);
211 #endif
212   for ( ; *ptr != NULL; ptr = &(*ptr)->next)
213     {
214       if (*ptr == (_IO_proc_file *) fp)
215 	{
216 	  *ptr = (*ptr)->next;
217 	  status = 0;
218 	  break;
219 	}
220     }
221 #ifdef _IO_MTSAFE_IO
222   _IO_lock_unlock (proc_file_chain_lock);
223   _IO_cleanup_region_end (0);
224 #endif
225 
226   if (status < 0 || _IO_close (_IO_fileno(fp)) < 0)
227     return -1;
228   /* POSIX.2 Rationale:  "Some historical implementations either block
229      or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
230      for the child process to terminate.  Since this behavior is not
231      described in POSIX.2, such implementations are not conforming." */
232   do
233     {
234       wait_pid = waitpid(((_IO_proc_file *) fp)->pid, &wstatus, 0);
235     }
236   while (wait_pid == -1 && errno == EINTR);
237   if (wait_pid == -1)
238     return -1;
239   return wstatus;
240 #else /* !_IO_HAVE_SYS_WAIT */
241   return -1;
242 #endif
243 }
244 
245 static struct _IO_jump_t _IO_proc_jumps = {
246   JUMP_INIT_DUMMY,
247   JUMP_INIT(finish, _IO_new_file_finish),
248   JUMP_INIT(overflow, _IO_new_file_overflow),
249   JUMP_INIT(underflow, _IO_new_file_underflow),
250   JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
251   JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
252   JUMP_INIT(xsputn, _IO_new_file_xsputn),
253   JUMP_INIT(xsgetn, INTUSE(_IO_default_xsgetn)),
254   JUMP_INIT(seekoff, _IO_new_file_seekoff),
255   JUMP_INIT(seekpos, _IO_default_seekpos),
256   JUMP_INIT(setbuf, _IO_new_file_setbuf),
257   JUMP_INIT(sync, _IO_new_file_sync),
258   JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
259   JUMP_INIT(read, INTUSE(_IO_file_read)),
260   JUMP_INIT(write, _IO_new_file_write),
261   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
262   JUMP_INIT(close, _IO_new_proc_close),
263   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
264   JUMP_INIT(showmanyc, _IO_default_showmanyc),
265   JUMP_INIT(imbue, _IO_default_imbue)
266 };
267 
268 static struct _IO_jump_t _IO_wproc_jumps = {
269   JUMP_INIT_DUMMY,
270   JUMP_INIT(finish, _IO_new_file_finish),
271   JUMP_INIT(overflow, _IO_new_file_overflow),
272   JUMP_INIT(underflow, _IO_new_file_underflow),
273   JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
274   JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
275   JUMP_INIT(xsputn, _IO_new_file_xsputn),
276   JUMP_INIT(xsgetn, INTUSE(_IO_default_xsgetn)),
277   JUMP_INIT(seekoff, _IO_new_file_seekoff),
278   JUMP_INIT(seekpos, _IO_default_seekpos),
279   JUMP_INIT(setbuf, _IO_new_file_setbuf),
280   JUMP_INIT(sync, _IO_new_file_sync),
281   JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
282   JUMP_INIT(read, INTUSE(_IO_file_read)),
283   JUMP_INIT(write, _IO_new_file_write),
284   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
285   JUMP_INIT(close, _IO_new_proc_close),
286   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
287   JUMP_INIT(showmanyc, _IO_default_showmanyc),
288   JUMP_INIT(imbue, _IO_default_imbue)
289 };
290 
291 strong_alias (_IO_new_popen, __new_popen)
292 versioned_symbol (libc, _IO_new_popen, _IO_popen, GLIBC_2_1);
293 versioned_symbol (libc, __new_popen, popen, GLIBC_2_1);
294 versioned_symbol (libc, _IO_new_proc_open, _IO_proc_open, GLIBC_2_1);
295 versioned_symbol (libc, _IO_new_proc_close, _IO_proc_close, GLIBC_2_1);
296