GNU Octave  6.2.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-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 // 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 #else
48 # include <errno.h>
49 # include <fcntl.h>
50 # include <sys/types.h>
51 # include <unistd.h>
52 #endif
53 
54 #include "octave-popen2.h"
55 
56 #if defined (__WIN32__) && ! defined (__CYGWIN__)
57 
58 static char *
59 make_command_string (const char *cmd, char *const *args)
60 {
61  char *const *argp;
62  size_t cmd_len;
63  char *command;
64 
65  // Count Command length, quotes, and terminating NUL character.
66  cmd_len = strlen (cmd) + 3;
67 
68  // Count argument length, space, and quotes.
69  // Ignore first arg as it is the command.
70  argp = args;
71  while (*++argp)
72  cmd_len += strlen (*argp) + 3;
73 
74  command = (char *) malloc (cmd_len);
75 
76  sprintf (command, "\"%s\"", cmd);
77 
78  argp = args;
79  while (*++argp)
80  sprintf (command, "%s \"%s\"", command, *argp);
81 
82  return command;
83 }
84 
85 pid_t
86 octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
87  int *fildes, const char **errmsg)
88 {
89  pid_t pid;
90 
91  char *command;
92  bool status;
93 
94  PROCESS_INFORMATION pi;
95  STARTUPINFO si;
96 
97  HANDLE hProcess = GetCurrentProcess ();
98  HANDLE childRead, childWrite, parentRead, parentWrite;
99  DWORD pipeMode;
100 
101  ZeroMemory (&pi, sizeof (pi));
102  ZeroMemory (&si, sizeof (si));
103  si.cb = sizeof (si);
104 
105  if (! CreatePipe (&childRead, &parentWrite, 0, 0)
106  || ! DuplicateHandle (hProcess, childRead, hProcess, &childRead,
107  0, TRUE,
108  DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
109  {
110  *errmsg = "popen2: pipe creation failed";
111  return -1;
112  }
113 
114  if (! CreatePipe (&parentRead, &childWrite, 0, 0)
115  || ! DuplicateHandle (hProcess, childWrite, hProcess, &childWrite,
116  0, TRUE,
117  DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
118  {
119  *errmsg = "popen2: pipe creation failed";
120  return -1;
121  }
122 
123  if (! sync_mode)
124  {
125  pipeMode = PIPE_NOWAIT;
126  SetNamedPipeHandleState (parentRead, &pipeMode, 0, 0);
127  }
128 
129  fildes[1] = _open_osfhandle ((intptr_t) parentRead, _O_RDONLY | _O_BINARY);
130  fildes[0] = _open_osfhandle ((intptr_t) parentWrite, _O_WRONLY | _O_BINARY);
131 
132  si.dwFlags |= STARTF_USESTDHANDLES;
133 
134  si.hStdInput = childRead;
135  si.hStdOutput = childWrite;
136  si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
137 
138  command = make_command_string (cmd, args);
139 
140  status = CreateProcess (0, command, 0, 0, TRUE, 0, 0, 0, &si, &pi);
141 
142  free (command);
143 
144  if (! status)
145  {
146  *errmsg = "popen2: process creation failed";
147  return -1;
148  }
149 
150  pid = pi.dwProcessId;
151 
152  CloseHandle (childRead);
153  CloseHandle (childWrite);
154 
155  CloseHandle (pi.hProcess);
156  CloseHandle (pi.hThread);
157 
158  return pid;
159 }
160 
161 #else
162 
163 pid_t
164 octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
165  int *fildes, const char **errmsg)
166 {
167  pid_t pid;
168 
169  int child_stdin[2], child_stdout[2];
170 
171  if (pipe (child_stdin) < 0)
172  {
173  *errmsg = strerror (errno);
174  return -1;
175  }
176 
177  if (pipe (child_stdout) < 0)
178  {
179  close (child_stdin[0]);
180  close (child_stdin[1]);
181 
182  *errmsg = strerror (errno);
183  return -1;
184  }
185 
186  pid = fork ();
187 
188  if (pid == 0)
189  {
190  // Child process
191 
192  close (child_stdin[1]);
193  close (child_stdout[0]);
194 
195  if (dup2 (child_stdin[0], STDIN_FILENO) >= 0)
196  {
197  close (child_stdin[0]);
198 
199  if (dup2 (child_stdout[1], STDOUT_FILENO) >= 0)
200  {
201  close (child_stdout[1]);
202 
203  if (execvp (cmd, args) < 0)
204  perror ("popen2 (child)");
205  }
206  else
207  perror ("popen2 (child)");
208  }
209  else
210  perror ("popen2 (child)");
211 
212  _exit (127);
213  }
214  else if (pid > 0)
215  {
216  // Parent process
217 
218  close (child_stdin[0]);
219  close (child_stdout[1]);
220 
221 #if defined (F_SETFL) && defined (O_NONBLOCK)
222  if (! sync_mode && fcntl (child_stdout[0], F_SETFL, O_NONBLOCK) < 0)
223  {
224  *errmsg = strerror (errno);
225  return -1;
226  }
227  else
228 #endif
229  {
230  fildes[0] = child_stdin[1];
231  fildes[1] = child_stdout[0];
232 
233  return pid;
234  }
235  }
236 
237  *errmsg = "foobar!";
238  *errmsg = strerror (errno);
239  return pid;
240 }
241 
242 #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:75
int fcntl(int fd, int cmd, long arg)
int dup2(int old_fd, int new_fd)
Definition: oct-syscalls.cc:53
pid_t fork(std::string &msg)
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