1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 #  include "config.h"
28 #endif
29 
30 #include <cerrno>
31 
32 #include <iomanip>
33 
34 // FIXME: we would prefer to avoid including these directly in Octave
35 // sources, but eliminating them is complicated by the mingling of
36 // octave_procbuf_list and the calls to system library functions like
37 // execl.
38 
39 #if defined (HAVE_UNISTD_H)
40 #  if defined (HAVE_SYS_TYPES_H)
41 #    include <sys/types.h>
42 #  endif
43 #  include <unistd.h>
44 #endif
45 
46 #include "lo-mappers.h"
47 #include "lo-utils.h"
48 #include "oct-procbuf.h"
49 #include "oct-syscalls.h"
50 #include "sysdep.h"
51 #include "unistd-wrappers.h"
52 #include "variables.h"
53 
54 #include "defun.h"
55 #include "errwarn.h"
56 #include "utils.h"
57 
58 #if ! defined (SHELL_PATH)
59 #  define SHELL_PATH "/bin/sh"
60 #endif
61 
62 // This class is based on the procbuf class from libg++, written by
63 // Per Bothner, Copyright (C) 1993 Free Software Foundation.
64 
65 #if (! (defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER)) \
66      && defined (HAVE_UNISTD_H))
67 
68 static octave_procbuf *octave_procbuf_list = nullptr;
69 
70 #endif
71 
72 #if ! defined (BUFSIZ)
73 #  define BUFSIZ 1024
74 #endif
75 
76 octave_procbuf *
open(const char * command,int mode)77 octave_procbuf::open (const char *command, int mode)
78 {
79 #if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER)
80 
81   if (is_open ())
82     return 0;
83 
84   f = (octave::popen (command, (mode & std::ios::in) ? "r" : "w"));
85 
86   if (! f)
87     return 0;
88 
89   // Oops... popen doesn't return the associated pid, so fake it for now
90 
91   proc_pid = 1;
92 
93   open_p = true;
94 
95   if (mode & std::ios::out)
96     ::setvbuf (f, nullptr, _IOLBF, BUFSIZ);
97 
98   return this;
99 
100 #elif defined (HAVE_UNISTD_H)
101 
102   int pipe_fds[2];
103 
104   volatile int child_std_end = (mode & std::ios::in) ? 1 : 0;
105 
106   volatile int parent_end, child_end;
107 
108   if (is_open ())
109     return nullptr;
110 
111   if (octave::sys::pipe (pipe_fds) < 0)
112     return nullptr;
113 
114   if (mode & std::ios::in)
115     {
116       parent_end = pipe_fds[0];
117       child_end = pipe_fds[1];
118     }
119   else
120     {
121       parent_end = pipe_fds[1];
122       child_end = pipe_fds[0];
123     }
124 
125   proc_pid = ::fork ();
126 
127   if (proc_pid == 0)
128     {
129       octave_close_wrapper (parent_end);
130 
131       if (child_end != child_std_end)
132         {
133           octave_dup2_wrapper (child_end, child_std_end);
134           octave_close_wrapper (child_end);
135         }
136 
137       while (octave_procbuf_list)
138         {
139           FILE *fp = octave_procbuf_list->f;
140 
141           if (fp)
142             {
143               std::fclose (fp);
144               fp = nullptr;
145             }
146 
147           octave_procbuf_list = octave_procbuf_list->next;
148         }
149 
150       execl (SHELL_PATH, "sh", "-c", command, static_cast<void *> (nullptr));
151 
152       exit (127);
153     }
154 
155   octave_close_wrapper (child_end);
156 
157   if (proc_pid < 0)
158     {
159       octave_close_wrapper (parent_end);
160       return nullptr;
161     }
162 
163   f = (::fdopen (parent_end, (mode & std::ios::in) ? "r" : "w"));
164 
165   if (mode & std::ios::out)
166     ::setvbuf (f, nullptr, _IOLBF, BUFSIZ);
167 
168   open_p = true;
169 
170   next = octave_procbuf_list;
171   octave_procbuf_list = this;
172 
173   return this;
174 
175 #else
176 
177   return 0;
178 
179 #endif
180 }
181 
182 octave_procbuf *
close(void)183 octave_procbuf::close (void)
184 {
185 #if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER)
186 
187   if (f)
188     {
189       wstatus = octave::pclose (f);
190       f = 0;
191     }
192 
193   open_p = false;
194 
195   return this;
196 
197 #elif defined (HAVE_UNISTD_H)
198 
199   if (f)
200     {
201       pid_t wait_pid;
202 
203       int status = -1;
204 
205       for (octave_procbuf **ptr = &octave_procbuf_list;
206            *ptr != nullptr;
207            ptr = &(*ptr)->next)
208         {
209           if (*ptr == this)
210             {
211               *ptr = (*ptr)->next;
212               status = 0;
213               break;
214             }
215         }
216 
217       if (status == 0 && std::fclose (f) == 0)
218         {
219           using namespace std;
220 
221           do
222             {
223               wait_pid = octave::sys::waitpid (proc_pid, &wstatus, 0);
224             }
225           while (wait_pid == -1 && errno == EINTR);
226         }
227 
228       f = nullptr;
229     }
230 
231   open_p = false;
232 
233   return this;
234 
235 #else
236 
237   return 0;
238 
239 #endif
240 }
241