GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-procbuf.cc
Go to the documentation of this file.
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 
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 
184 {
185 #if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER)
186 
187  if (f)
188  {
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 }
octave_procbuf * close(void)
Definition: oct-procbuf.cc:183
bool is_open(void) const
Definition: oct-procbuf.h:65
octave_procbuf * next
Definition: oct-procbuf.h:77
octave_procbuf * open(const char *command, int mode)
Definition: oct-procbuf.cc:77
int pipe(int *fildes)
pid_t waitpid(pid_t pid, int *status, int options)
pid_t fork(std::string &msg)
FILE * popen(const char *command, const char *mode)
Definition: sysdep.cc:619
int pclose(FILE *f)
Definition: sysdep.cc:643
#define BUFSIZ
Definition: oct-procbuf.cc:73
#define SHELL_PATH
Definition: oct-procbuf.cc:59
int octave_close_wrapper(int fd)
int octave_dup2_wrapper(int fd1, int fd2)