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
53struct _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};
60typedef struct _IO_proc_file _IO_proc_file;
61
62static struct _IO_jump_t _IO_proc_jumps;
63static struct _IO_jump_t _IO_wproc_jumps;
64
65static struct _IO_proc_file *proc_file_chain;
66
67#ifdef _IO_MTSAFE_IO
68static _IO_lock_t proc_file_chain_lock = _IO_lock_initializer;
69
70#if 0
71static void
72unlock (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
196int
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
245static 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
268static 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
291strong_alias (_IO_new_popen, __new_popen)
292versioned_symbol (libc, _IO_new_popen, _IO_popen, GLIBC_2_1);
293versioned_symbol (libc, __new_popen, popen, GLIBC_2_1);
294versioned_symbol (libc, _IO_new_proc_open, _IO_proc_open, GLIBC_2_1);
295versioned_symbol (libc, _IO_new_proc_close, _IO_proc_close, GLIBC_2_1);
296