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