GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
octave-popen2.c
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2016-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// It makes more sense to define octave_popen2 with the wrapper
27// functions than it does to try to provide wrappers for all the
28// individual functions and macros that it uses and that may be provided
29// by gnulib. We don't include gnulib headers directly in Octave's C++
30// source files to avoid problems that may be caused by the way that
31// gnulib overrides standard library functions.
32
33#if defined (HAVE_CONFIG_H)
34# include "config.h"
35#endif
36
37#include <stdbool.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42#if defined (__WIN32__) && ! defined (__CYGWIN__)
43# include <fcntl.h>
44# include <io.h>
45# define WIN32_LEAN_AND_MEAN 1
46# include <windows.h>
47
48# include "uniconv-wrappers.h"
49#else
50# include <errno.h>
51# include <fcntl.h>
52# include <sys/types.h>
53# include <unistd.h>
54#endif
55
56#include "octave-popen2.h"
57
58#if defined (__WIN32__) && ! defined (__CYGWIN__)
59
60static char *
61make_command_string (const char *cmd, char *const *args)
62{
63 char *const *argp;
64 size_t cmd_len;
65 char *command;
66
67 // Count Command length, quotes, and terminating NUL character.
68 cmd_len = strlen (cmd) + 3;
69
70 // Count argument length, space, and quotes.
71 // Ignore first arg as it is the command.
72 argp = args;
73 while (*++argp)
74 cmd_len += strlen (*argp) + 3;
75
76 command = (char *) malloc (cmd_len);
77
78 sprintf (command, "\"%s\"", cmd);
79
80 argp = args;
81 while (*++argp)
82 sprintf (command, "%s \"%s\"", command, *argp);
83
84 return command;
85}
86
87pid_t
88octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
89 int *fildes, const char **errmsg)
90{
91 pid_t pid;
92
93 char *command;
94 bool status;
95
96 PROCESS_INFORMATION pi;
97 STARTUPINFO si;
98
99 HANDLE hProcess = GetCurrentProcess ();
100 HANDLE childRead, childWrite, parentRead, parentWrite;
101 DWORD pipeMode;
102
103 ZeroMemory (&pi, sizeof (pi));
104 ZeroMemory (&si, sizeof (si));
105 si.cb = sizeof (si);
106
107 if (! CreatePipe (&childRead, &parentWrite, 0, 0)
108 || ! DuplicateHandle (hProcess, childRead, hProcess, &childRead,
109 0, TRUE,
110 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
111 {
112 *errmsg = "popen2: pipe creation failed";
113 return -1;
114 }
115
116 if (! CreatePipe (&parentRead, &childWrite, 0, 0)
117 || ! DuplicateHandle (hProcess, childWrite, hProcess, &childWrite,
118 0, TRUE,
119 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
120 {
121 *errmsg = "popen2: pipe creation failed";
122 return -1;
123 }
124
125 if (! sync_mode)
126 {
127 pipeMode = PIPE_NOWAIT;
128 SetNamedPipeHandleState (parentRead, &pipeMode, 0, 0);
129 }
130
131 fildes[1] = _open_osfhandle ((intptr_t) parentRead, _O_RDONLY | _O_BINARY);
132 fildes[0] = _open_osfhandle ((intptr_t) parentWrite, _O_WRONLY | _O_BINARY);
133
134 si.dwFlags |= STARTF_USESTDHANDLES;
135
136 si.hStdInput = childRead;
137 si.hStdOutput = childWrite;
138 si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
139
140 command = make_command_string (cmd, args);
141
142 wchar_t *wcmd = u8_to_wchar (command);
143
144 free (command);
145
146 status = CreateProcessW (NULL, wcmd, NULL, NULL, TRUE, CREATE_NO_WINDOW,
147 NULL, NULL, &si, &pi);
148
149 free (wcmd);
150
151 if (! status)
152 {
153 *errmsg = "popen2: process creation failed";
154 return -1;
155 }
156
157 pid = pi.dwProcessId;
158
159 CloseHandle (childRead);
160 CloseHandle (childWrite);
161
162 CloseHandle (pi.hProcess);
163 CloseHandle (pi.hThread);
164
165 return pid;
166}
167
168#else
169
170pid_t
171octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
172 int *fildes, const char **errmsg)
173{
174 pid_t pid;
175
176 int child_stdin[2], child_stdout[2];
177
178 if (pipe (child_stdin) < 0)
179 {
180 *errmsg = strerror (errno);
181 return -1;
182 }
183
184 if (pipe (child_stdout) < 0)
185 {
186 close (child_stdin[0]);
187 close (child_stdin[1]);
188
189 *errmsg = strerror (errno);
190 return -1;
191 }
192
193 pid = fork ();
194
195 if (pid == 0)
196 {
197 // Child process
198
199 close (child_stdin[1]);
200 close (child_stdout[0]);
201
202 if (dup2 (child_stdin[0], STDIN_FILENO) >= 0)
203 {
204 close (child_stdin[0]);
205
206 if (dup2 (child_stdout[1], STDOUT_FILENO) >= 0)
207 {
208 close (child_stdout[1]);
209
210 if (execvp (cmd, args) < 0)
211 perror ("popen2 (child)");
212 }
213 else
214 perror ("popen2 (child)");
215 }
216 else
217 perror ("popen2 (child)");
218
219 _exit (127);
220 }
221 else if (pid > 0)
222 {
223 // Parent process
224
225 close (child_stdin[0]);
226 close (child_stdout[1]);
227
228#if defined (F_SETFL) && defined (O_NONBLOCK)
229 if (! sync_mode && fcntl (child_stdout[0], F_SETFL, O_NONBLOCK) < 0)
230 {
231 *errmsg = strerror (errno);
232 return -1;
233 }
234 else
235#endif
236 {
237 fildes[0] = child_stdin[1];
238 fildes[1] = child_stdout[0];
239
240 return pid;
241 }
242 }
243
244 *errmsg = "foobar!";
245 *errmsg = strerror (errno);
246 return pid;
247}
248
249#endif
static const double pi
Definition: lo-specfun.cc:1995
int pipe(int *fildes)
int execvp(const std::string &file, const string_vector &argv)
Definition: oct-syscalls.cc:74
int fcntl(int fd, int cmd, long arg)
int dup2(int old_fd, int new_fd)
Definition: oct-syscalls.cc:52
pid_t fork(std::string &msg)
Definition: oct-syscalls.cc:99
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:85
void * malloc(unsigned)
void free(void *)
pid_t octave_popen2(const char *cmd, char *const *args, bool sync_mode, int *fildes, const char **errmsg)
#define STDIN_FILENO
Definition: sysdep.cc:92
wchar_t * u8_to_wchar(const char *u8)