GNU Octave 7.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-2022 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
58OCTAVE_NAMESPACE_BEGIN
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
70static procbuf *procbuf_list = nullptr;
71
72#endif
73
74#if ! defined (BUFSIZ)
75# define BUFSIZ 1024
76#endif
77
78procbuf *
79procbuf::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
184procbuf *
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
244OCTAVE_NAMESPACE_END
pid_t m_proc_pid
Definition: oct-procbuf.h:79
int m_wstatus
Definition: oct-procbuf.h:75
procbuf * m_next
Definition: oct-procbuf.h:81
bool m_open_p
Definition: oct-procbuf.h:77
procbuf * open(const char *command, int mode)
Definition: oct-procbuf.cc:79
bool is_open(void) const
Definition: oct-procbuf.h:69
procbuf * close(void)
Definition: oct-procbuf.cc:185
int pipe(int *fildes)
pid_t waitpid(pid_t pid, int *status, int options)
pid_t fork(std::string &msg)
Definition: oct-syscalls.cc:99
STL namespace.
#define BUFSIZ
Definition: oct-procbuf.cc:75
#define SHELL_PATH
Definition: oct-procbuf.cc:61
int pclose(FILE *f)
Definition: sysdep.cc:711
FILE * popen(const char *command, const char *mode)
Definition: sysdep.cc:695
int octave_close_wrapper(int fd)
int octave_dup2_wrapper(int fd1, int fd2)