GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
octave-popen2.c
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2016-2017 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 // It makes more sense to define octave_popen2 with the wrapper
24 // functions than it does to try to provide wrappers for all the
25 // individual functions and macros that it uses and that may be provided
26 // by gnulib. We don't include gnulib headers directly in Octave's C++
27 // source files to avoid problems that may be caused by the way that
28 // gnulib overrides standard library functions.
29 
30 #if defined (HAVE_CONFIG_H)
31 # include "config.h"
32 #endif
33 
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #if defined (__WIN32__) && ! defined (__CYGWIN__)
40 # include <fcntl.h>
41 # include <io.h>
42 # define WIN32_LEAN_AND_MEAN 1
43 # include <windows.h>
44 #else
45 # include <errno.h>
46 # include <fcntl.h>
47 # include <sys/types.h>
48 # include <unistd.h>
49 #endif
50 
51 #include "octave-popen2.h"
52 
53 #if defined (__WIN32__) && ! defined (__CYGWIN__)
54 
55 static char *
56 make_command_string (const char *cmd, char *const *args)
57 {
58  char *const *argp;
59  size_t cmd_len;
60  char *command;
61 
62  // Count Command length, quotes, and terminating NUL character.
63  cmd_len = strlen (cmd) + 3;
64 
65  // Count argument length, space, and quotes.
66  // Ignore first arg as it is the command.
67  argp = args;
68  while (*++argp)
69  cmd_len += strlen (*argp) + 3;
70 
71  command = (char *) malloc (cmd_len);
72 
73  sprintf (command, "\"%s\"", cmd);
74 
75  argp = args;
76  while (*++argp)
77  sprintf (command, "%s \"%s\"", command, *argp);
78 
79  return command;
80 }
81 
82 pid_t
83 octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
84  int *fildes, const char **errmsg)
85 {
86  pid_t pid;
87 
88  char *command;
89  bool status;
90 
91  PROCESS_INFORMATION pi;
92  STARTUPINFO si;
93 
94  HANDLE hProcess = GetCurrentProcess ();
95  HANDLE childRead, childWrite, parentRead, parentWrite;
96  DWORD pipeMode;
97 
98  ZeroMemory (&pi, sizeof (pi));
99  ZeroMemory (&si, sizeof (si));
100  si.cb = sizeof (si);
101 
102  if (! CreatePipe (&childRead, &parentWrite, 0, 0)
103  || ! DuplicateHandle (hProcess, childRead, hProcess, &childRead,
104  0, TRUE,
105  DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
106  {
107  *errmsg = "popen2: pipe creation failed";
108  return -1;
109  }
110 
111  if (! CreatePipe (&parentRead, &childWrite, 0, 0)
112  || ! DuplicateHandle (hProcess, childWrite, hProcess, &childWrite,
113  0, TRUE,
114  DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
115  {
116  *errmsg = "popen2: pipe creation failed";
117  return -1;
118  }
119 
120  if (! sync_mode)
121  {
122  pipeMode = PIPE_NOWAIT;
123  SetNamedPipeHandleState (parentRead, &pipeMode, 0, 0);
124  }
125 
126  fildes[1] = _open_osfhandle ((intptr_t) parentRead, _O_RDONLY | _O_BINARY);
127  fildes[0] = _open_osfhandle ((intptr_t) parentWrite, _O_WRONLY | _O_BINARY);
128 
129  si.dwFlags |= STARTF_USESTDHANDLES;
130 
131  si.hStdInput = childRead;
132  si.hStdOutput = childWrite;
133  si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
134 
135  command = make_command_string (cmd, args);
136 
137  status = CreateProcess (0, command, 0, 0, TRUE, 0, 0, 0, &si, &pi);
138 
139  free (command);
140 
141  if (! status)
142  {
143  *errmsg = "popen2: process creation failed";
144  return -1;
145  }
146 
147  pid = pi.dwProcessId;
148 
149  CloseHandle (childRead);
150  CloseHandle (childWrite);
151 
152  CloseHandle (pi.hProcess);
153  CloseHandle (pi.hThread);
154 
155  return pid;
156 }
157 
158 #else
159 
160 pid_t
161 octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
162  int *fildes, const char **errmsg)
163 {
164  pid_t pid;
165 
166  int child_stdin[2], child_stdout[2];
167 
168  if (pipe (child_stdin) < 0)
169  {
170  *errmsg = strerror (errno);
171  return -1;
172  }
173 
174  if (pipe (child_stdout) < 0)
175  {
176  close (child_stdin[0]);
177  close (child_stdin[1]);
178 
179  *errmsg = strerror (errno);
180  return -1;
181  }
182 
183  pid = fork ();
184 
185  if (pid == 0)
186  {
187  // Child process
188 
189  close (child_stdin[1]);
190  close (child_stdout[0]);
191 
192  if (dup2 (child_stdin[0], STDIN_FILENO) >= 0)
193  {
194  close (child_stdin[0]);
195 
196  if (dup2 (child_stdout[1], STDOUT_FILENO) >= 0)
197  {
198  close (child_stdout[1]);
199 
200  if (execvp (cmd, args) < 0)
201  perror ("popen2 (child)");
202  }
203  else
204  perror ("popen2 (child)");
205  }
206  else
207  perror ("popen2 (child)");
208 
209  _exit (127);
210  }
211  else if (pid > 0)
212  {
213  // Parent process
214 
215  close (child_stdin[0]);
216  close (child_stdout[1]);
217 
218 #if defined (F_SETFL) && defined (O_NONBLOCK)
219  if (! sync_mode && fcntl (child_stdout[0], F_SETFL, O_NONBLOCK) < 0)
220  {
221  *errmsg = strerror (errno);
222  return -1;
223  }
224  else
225 #endif
226  {
227  fildes[0] = child_stdin[1];
228  fildes[1] = child_stdout[0];
229 
230  return pid;
231  }
232  }
233 
234  *errmsg = "foobar!";
235  *errmsg = strerror (errno);
236  return pid;
237 }
238 
239 #endif
int dup2(int old_fd, int new_fd)
Definition: oct-syscalls.cc:50
int fcntl(int fd, int cmd, long arg)
#define STDIN_FILENO
Definition: sysdep.cc:93
to define functions rather than attempting to enter them directly on the command line The block of commands is executed as soon as you exit the editor To avoid executing any simply delete all the lines from the buffer before leaving the editor When invoked with no edit the previously executed command
Definition: oct-hist.cc:587
JNIEnv void * args
Definition: ov-java.cc:67
pid_t octave_popen2(const char *cmd, char *const *args, bool sync_mode, int *fildes, const char **errmsg)
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:75
void free(void *)
int execvp(const std::string &file, const string_vector &argv)
Definition: oct-syscalls.cc:72
pid_t fork(std::string &msg)
Definition: oct-syscalls.cc:97
void * malloc(size_t)
int pipe(int *fildes)
static const double pi
Definition: lo-specfun.cc:3610