GNU Octave  9.1.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-2024 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 
59 
60 #if ! defined (SHELL_PATH)
61 # define SHELL_PATH "/bin/sh"
62 #endif
63 
64 // This class is based on the procbuf class from libg++, written by
65 // Per Bothner, Copyright (C) 1993 Free Software Foundation.
66 
67 #if (! (defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER)) \
68  && defined (HAVE_UNISTD_H))
69 
70 static procbuf *procbuf_list = nullptr;
71 
72 #endif
73 
74 #if ! defined (BUFSIZ)
75 # define BUFSIZ 1024
76 #endif
77 
78 procbuf *
79 procbuf::open (const char *command, int mode)
80 {
81 #if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER)
82 
83  if (is_open ())
84  return 0;
85 
86  m_f = (octave::popen (command, (mode & std::ios::in) ? "r" : "w"));
87 
88  if (! m_f)
89  return 0;
90 
91  // Oops... popen doesn't return the associated pid, so fake it for now
92 
93  m_proc_pid = 1;
94 
95  m_open_p = true;
96 
97  if (mode & std::ios::out)
98  ::setvbuf (m_f, nullptr, _IOLBF, BUFSIZ);
99 
100  return this;
101 
102 #elif defined (HAVE_UNISTD_H)
103 
104  int pipe_fds[2];
105 
106  volatile int child_std_end = (mode & std::ios::in) ? 1 : 0;
107 
108  volatile int parent_end, child_end;
109 
110  if (is_open ())
111  return nullptr;
112 
113  if (octave::sys::pipe (pipe_fds) < 0)
114  return nullptr;
115 
116  if (mode & std::ios::in)
117  {
118  parent_end = pipe_fds[0];
119  child_end = pipe_fds[1];
120  }
121  else
122  {
123  parent_end = pipe_fds[1];
124  child_end = pipe_fds[0];
125  }
126 
127  m_proc_pid = ::fork ();
128 
129  if (m_proc_pid == 0)
130  {
131  octave_close_wrapper (parent_end);
132 
133  if (child_end != child_std_end)
134  {
135  octave_dup2_wrapper (child_end, child_std_end);
136  octave_close_wrapper (child_end);
137  }
138 
139  while (procbuf_list)
140  {
141  FILE *fp = procbuf_list->m_f;
142 
143  if (fp)
144  {
145  std::fclose (fp);
146  fp = nullptr;
147  }
148 
149  procbuf_list = procbuf_list->m_next;
150  }
151 
152  execl (SHELL_PATH, "sh", "-c", command, static_cast<void *> (nullptr));
153 
154  exit (127);
155  }
156 
157  octave_close_wrapper (child_end);
158 
159  if (m_proc_pid < 0)
160  {
161  octave_close_wrapper (parent_end);
162  return nullptr;
163  }
164 
165  m_f = (::fdopen (parent_end, (mode & std::ios::in) ? "r" : "w"));
166 
167  if (mode & std::ios::out)
168  ::setvbuf (m_f, nullptr, _IOLBF, BUFSIZ);
169 
170  m_open_p = true;
171 
172  m_next = procbuf_list;
173  procbuf_list = this;
174 
175  return this;
176 
177 #else
178 
179  return 0;
180 
181 #endif
182 }
183 
184 procbuf *
186 {
187 #if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER)
188 
189  if (m_f)
190  {
192  m_f = 0;
193  }
194 
195  m_open_p = false;
196 
197  return this;
198 
199 #elif defined (HAVE_UNISTD_H)
200 
201  if (m_f)
202  {
203  pid_t wait_pid;
204 
205  int status = -1;
206 
207  for (procbuf **ptr = &procbuf_list;
208  *ptr != nullptr;
209  ptr = &(*ptr)->m_next)
210  {
211  if (*ptr == this)
212  {
213  *ptr = (*ptr)->m_next;
214  status = 0;
215  break;
216  }
217  }
218 
219  if (status == 0 && std::fclose (m_f) == 0)
220  {
221  using namespace std;
222 
223  do
224  {
225  wait_pid = octave::sys::waitpid (m_proc_pid, &m_wstatus, 0);
226  }
227  while (wait_pid == -1 && errno == EINTR);
228  }
229 
230  m_f = nullptr;
231  }
232 
233  m_open_p = false;
234 
235  return this;
236 
237 #else
238 
239  return 0;
240 
241 #endif
242 }
243 
244 OCTAVE_END_NAMESPACE(octave)
pid_t m_proc_pid
Definition: oct-procbuf.h:75
procbuf * close()
Definition: oct-procbuf.cc:185
bool is_open() const
Definition: oct-procbuf.h:65
int m_wstatus
Definition: oct-procbuf.h:71
procbuf * m_next
Definition: oct-procbuf.h:77
bool m_open_p
Definition: oct-procbuf.h:73
procbuf * open(const char *command, int mode)
Definition: oct-procbuf.cc:79
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
FILE * popen(const char *command, const char *mode)
Definition: sysdep.cc:626
int pclose(FILE *f)
Definition: sysdep.cc:643
#define BUFSIZ
Definition: oct-procbuf.cc:75
#define SHELL_PATH
Definition: oct-procbuf.cc:61
int pipe(int *fildes)
pid_t fork(std::string &msg)
Definition: oct-syscalls.cc:99
pid_t waitpid(pid_t pid, int *status, int options)
int octave_close_wrapper(int fd)
int octave_dup2_wrapper(int fd1, int fd2)