GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
octave-popen2.c
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2016-2025 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 size_t arg_len;
67
68 // Count command length, quotes, and terminating NUL character.
69 cmd_len = strlen (cmd) + 3;
70
71 // Count argument length, space, and quotes.
72 // Ignore first arg as it is the command.
73 argp = args;
74 while (*++argp)
75 cmd_len += strlen (*argp) + 3;
76
77 command = (char *) malloc (cmd_len);
78
79 // double-quote command
80 sprintf (command, "\"%s\"", cmd);
81
82 argp = args;
83 cmd_len = strlen (cmd) + 2;
84 while (*++argp)
85 {
86 // append double-quoted argument separated by space to command buffer
87 command[cmd_len++] = ' ';
88 command[cmd_len++] = '"';
89 arg_len = strlen (*argp);
90 memcpy (command + cmd_len, *argp, arg_len);
91 cmd_len += arg_len;
92 command[cmd_len++] = '"';
93 }
94 command[cmd_len] = 0;
95
96 return command;
97}
98
99pid_t
100octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
101 int *fildes, const char **errmsg)
102{
103 pid_t pid;
104
105 char *command;
106 bool status;
107
108 PROCESS_INFORMATION pi;
109 STARTUPINFO si;
110
111 HANDLE hProcess = GetCurrentProcess ();
112 HANDLE childRead, childWrite, parentRead, parentWrite;
113 DWORD pipeMode;
114
115 ZeroMemory (&pi, sizeof (pi));
116 ZeroMemory (&si, sizeof (si));
117 si.cb = sizeof (si);
118
119 if (! CreatePipe (&childRead, &parentWrite, 0, 0)
120 || ! DuplicateHandle (hProcess, childRead, hProcess, &childRead,
121 0, TRUE,
122 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
123 {
124 *errmsg = "popen2: pipe creation failed";
125 return -1;
126 }
127
128 if (! CreatePipe (&parentRead, &childWrite, 0, 0)
129 || ! DuplicateHandle (hProcess, childWrite, hProcess, &childWrite,
130 0, TRUE,
131 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
132 {
133 *errmsg = "popen2: pipe creation failed";
134 return -1;
135 }
136
137 if (! sync_mode)
138 {
139 pipeMode = PIPE_NOWAIT;
140 SetNamedPipeHandleState (parentRead, &pipeMode, 0, 0);
141 }
142
143 fildes[1] = _open_osfhandle ((intptr_t) parentRead, _O_RDONLY | _O_BINARY);
144 fildes[0] = _open_osfhandle ((intptr_t) parentWrite, _O_WRONLY | _O_BINARY);
145
146 si.dwFlags |= STARTF_USESTDHANDLES;
147
148 si.hStdInput = childRead;
149 si.hStdOutput = childWrite;
150 si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
151
152 command = make_command_string (cmd, args);
153
154 wchar_t *wcmd = u8_to_wchar (command);
155
156 free (command);
157
158 status = CreateProcessW (NULL, wcmd, NULL, NULL, TRUE, CREATE_NO_WINDOW,
159 NULL, NULL, &si, &pi);
160
161 free (wcmd);
162
163 if (! status)
164 {
165 *errmsg = "popen2: process creation failed";
166 return -1;
167 }
168
169 pid = pi.dwProcessId;
170
171 CloseHandle (childRead);
172 CloseHandle (childWrite);
173
174 CloseHandle (pi.hProcess);
175 CloseHandle (pi.hThread);
176
177 return pid;
178}
179
180#else
181
182pid_t
183octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
184 int *fildes, const char **errmsg)
185{
186 pid_t pid;
187
188 int child_stdin[2], child_stdout[2];
189
190 if (pipe (child_stdin) < 0)
191 {
192 *errmsg = strerror (errno);
193 return -1;
194 }
195
196 if (pipe (child_stdout) < 0)
197 {
198 close (child_stdin[0]);
199 close (child_stdin[1]);
200
201 *errmsg = strerror (errno);
202 return -1;
203 }
204
205 pid = fork ();
206
207 if (pid == 0)
208 {
209 // Child process
210
211 close (child_stdin[1]);
212 close (child_stdout[0]);
213
214 if (dup2 (child_stdin[0], STDIN_FILENO) >= 0)
215 {
216 close (child_stdin[0]);
217
218 if (dup2 (child_stdout[1], STDOUT_FILENO) >= 0)
219 {
220 close (child_stdout[1]);
221
222 if (execvp (cmd, args) < 0)
223 perror ("popen2 (child)");
224 }
225 else
226 perror ("popen2 (child)");
227 }
228 else
229 perror ("popen2 (child)");
230
231 _exit (127);
232 }
233 else if (pid > 0)
234 {
235 // Parent process
236
237 close (child_stdin[0]);
238 close (child_stdout[1]);
239
240#if defined (F_SETFL) && defined (O_NONBLOCK)
241 if (! sync_mode && fcntl (child_stdout[0], F_SETFL, O_NONBLOCK) < 0)
242 {
243 *errmsg = strerror (errno);
244 return -1;
245 }
246 else
247#endif
248 {
249 fildes[0] = child_stdin[1];
250 fildes[1] = child_stdout[0];
251
252 return pid;
253 }
254 }
255
256 *errmsg = "foobar!";
257 *errmsg = strerror (errno);
258 return pid;
259}
260
261#endif
T::size_type strlen(const typename T::value_type *str)
Definition oct-string.cc:88
int pipe(int *fildes)
pid_t fork(std::string &msg)
int execvp(const std::string &file, const string_vector &argv)
int fcntl(int fd, int cmd, long arg)
int dup2(int old_fd, int new_fd)
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)