1 : /******************************************************************************
2 : * $Id: ogrgpsbabelfork.cpp 19787 2010-05-31 22:26:57Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Utility to fork a process and pipe data into/from it
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "cpl_vsi.h"
32 : #include "cpl_error.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_string.h"
35 : #include "cpl_multiproc.h"
36 :
37 : #include "ogr_gpsbabel.h"
38 :
39 : #define PIPE_BUFFER_SIZE 4096
40 :
41 : #define IN_FOR_PARENT 0
42 : #define OUT_FOR_PARENT 1
43 :
44 :
45 : #ifndef WIN32
46 :
47 : #include <unistd.h>
48 : #include <stdio.h>
49 : #include <stdlib.h>
50 : #include <sys/types.h>
51 : #include <sys/wait.h>
52 : #include <errno.h>
53 :
54 :
55 3 : static void WriteToPipe(FILE* fin, int pipe_fd)
56 : {
57 : char buf[PIPE_BUFFER_SIZE];
58 0 : while(TRUE)
59 : {
60 3 : int nRead = (int)VSIFReadL(buf, 1, PIPE_BUFFER_SIZE, fin);
61 3 : int nWritten = write(pipe_fd, buf, nRead);
62 3 : if (nWritten < nRead || nRead < PIPE_BUFFER_SIZE)
63 : break;
64 : }
65 3 : }
66 :
67 9 : static void ReadFromPipe(int pipe_fd, FILE* fout)
68 : {
69 : char buf[PIPE_BUFFER_SIZE];
70 3 : while(TRUE)
71 : {
72 9 : int nRead = read(pipe_fd, buf, PIPE_BUFFER_SIZE);
73 9 : if (nRead <= 0)
74 6 : break;
75 3 : int nWritten = (int)VSIFWriteL(buf, 1, nRead, fout);
76 3 : if (nWritten < nRead)
77 0 : break;
78 : }
79 6 : }
80 :
81 3 : int ForkAndPipe(const char * const argv[], FILE* fin, FILE* fout)
82 : {
83 : pid_t pid;
84 3 : int pipe_in[2] = { -1, -1 };
85 3 : int pipe_out[2] = { -1, -1 };
86 3 : int pipe_err[2] = { -1, -1 };
87 : int i;
88 :
89 3 : if (pipe(pipe_in) ||
90 : pipe(pipe_out) ||
91 : pipe(pipe_err))
92 0 : goto err_pipe;
93 :
94 3 : pid = fork();
95 3 : if (pid == 0)
96 : {
97 : /* Close unused end of pipe */
98 0 : close(pipe_in[OUT_FOR_PARENT]);
99 0 : close(pipe_out[IN_FOR_PARENT]);
100 0 : close(pipe_err[IN_FOR_PARENT]);
101 :
102 0 : dup2(pipe_in[IN_FOR_PARENT], fileno(stdin));
103 0 : dup2(pipe_out[OUT_FOR_PARENT], fileno(stdout));
104 0 : dup2(pipe_err[OUT_FOR_PARENT], fileno(stderr));
105 :
106 0 : execvp(argv[0], (char* const*) argv);
107 :
108 0 : char* pszErr = strerror(errno);
109 :
110 0 : fprintf(stderr, "An error occured while forking process %s : %s", argv[0], pszErr);
111 :
112 0 : exit(1);
113 : }
114 3 : else if (pid < 0)
115 : {
116 0 : CPLError(CE_Failure, CPLE_AppDefined, "fork() failed");
117 0 : goto err;
118 : }
119 : else
120 : {
121 : /* Close unused end of pipe */
122 3 : close(pipe_in[IN_FOR_PARENT]);
123 3 : close(pipe_out[OUT_FOR_PARENT]);
124 3 : close(pipe_err[OUT_FOR_PARENT]);
125 :
126 : /* Ignore SIGPIPE */
127 : #ifdef SIGPIPE
128 3 : signal (SIGPIPE, SIG_IGN);
129 : #endif
130 :
131 3 : if (fin != NULL)
132 3 : WriteToPipe(fin, pipe_in[OUT_FOR_PARENT]);
133 3 : close(pipe_in[OUT_FOR_PARENT]);
134 :
135 3 : if (fout != NULL)
136 3 : ReadFromPipe(pipe_out[IN_FOR_PARENT], fout);
137 3 : close(pipe_out[IN_FOR_PARENT]);
138 :
139 3 : CPLString osName;
140 3 : osName.Printf("/vsimem/child_stderr_" CPL_FRMT_GIB, CPLGetPID());
141 3 : FILE* ferr = VSIFOpenL(osName.c_str(), "w");
142 3 : ReadFromPipe(pipe_err[IN_FOR_PARENT], ferr);
143 3 : close(pipe_err[IN_FOR_PARENT]);
144 3 : VSIFCloseL(ferr);
145 3 : vsi_l_offset nDataLength = 0;
146 3 : GByte* pData = VSIGetMemFileBuffer(osName.c_str(), &nDataLength, TRUE);
147 3 : if (pData)
148 0 : CPLError(CE_Failure, CPLE_AppDefined, "[%s error] %s", argv[0], pData);
149 3 : CPLFree(pData);
150 :
151 0 : while(1)
152 : {
153 : int status;
154 3 : int ret = waitpid (pid, &status, 0);
155 3 : if (ret < 0)
156 : {
157 0 : if (errno != EINTR)
158 : {
159 0 : break;
160 : }
161 : }
162 : else
163 3 : break;
164 : }
165 3 : return pData == NULL;
166 : }
167 0 : err_pipe:
168 0 : CPLError(CE_Failure, CPLE_AppDefined, "Could not create pipe");
169 0 : err:
170 0 : for(i=0;i<2;i++)
171 : {
172 0 : if (pipe_in[i] >= 0)
173 0 : close(pipe_in[i]);
174 0 : if (pipe_out[i] >= 0)
175 0 : close(pipe_out[i]);
176 0 : if (pipe_err[i] >= 0)
177 0 : close(pipe_err[i]);
178 : }
179 :
180 0 : return FALSE;
181 : }
182 :
183 : #else
184 :
185 : #include <windows.h>
186 :
187 : static void WriteToPipe(FILE* fin, HANDLE pipe_fd)
188 : {
189 : char buf[PIPE_BUFFER_SIZE];
190 : while(TRUE)
191 : {
192 : int nRead = (int)VSIFReadL(buf, 1, PIPE_BUFFER_SIZE, fin);
193 : DWORD nWritten;
194 : if (!WriteFile(pipe_fd, buf, nRead, &nWritten, NULL))
195 : break;
196 : if ((int)nWritten < nRead || nRead < PIPE_BUFFER_SIZE)
197 : break;
198 : }
199 : }
200 :
201 : static void ReadFromPipe(HANDLE pipe_fd, FILE* fout)
202 : {
203 : char buf[PIPE_BUFFER_SIZE];
204 : while(TRUE)
205 : {
206 : DWORD nRead;
207 : if (!ReadFile( pipe_fd, buf, PIPE_BUFFER_SIZE, &nRead, NULL))
208 : break;
209 : if (nRead <= 0)
210 : break;
211 : int nWritten = (int)VSIFWriteL(buf, 1, nRead, fout);
212 : if (nWritten < (int)nRead)
213 : break;
214 : }
215 : }
216 :
217 : int ForkAndPipe(const char * const argv[], FILE* fin, FILE* fout)
218 : {
219 : HANDLE pipe_in[2] = {NULL, NULL};
220 : HANDLE pipe_out[2] = {NULL, NULL};
221 : HANDLE pipe_err[2] = {NULL, NULL};
222 : SECURITY_ATTRIBUTES saAttr;
223 : PROCESS_INFORMATION piProcInfo;
224 : STARTUPINFO siStartInfo;
225 : CPLString osCommandLine;
226 : int i;
227 : CPLString osName;
228 : FILE* ferr;
229 : vsi_l_offset nDataLength = 0;
230 : GByte* pData;
231 :
232 : saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
233 : saAttr.bInheritHandle = TRUE;
234 : saAttr.lpSecurityDescriptor = NULL;
235 :
236 : if (!CreatePipe(&pipe_in[IN_FOR_PARENT],&pipe_in[OUT_FOR_PARENT],&saAttr, 0))
237 : goto err_pipe;
238 : /* The child must not inherit from the write side of the pipe_in */
239 : if (!SetHandleInformation(pipe_in[OUT_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
240 : goto err_pipe;
241 :
242 : if (!CreatePipe(&pipe_out[IN_FOR_PARENT],&pipe_out[OUT_FOR_PARENT],&saAttr, 0))
243 : goto err_pipe;
244 : /* The child must not inherit from the read side of the pipe_out */
245 : if (!SetHandleInformation(pipe_out[IN_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
246 : goto err_pipe;
247 :
248 : if (!CreatePipe(&pipe_err[IN_FOR_PARENT],&pipe_err[OUT_FOR_PARENT],&saAttr, 0))
249 : goto err_pipe;
250 : /* The child must not inherit from the read side of the pipe_err */
251 : if (!SetHandleInformation(pipe_err[IN_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
252 : goto err_pipe;
253 :
254 : memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION));
255 : memset(&siStartInfo, 0, sizeof(STARTUPINFO));
256 : siStartInfo.cb = sizeof(STARTUPINFO);
257 : siStartInfo.hStdInput = pipe_in[IN_FOR_PARENT];
258 : siStartInfo.hStdOutput = pipe_out[OUT_FOR_PARENT];
259 : siStartInfo.hStdError = pipe_err[OUT_FOR_PARENT];
260 : siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
261 :
262 : for(i=0;argv[i] != NULL;i++)
263 : {
264 : if (i > 0)
265 : osCommandLine += " ";
266 : osCommandLine += argv[i];
267 : }
268 :
269 : if (!CreateProcess(NULL,
270 : (CHAR*)osCommandLine.c_str(),
271 : NULL, // process security attributes
272 : NULL, // primary thread security attributes
273 : TRUE, // handles are inherited
274 : 0, // creation flags
275 : NULL, // use parent's environment
276 : NULL, // use parent's current directory
277 : &siStartInfo,
278 : &piProcInfo))
279 : {
280 : CPLError(CE_Failure, CPLE_AppDefined, "Could not create process %s",
281 : osCommandLine.c_str());
282 : goto err;
283 : }
284 :
285 : CloseHandle(piProcInfo.hProcess);
286 : CloseHandle(piProcInfo.hThread);
287 : CloseHandle(pipe_in[IN_FOR_PARENT]);
288 :
289 : if (fin != NULL)
290 : WriteToPipe(fin, pipe_in[OUT_FOR_PARENT]);
291 : CloseHandle(pipe_in[OUT_FOR_PARENT]);
292 :
293 : CloseHandle(pipe_out[OUT_FOR_PARENT]);
294 : if (fout != NULL)
295 : ReadFromPipe(pipe_out[IN_FOR_PARENT], fout);
296 :
297 : osName.Printf("/vsimem/child_stderr_" CPL_FRMT_GIB, CPLGetPID());
298 : ferr = VSIFOpenL(osName.c_str(), "w");
299 : CloseHandle(pipe_err[OUT_FOR_PARENT]);
300 : ReadFromPipe(pipe_err[IN_FOR_PARENT], ferr);
301 : VSIFCloseL(ferr);
302 : pData = VSIGetMemFileBuffer(osName.c_str(), &nDataLength, TRUE);
303 : if (pData)
304 : CPLError(CE_Failure, CPLE_AppDefined, "[%s error] %s", argv[0], pData);
305 : CPLFree(pData);
306 :
307 : CloseHandle(pipe_out[IN_FOR_PARENT]);
308 : CloseHandle(pipe_err[IN_FOR_PARENT]);
309 :
310 : return pData == NULL;
311 :
312 : err_pipe:
313 : CPLError(CE_Failure, CPLE_AppDefined, "Could not create pipe");
314 : err:
315 : for(i=0;i<2;i++)
316 : {
317 : if (pipe_in[i] != NULL)
318 : CloseHandle(pipe_in[i]);
319 : if (pipe_out[i] != NULL)
320 : CloseHandle(pipe_out[i]);
321 : if (pipe_err[i] != NULL)
322 : CloseHandle(pipe_err[i]);
323 : }
324 :
325 : return FALSE;
326 : }
327 :
328 : #endif
|