Name | Executed | Routines | % | Executed | Lines | % | Unexecuted |
/home/matt/eu/rds/include/std/pipeio.e | 10 | 16 | 62.50% | 94 | 165 | 56.97% | 71 |
Routine | Executed | Lines | Unexecuted | |
exec_args() | 13 | 34 | 38.24% | 21 |
os_execv() | 0 | 12 | 0.00% | 12 |
create() | 8 | 17 | 47.06% | 9 |
os_dup2() | 0 | 6 | 0.00% | 6 |
error() | 0 | 3 | 0.00% | 3 |
get_errno() | 0 | 3 | 0.00% | 3 |
read() | 12 | 15 | 80.00% | 3 |
close() | 5 | 7 | 71.43% | 2 |
error_no() | 0 | 2 | 0.00% | 2 |
os_fork() | 4 | 6 | 66.67% | 2 |
os_pipe() | 8 | 10 | 80.00% | 2 |
os_signal() | 0 | 2 | 0.00% | 2 |
process() | 4 | 6 | 66.67% | 2 |
write() | 8 | 10 | 80.00% | 2 |
exec() | 2 | 2 | 100.00% | 0 |
kill() | 7 | 7 | 100.00% | 0 |
# | Executed | |
1 | namespace pipeio | |
2 | ||
3 | --**** | |
4 | -- === Pipe Input/Output | |
5 | -- | |
6 | -- ==== Notes | |
7 | -- Due to a bug, Euphoria does not handle STDERR properly | |
8 | -- STDERR cannot captured for Euphoria programs (other programs will work fully) | |
9 | -- The IO functions currently work with file handles, a future version might wrap them in streams | |
10 | -- so that they can be used directly alongside other file/socket/other-streams with a | |
11 | -- stream_select() function. | |
12 | -- | |
13 | ||
14 | --Includes | |
15 | include std/dll.e | |
16 | include std/machine.e | |
17 | include std/error.e | |
18 | ||
19 | 2 | ifdef WIN32 then |
20 | constant | |
21 | kernel32 = open_dll("kernel32.dll"), | |
22 | --iGetExitCodeProcess=define_c_func(kernel32,"GetExitCodeProcess",{C_UINT,C_POINTER},C_INT), | |
23 | iCreatePipe = define_c_func(kernel32,"CreatePipe",{C_POINTER,C_POINTER,C_POINTER,C_DWORD},C_BOOL), | |
24 | iReadFile = define_c_func(kernel32,"ReadFile",{C_UINT,C_POINTER,C_DWORD,C_POINTER,C_POINTER},C_BOOL), | |
25 | iWriteFile = define_c_func(kernel32,"WriteFile",{C_UINT,C_POINTER,C_DWORD,C_POINTER,C_POINTER},C_BOOL), | |
26 | iCloseHandle = define_c_func(kernel32,"CloseHandle",{C_UINT},C_BOOL), | |
27 | iTerminateProcess=define_c_func(kernel32,"TerminateProcess",{C_UINT,C_UINT},C_BOOL), | |
28 | iGetLastError = define_c_func(kernel32,"GetLastError",{},C_DWORD), | |
29 | iGetStdHandle = define_c_func(kernel32,"GetStdHandle",{C_DWORD},C_UINT), | |
30 | iSetHandleInformation = define_c_func(kernel32,"SetHandleInformation",{C_UINT,C_DWORD,C_DWORD},C_BOOL), | |
31 | iCreateProcess = define_c_func(kernel32,"CreateProcessA",{C_POINTER,C_POINTER,C_POINTER, | |
32 | C_POINTER,C_BOOL,C_DWORD,C_POINTER,C_POINTER,C_POINTER,C_POINTER},C_BOOL) | |
33 | ||
34 | constant | |
35 | -- STD_INPUT_HANDLE = -10, | |
36 | -- STD_OUTPUT_HANDLE = -11, | |
37 | -- STD_ERROR_HANDLE = -12, | |
38 | -- FILE_INVALID_HANDLE = -1, | |
39 | -- ERROR_BROKEN_PIPE = 109, | |
40 | SA_SIZE = 12, | |
41 | PIPE_WRITE_HANDLE = 1, PIPE_READ_HANDLE=2, | |
42 | HANDLE_FLAG_INHERIT=1, | |
43 | SUIdwFlags = 44, | |
44 | SUIhStdInput = 56, | |
45 | STARTUPINFO_SIZE = 68, | |
46 | STARTF_USESHOWWINDOW = 1, | |
47 | STARTF_USESTDHANDLES = 256, | |
48 | PROCESS_INFORMATION_SIZE = 16, | |
49 | FAIL = 0 | |
50 | ||
51 | elsedef | |
52 | --*NIX-specific constants | |
53 | constant | |
54 | 2 | STDLIB = open_dll({ "libc.so", "libc.dylib", "" }), |
55 | 2 | PIPE = define_c_func(STDLIB, "pipe", {C_POINTER}, C_INT), |
56 | 2 | READ = define_c_func(STDLIB, "read", {C_INT, C_POINTER, C_INT}, C_INT), |
57 | 2 | WRITE = define_c_func(STDLIB, "write", {C_INT, C_POINTER, C_INT}, C_INT), |
58 | 2 | CLOSE = define_c_func(STDLIB, "close", {C_INT}, C_INT), |
59 | 2 | DUP2 = define_c_func(STDLIB, "dup2", {C_INT, C_INT}, C_INT), |
60 | 2 | KILL = define_c_func(STDLIB, "kill", {C_INT, C_INT}, C_INT), |
61 | 2 | FORK = define_c_func(STDLIB, "fork", {}, C_INT), |
62 | 2 | EXECV = define_c_func(STDLIB, "execv", {C_POINTER, C_POINTER}, C_INT), |
63 | 2 | SIGNAL = define_c_func(STDLIB, "signal", {C_INT, C_POINTER}, C_POINTER), |
64 | 2 | ERRNO = define_c_var( STDLIB, "errno"), |
65 | 2 | FAIL = -1 |
66 | ||
67 | enum | |
68 | 2 | os_stdin = 0, os_stdout, os_stderr, |
69 | 2 | os_sig_dfl = 0, os_sig_ign |
70 | end ifdef | |
71 | ||
72 | --**** | |
73 | -- === Accessor Constants | |
74 | ||
75 | public enum | |
76 | --** Child processes standard input | |
77 | 2 | STDIN, |
78 | --** Child processes standard output | |
79 | 2 | STDOUT, |
80 | --** Child processes standard error | |
81 | 2 | STDERR, |
82 | --** Process ID | |
83 | 2 | PID |
84 | ||
85 | -- | |
86 | public enum | |
87 | --** Set of pipes that are for the use of the parent | |
88 | 2 | PARENT, |
89 | --** Set of pipes that are given to the child - should not be used by the parent | |
90 | 2 | CHILD |
91 | ||
92 | -- | |
93 | 2 | atom os_errno = 0 |
94 | ||
95 | -- Common functions | |
96 | 0 | |
97 | 0 | ifdef WIN32 then |
98 | return c_func(iGetLastError,{}) | |
99 | elsedef | |
100 | 0 | return peek4u(ERRNO) |
101 | end ifdef | |
102 | end function | |
103 | ||
104 | --**** | |
105 | -- === Opening/Closing | |
106 | ||
107 | --** | |
108 | -- Process Type | |
109 | ||
110 | 2 | |
111 | 2 | if atom(o) then |
112 | 0 | return 0 |
113 | end if | |
114 | ||
115 | 2 | if length(o) != 4 then |
116 | 0 | return 0 |
117 | end if | |
118 | ||
119 | 2 | return 1 |
120 | end type | |
121 | ||
122 | --** | |
123 | -- Close handle fd | |
124 | -- | |
125 | -- Returns: | |
126 | -- An **integer**, 0 on success, -1 on failure | |
127 | -- | |
128 | -- Example 1: | |
129 | -- | |
130 | -- integer status = pipeio:close(p[STDIN]) | |
131 | -- | |
132 | -- | |
133 | ||
134 | 12 | |
135 | atom ret | |
136 | ||
137 | 12 | ifdef WIN32 then |
138 | ret=c_func(iCloseHandle,{fd}) | |
139 | elsedef | |
140 | 12 | ret=c_func(CLOSE, {fd}) |
141 | end ifdef | |
142 | ||
143 | 12 | if ret = FAIL then |
144 | 0 | os_errno = get_errno() |
145 | 0 | return -1 |
146 | end if | |
147 | ||
148 | 12 | return 0 |
149 | end function | |
150 | ||
151 | --** | |
152 | -- Close pipes and kill process p with signal signal (default 15) | |
153 | -- | |
154 | -- Comments: | |
155 | -- Signal is ignored on Windows. | |
156 | -- | |
157 | -- Example 1: | |
158 | -- | |
159 | -- kill(p) | |
160 | -- | |
161 | -- | |
162 | ||
163 | 2 | |
164 | atom ret | |
165 | ||
166 | --Close the pipes | |
167 | --If any fail its probably just because they were already closed, so that is ignored | |
168 | 2 | ret=close(p[STDIN]) |
169 | 2 | ret=close(p[STDOUT]) |
170 | 2 | ret=close(p[STDERR]) |
171 | ||
172 | --Error may result, but it is usually just because the process has already ended. | |
173 | 2 | ifdef WIN32 then |
174 | --Not how to handle "signal", so its ignored on Windows for now | |
175 | ret=c_func(iTerminateProcess,{p[PID],signal and 0}) | |
176 | elsedef | |
177 | 2 | ret=c_func(KILL, {p[PID], signal}) |
178 | end ifdef | |
179 | 2 | end procedure |
180 | ||
181 | 6 | |
182 | sequence handles | |
183 | atom ret | |
184 | ||
185 | 6 | ifdef WIN32 then |
186 | atom psaAttrib, phWriteToPipe, phReadFromPipe | |
187 | ||
188 | psaAttrib = allocate(SA_SIZE+2*4) | |
189 | poke4(psaAttrib,{SA_SIZE,0,1}) | |
190 | phWriteToPipe = psaAttrib+SA_SIZE | |
191 | phReadFromPipe = psaAttrib+SA_SIZE+4 | |
192 | ret = c_func(iCreatePipe,{phReadFromPipe,phWriteToPipe,psaAttrib,0}) | |
193 | handles = peek4u({phWriteToPipe,2}) | |
194 | free(psaAttrib) | |
195 | elsedef | |
196 | 6 | atom cmd = allocate(8) |
197 | 6 | ret = c_func(PIPE,{cmd}) |
198 | 6 | handles = peek4u({cmd,2}) |
199 | 6 | free(cmd) |
200 | end ifdef | |
201 | ||
202 | 6 | if ret = FAIL then |
203 | 0 | os_errno = get_errno() |
204 | 0 | return -1 |
205 | end if | |
206 | ||
207 | 6 | return handles |
208 | end function | |
209 | ||
210 | --**** | |
211 | -- === Read/Write Process | |
212 | ||
213 | --** | |
214 | -- Read ##bytes## bytes from handle ##fd## | |
215 | -- | |
216 | -- Returns: | |
217 | -- A **sequence**, containing data, an empty sequence on EOF or an error code. | |
218 | -- Similar to [[:get_bytes]]. | |
219 | -- | |
220 | -- Example 1: | |
221 | -- | |
222 | -- sequence data=read(p[STDOUT],256) | |
223 | -- | |
224 | -- | |
225 | ||
226 | 1 | |
227 | 1 | if bytes=0 then return "" end if |
228 | ||
229 | 1 | sequence data |
230 | 1 | atom |
231 | ret, ReadCount, | |
232 | 1 | buf = allocate(bytes) |
233 | ||
234 | 1 | ifdef WIN32 then |
235 | atom pReadCount=allocate(4) | |
236 | ret = c_func(iReadFile,{fd,buf,bytes,pReadCount,0}) | |
237 | ReadCount=peek4u(pReadCount) | |
238 | free(pReadCount) | |
239 | elsedef | |
240 | 1 | ret = c_func(READ, {fd, buf, bytes}) |
241 | 1 | ReadCount=ret |
242 | end ifdef | |
243 | ||
244 | 1 | if ret = FAIL then |
245 | 0 | os_errno = get_errno() |
246 | 0 | free(buf) |
247 | 0 | return "" |
248 | end if | |
249 | ||
250 | 1 | data=peek({buf,ReadCount}) |
251 | ||
252 | 1 | free(buf) |
253 | ||
254 | 1 | return data |
255 | end function | |
256 | ||
257 | --**** | |
258 | -- Write ##bytes## to handle ##fd## | |
259 | -- | |
260 | -- Returns: | |
261 | -- A **integer**, number of bytes written, or -1 on error | |
262 | -- | |
263 | -- Example 1: | |
264 | -- | |
265 | -- integer bytes_written = write(p[STDIN],"Hello World!") | |
266 | -- | |
267 | -- | |
268 | ||
269 | 1 | |
270 | atom | |
271 | -- fd = p[2], | |
272 | 1 | buf = allocate_string(str), |
273 | ret,WrittenCount | |
274 | ||
275 | 1 | ifdef WIN32 then |
276 | atom pWrittenCount=allocate(4) | |
277 | ret=c_func(iWriteFile,{fd,buf,length(str),pWrittenCount,0}) | |
278 | WrittenCount=peek4u(pWrittenCount) | |
279 | free(pWrittenCount) | |
280 | elsedef | |
281 | 1 | ret = c_func(WRITE, {fd, buf, length(str)}) |
282 | 1 | WrittenCount=ret |
283 | end ifdef | |
284 | ||
285 | 1 | free(buf) |
286 | ||
287 | 1 | if ret = FAIL then |
288 | 0 | os_errno = get_errno() |
289 | 0 | return -1 |
290 | end if | |
291 | ||
292 | 1 | return WrittenCount |
293 | end function | |
294 | ||
295 | 0 | |
296 | 0 | crash(sprintf("Errno = %d", os_errno)) |
297 | 0 | end procedure |
298 | ||
299 | --** | |
300 | -- Get error no from last call to a pipe function | |
301 | -- | |
302 | -- Comments: | |
303 | -- Value returned will be OS-specific, and is not always set on Windows at least | |
304 | -- | |
305 | -- Example 1: | |
306 | -- | |
307 | -- integer error = error_no() | |
308 | -- | |
309 | -- | |
310 | 0 | |
311 | 0 | return os_errno |
312 | end function | |
313 | ||
314 | 2 | ifdef WIN32 then |
315 | --WIN32-specific functions | |
316 | function GetStdHandle(atom device) | |
317 | return c_func(iGetStdHandle,{device}) | |
318 | end function | |
319 | ||
320 | function SetHandleInformation(atom hObject, atom dwMask, atom dwFlags) | |
321 | return c_func(iSetHandleInformation,{hObject,dwMask,dwFlags}) | |
322 | end function | |
323 | ||
324 | procedure CloseAllHandles(sequence handles) | |
325 | atom ret | |
326 | for i = 1 to length(handles) do | |
327 | ret=close(handles[i]) | |
328 | end for | |
329 | end procedure | |
330 | ||
331 | function CreateProcess(sequence CommandLine,sequence StdHandles) | |
332 | object fnVal | |
333 | atom pPI, pSUI, pCmdLine | |
334 | sequence ProcInfo | |
335 | ||
336 | pCmdLine = allocate_string(CommandLine) | |
337 | pPI = allocate(PROCESS_INFORMATION_SIZE) | |
338 | mem_set(pPI,0,PROCESS_INFORMATION_SIZE) | |
339 | pSUI = allocate(STARTUPINFO_SIZE) | |
340 | mem_set(pSUI,0,STARTUPINFO_SIZE) | |
341 | poke4(pSUI,STARTUPINFO_SIZE) | |
342 | poke4(pSUI+SUIdwFlags,or_bits(STARTF_USESTDHANDLES,STARTF_USESHOWWINDOW)) | |
343 | poke4(pSUI+SUIhStdInput,StdHandles) | |
344 | fnVal = c_func(iCreateProcess,{0,pCmdLine,0,0,1,0,0,0,pSUI,pPI}) | |
345 | free(pCmdLine) | |
346 | free(pSUI) | |
347 | ProcInfo = peek4u({pPI,4}) | |
348 | free(pPI) | |
349 | if not fnVal then | |
350 | return 0 | |
351 | end if | |
352 | return ProcInfo | |
353 | end function -- CreateProcess() | |
354 | ||
355 | --WIN32 version of create() | |
356 | ||
357 | --** | |
358 | -- Create pipes for inter-process communication | |
359 | -- | |
360 | -- Returns: | |
361 | -- A **handle**, process handles { {parent side pipes},{child side pipes} } | |
362 | -- | |
363 | -- Example 1: | |
364 | -- | |
365 | -- object p = exec("dir", create()) | |
366 | -- | |
367 | -- | |
368 | public function create() | |
369 | atom hChildStdInRd,hChildStdOutWr, hChildStdErrWr, -- handles used by child process | |
370 | hChildStdInWr, hChildStdOutRd,hChildStdErrRd -- handles used by parent process | |
371 | ||
372 | object | |
373 | StdInPipe = {}, | |
374 | StdOutPipe = {}, | |
375 | StdErrPipe = {} | |
376 | ||
377 | object fnVal | |
378 | ||
379 | -- capture child process std input | |
380 | StdInPipe = os_pipe() | |
381 | if atom(StdInPipe) then return -1 end if | |
382 | hChildStdInRd = StdInPipe[PIPE_READ_HANDLE] | |
383 | hChildStdInWr = StdInPipe[PIPE_WRITE_HANDLE] | |
384 | ||
385 | ||
386 | -- capture child process std output | |
387 | StdOutPipe = os_pipe() | |
388 | if atom(StdOutPipe) then | |
389 | CloseAllHandles(StdInPipe) | |
390 | return -1 | |
391 | end if | |
392 | hChildStdOutWr = StdOutPipe[PIPE_WRITE_HANDLE] | |
393 | hChildStdOutRd = StdOutPipe[PIPE_READ_HANDLE] | |
394 | ||
395 | -- capture child process std error | |
396 | StdErrPipe = os_pipe() | |
397 | if atom(StdErrPipe) then | |
398 | CloseAllHandles(StdErrPipe & StdOutPipe) | |
399 | return -1 | |
400 | end if | |
401 | hChildStdErrWr = StdErrPipe[PIPE_WRITE_HANDLE] | |
402 | hChildStdErrRd = StdErrPipe[PIPE_READ_HANDLE] | |
403 | ||
404 | fnVal = SetHandleInformation(StdInPipe[PIPE_WRITE_HANDLE],HANDLE_FLAG_INHERIT,0) | |
405 | fnVal = SetHandleInformation(StdOutPipe[PIPE_READ_HANDLE],HANDLE_FLAG_INHERIT,0) | |
406 | fnVal = SetHandleInformation(StdErrPipe[PIPE_READ_HANDLE],HANDLE_FLAG_INHERIT,0) | |
407 | ||
408 | return {{hChildStdInWr,hChildStdOutRd,hChildStdErrRd}, | |
409 | {hChildStdInRd,hChildStdOutWr,hChildStdErrWr}} | |
410 | ||
411 | end function | |
412 | ||
413 | --WIN32 version of exec() | |
414 | ||
415 | --** | |
416 | -- Open process with command line cmd | |
417 | -- | |
418 | -- Returns: | |
419 | -- A **handle**, process handles { [[:PID]], [[:STDIN]], [[:STDOUT]], [[:STDERR]] } | |
420 | -- | |
421 | -- Example 1: | |
422 | -- | |
423 | -- object p = exec("dir", create()) | |
424 | -- | |
425 | -- | |
426 | ||
427 | public function exec(sequence cmd, sequence pipe) | |
428 | object fnVal | |
429 | atom hChildStdInRd,hChildStdOutWr, hChildStdErrWr, -- handles used by child process | |
430 | hChildStdInWr, hChildStdOutRd,hChildStdErrRd -- handles used by parent process | |
431 | atom ret | |
432 | ||
433 | hChildStdInWr = pipe[1][1] | |
434 | hChildStdOutRd = pipe[1][2] | |
435 | hChildStdErrRd = pipe[1][3] | |
436 | hChildStdInRd = pipe[2][1] | |
437 | hChildStdOutWr = pipe[2][2] | |
438 | hChildStdErrWr = pipe[2][3] | |
439 | ||
440 | atom hChildProcess | |
441 | ||
442 | -- create child process | |
443 | fnVal = CreateProcess(cmd,{hChildStdInRd,hChildStdOutWr,hChildStdErrWr}) | |
444 | if atom(fnVal) then | |
445 | return -1 | |
446 | end if | |
447 | hChildProcess = fnVal[1] | |
448 | ret=close(fnVal[2]) -- hChildThread not needed. | |
449 | ||
450 | ret=close(hChildStdInRd) | |
451 | ||
452 | ret=close(hChildStdOutWr) | |
453 | ||
454 | ret=close(hChildStdErrWr) | |
455 | ||
456 | return {hChildStdInWr,hChildStdOutRd,hChildStdErrRd,hChildProcess} | |
457 | ||
458 | end function | |
459 | ||
460 | elsedef | |
461 | ||
462 | --*NIX-specific functions | |
463 | 0 | |
464 | 0 | atom r = c_func(DUP2, {oldfd, newfd}) |
465 | 0 | if r = -1 then |
466 | 0 | os_errno = peek4u(ERRNO) |
467 | 0 | return -1 |
468 | end if | |
469 | ||
470 | 0 | return r |
471 | end function | |
472 | ||
473 | 2 | |
474 | 2 | atom pid = c_func(FORK, {}) |
475 | 2 | if pid = -1 then |
476 | 0 | os_errno = peek4u(ERRNO) |
477 | 0 | return -1 |
478 | end if | |
479 | ||
480 | 2 | return pid |
481 | end function | |
482 | ||
483 | 0 | |
484 | atom sbuf | |
485 | atom vbuf | |
486 | sequence vbufseq | |
487 | atom r | |
488 | ||
489 | 0 | sbuf = allocate_string(s) |
490 | 0 | vbufseq = {sbuf}--http://www.cs.toronto.edu/~demke/369S.07/OS161_man/syscall/execv.html |
491 | ||
492 | 0 | for i = 1 to length(v) do |
493 | 0 | vbufseq &= allocate_string(v[i]) |
494 | 0 | end for |
495 | ||
496 | 0 | vbufseq &= 0 |
497 | 0 | vbuf = allocate(length(vbufseq)*4) |
498 | 0 | poke4(vbuf, vbufseq) |
499 | 0 | r = c_func(EXECV, {sbuf, vbuf}) -- execv() should never return |
500 | 0 | os_errno = peek4u(ERRNO) |
501 | 0 | return -1 |
502 | end function | |
503 | ||
504 | 0 | |
505 | 0 | return c_func(SIGNAL, {signal, handler}) |
506 | end function | |
507 | ||
508 | --*NIX version of create() | |
509 | ||
510 | --See docs above in WIN32 version | |
511 | 2 | |
512 | object ipipe,opipe,epipe | |
513 | integer ret | |
514 | ||
515 | --Create pipes | |
516 | 2 | ipipe=os_pipe() |
517 | 2 | if atom(ipipe) then |
518 | 0 | return -1 |
519 | end if | |
520 | ||
521 | 2 | opipe=os_pipe() |
522 | 2 | if atom(opipe) then |
523 | 0 | ret=close(ipipe[1]) |
524 | 0 | ret=close(ipipe[2]) |
525 | 0 | return -1 |
526 | end if | |
527 | ||
528 | 2 | epipe=os_pipe() |
529 | 2 | if atom(epipe) then |
530 | 0 | ret=close(ipipe[1]) |
531 | 0 | ret=close(ipipe[2]) |
532 | 0 | ret=close(opipe[1]) |
533 | 0 | ret=close(opipe[2]) |
534 | 0 | return -1 |
535 | end if | |
536 | 2 | return {{ipipe[2],opipe[1],epipe[1]},{ipipe[1],opipe[2],epipe[2]}} |
537 | end function | |
538 | ||
539 | --Linux takes parameters as a sequence of args, | |
540 | --so this is wrapped in a function below to make it compatible with the Windows implementation | |
541 | 2 | |
542 | atom pid | |
543 | integer ret | |
544 | sequence p | |
545 | object ipipe,opipe,epipe | |
546 | ||
547 | 2 | ipipe = pipe[2][1] & pipe[1][1] |
548 | 2 | opipe = pipe[1][2] & pipe[2][2] |
549 | 2 | epipe = pipe[1][3] & pipe[2][3] |
550 | ||
551 | --Fork | |
552 | 2 | pid=os_fork() |
553 | ||
554 | 2 | if pid=0 then |
555 | --Child process | |
556 | ||
557 | --Not much can really be done about errors at this stage, | |
558 | --so most are left unchecked | |
559 | ||
560 | --Close the sides we don't need, otherwise they will be left hanging | |
561 | 0 | ret=close(ipipe[2]) |
562 | 0 | ret=close(opipe[1]) |
563 | 0 | ret=close(epipe[1]) |
564 | ||
565 | --What does this do? | |
566 | 0 | ret=os_signal(15, os_sig_dfl)--15 = sigterm |
567 | ||
568 | --dup our pipe descriptors to STD*, then close them so they aren't left hanging | |
569 | 0 | ret=os_dup2(ipipe[1], os_stdin) |
570 | 0 | ret=close(ipipe[1]) |
571 | ||
572 | 0 | ret=os_dup2(opipe[2], os_stdout) |
573 | 0 | ret=close(opipe[2]) |
574 | ||
575 | 0 | ret=os_dup2(epipe[2], os_stderr) |
576 | 0 | ret=close(epipe[2]) |
577 | ||
578 | --Replace the forked child process with the process we intend to launch | |
579 | 0 | ret=os_execv(command,args) |
580 | ||
581 | --We should never reach this, so its an error no matter what happens | |
582 | 0 | error() |
583 | 2 | elsif pid=-1 then |
584 | --Failed to fork | |
585 | --Close all the descriptors | |
586 | 0 | ret=close(ipipe[1]) |
587 | 0 | ret=close(ipipe[2]) |
588 | 0 | ret=close(opipe[1]) |
589 | 0 | ret=close(opipe[2]) |
590 | 0 | ret=close(epipe[1]) |
591 | 0 | ret=close(epipe[2]) |
592 | 0 | return -1 |
593 | else | |
594 | --Parent process | |
595 | ||
596 | --Process info | |
597 | 2 | p={ipipe[2], opipe[1], epipe[1], pid} |
598 | ||
599 | --Close the sides we don't need, otherwise they will be left hanging | |
600 | 2 | ret=close(ipipe[1]) |
601 | 2 | ret=close(opipe[2]) or ret |
602 | 2 | ret=close(epipe[2]) or ret |
603 | ||
604 | --If any failed to close, something is wrong with them, so bail out | |
605 | 2 | if ret then |
606 | 0 | kill(p) |
607 | 0 | return -1 |
608 | end if | |
609 | ||
610 | 2 | return p |
611 | end if | |
612 | end function | |
613 | ||
614 | --*NIX version of exec() | |
615 | ||
616 | --See docs above in WIN32 version | |
617 | 2 | |
618 | --*NIX needs exe and args separated, | |
619 | --but for Windows compatibility, we need to accept a command line | |
620 | ||
621 | --PHP's proc_open() does it this way. | |
622 | --If there is a better way, please fix it. | |
623 | --Need to make sure this works on all *NIX platforms | |
624 | 2 | return exec_args("/bin/sh",{"-c", cmd}, pipe) |
625 | end function | |
626 | end ifdef |