1 /* Copyright (C) 1998-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.
17 
18    As a special exception, if you link the code in this file with
19    files compiled with a GNU compiler to produce an executable,
20    that does not cause the resulting executable to be covered by
21    the GNU Lesser General Public License.  This exception does not
22    however invalidate any other reasons why the executable file
23    might be covered by the GNU Lesser General Public License.
24    This exception applies to code released by its copyright holders
25    in files containing the exception.  */
26 
27 #define _IO_USE_OLD_IO_FILE
28 #include "libioP.h"
29 #include <signal.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 
36 #include <shlib-compat.h>
37 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
38 
39 struct _IO_proc_file
40 {
41   struct _IO_FILE_complete_plus file;
42   /* Following fields must match those in class procbuf (procbuf.h) */
43   pid_t pid;
44   struct _IO_proc_file *next;
45 };
46 typedef struct _IO_proc_file _IO_proc_file;
47 
48 static struct _IO_proc_file *old_proc_file_chain;
49 
50 #ifdef _IO_MTSAFE_IO
51 static _IO_lock_t proc_file_chain_lock = _IO_lock_initializer;
52 
53 static void
unlock(void * not_used)54 unlock (void *not_used)
55 {
56   _IO_lock_unlock (proc_file_chain_lock);
57 }
58 #endif
59 
60 FILE *
61 attribute_compat_text_section
_IO_old_proc_open(FILE * fp,const char * command,const char * mode)62 _IO_old_proc_open (FILE *fp, const char *command, const char *mode)
63 {
64   volatile int read_or_write;
65   volatile int parent_end, child_end;
66   int pipe_fds[2];
67   pid_t child_pid;
68   if (_IO_file_is_open (fp))
69     return NULL;
70   if (__pipe (pipe_fds) < 0)
71     return NULL;
72   if (mode[0] == 'r' && mode[1] == '\0')
73     {
74       parent_end = pipe_fds[0];
75       child_end = pipe_fds[1];
76       read_or_write = _IO_NO_WRITES;
77     }
78   else if (mode[0] == 'w' && mode[1] == '\0')
79     {
80       parent_end = pipe_fds[1];
81       child_end = pipe_fds[0];
82       read_or_write = _IO_NO_READS;
83     }
84   else
85     {
86       __close (pipe_fds[0]);
87       __close (pipe_fds[1]);
88       __set_errno (EINVAL);
89       return NULL;
90     }
91   ((_IO_proc_file *) fp)->pid = child_pid = __fork ();
92   if (child_pid == 0)
93     {
94       int child_std_end = mode[0] == 'r' ? 1 : 0;
95       struct _IO_proc_file *p;
96 
97       __close (parent_end);
98       if (child_end != child_std_end)
99 	{
100 	  __dup2 (child_end, child_std_end);
101 	  __close (child_end);
102 	}
103       /* POSIX.2:  "popen() shall ensure that any streams from previous
104          popen() calls that remain open in the parent process are closed
105 	 in the new child process." */
106       for (p = old_proc_file_chain; p; p = p->next)
107 	__close (_IO_fileno ((FILE *) p));
108 
109       execl ("/bin/sh", "sh", "-c", command, (char *) 0);
110       _exit (127);
111     }
112   __close (child_end);
113   if (child_pid < 0)
114     {
115       __close (parent_end);
116       return NULL;
117     }
118   _IO_fileno (fp) = parent_end;
119 
120   /* Link into old_proc_file_chain. */
121 #ifdef _IO_MTSAFE_IO
122   _IO_cleanup_region_start_noarg (unlock);
123   _IO_lock_lock (proc_file_chain_lock);
124 #endif
125   ((_IO_proc_file *) fp)->next = old_proc_file_chain;
126   old_proc_file_chain = (_IO_proc_file *) fp;
127 #ifdef _IO_MTSAFE_IO
128   _IO_lock_unlock (proc_file_chain_lock);
129   _IO_cleanup_region_end (0);
130 #endif
131 
132   _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
133   return fp;
134 }
135 
136 FILE *
137 attribute_compat_text_section
_IO_old_popen(const char * command,const char * mode)138 _IO_old_popen (const char *command, const char *mode)
139 {
140   struct locked_FILE
141   {
142     struct _IO_proc_file fpx;
143 #ifdef _IO_MTSAFE_IO
144     _IO_lock_t lock;
145 #endif
146   } *new_f;
147   FILE *fp;
148 
149   new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
150   if (new_f == NULL)
151     return NULL;
152 #ifdef _IO_MTSAFE_IO
153   new_f->fpx.file.file._file._lock = &new_f->lock;
154 #endif
155   fp = &new_f->fpx.file.file._file;
156   _IO_old_init (fp, 0);
157   _IO_JUMPS_FILE_plus (&new_f->fpx.file) = &_IO_old_proc_jumps;
158   _IO_old_file_init_internal ((struct _IO_FILE_plus *) &new_f->fpx.file);
159   if (_IO_old_proc_open (fp, command, mode) != NULL)
160     return fp;
161   _IO_un_link ((struct _IO_FILE_plus *) &new_f->fpx.file);
162   free (new_f);
163   return NULL;
164 }
165 
166 int
167 attribute_compat_text_section
_IO_old_proc_close(FILE * fp)168 _IO_old_proc_close (FILE *fp)
169 {
170   /* This is not name-space clean. FIXME! */
171   int wstatus;
172   _IO_proc_file **ptr = &old_proc_file_chain;
173   pid_t wait_pid;
174   int status = -1;
175 
176   /* Unlink from old_proc_file_chain. */
177 #ifdef _IO_MTSAFE_IO
178   _IO_cleanup_region_start_noarg (unlock);
179   _IO_lock_lock (proc_file_chain_lock);
180 #endif
181   for ( ; *ptr != NULL; ptr = &(*ptr)->next)
182     {
183       if (*ptr == (_IO_proc_file *) fp)
184 	{
185 	  *ptr = (*ptr)->next;
186 	  status = 0;
187 	  break;
188 	}
189     }
190 #ifdef _IO_MTSAFE_IO
191   _IO_lock_unlock (proc_file_chain_lock);
192   _IO_cleanup_region_end (0);
193 #endif
194 
195   if (status < 0 || __close (_IO_fileno(fp)) < 0)
196     return -1;
197   /* POSIX.2 Rationale:  "Some historical implementations either block
198      or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
199      for the child process to terminate.  Since this behavior is not
200      described in POSIX.2, such implementations are not conforming." */
201   do
202     {
203       wait_pid = __waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
204     }
205   while (wait_pid == -1 && errno == EINTR);
206   if (wait_pid == -1)
207     return -1;
208   return wstatus;
209 }
210 
211 const struct _IO_jump_t _IO_old_proc_jumps libio_vtable = {
212   JUMP_INIT_DUMMY,
213   JUMP_INIT(finish, _IO_old_file_finish),
214   JUMP_INIT(overflow, _IO_old_file_overflow),
215   JUMP_INIT(underflow, _IO_old_file_underflow),
216   JUMP_INIT(uflow, _IO_default_uflow),
217   JUMP_INIT(pbackfail, _IO_default_pbackfail),
218   JUMP_INIT(xsputn, _IO_old_file_xsputn),
219   JUMP_INIT(xsgetn, _IO_default_xsgetn),
220   JUMP_INIT(seekoff, _IO_old_file_seekoff),
221   JUMP_INIT(seekpos, _IO_default_seekpos),
222   JUMP_INIT(setbuf, _IO_old_file_setbuf),
223   JUMP_INIT(sync, _IO_old_file_sync),
224   JUMP_INIT(doallocate, _IO_file_doallocate),
225   JUMP_INIT(read, _IO_file_read),
226   JUMP_INIT(write, _IO_old_file_write),
227   JUMP_INIT(seek, _IO_file_seek),
228   JUMP_INIT(close, _IO_old_proc_close),
229   JUMP_INIT(stat, _IO_file_stat),
230   JUMP_INIT(showmanyc, _IO_default_showmanyc),
231   JUMP_INIT(imbue, _IO_default_imbue)
232 };
233 
234 strong_alias (_IO_old_popen, __old_popen)
235 compat_symbol (libc, _IO_old_popen, _IO_popen, GLIBC_2_0);
236 compat_symbol (libc, __old_popen, popen, GLIBC_2_0);
237 compat_symbol (libc, _IO_old_proc_open, _IO_proc_open, GLIBC_2_0);
238 compat_symbol (libc, _IO_old_proc_close, _IO_proc_close, GLIBC_2_0);
239 
240 #endif
241