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 */
42extern _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
49extern int _IO_pipe __P ((int des[2]));
50#endif
51
52#ifndef _IO_dup2
53#define _IO_dup2 dup2
54extern 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
72struct _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};
79typedef struct _IO_proc_file _IO_proc_file;
80
81static 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
185strong_alias (_IO_popen, popen);
186#endif
187
188int
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
229struct _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};
249