180 !UnixPTYStream methodsFor:'private'! |
182 !UnixPTYStream methodsFor:'private'! |
181 |
183 |
182 openPTYFor:aCommandString withMode:openMode inDirectory:aDirectory |
184 openPTYFor:aCommandString withMode:openMode inDirectory:aDirectory |
183 "open a pty to the unix command in commandString" |
185 "open a pty to the unix command in commandString" |
184 |
186 |
185 |blocked ptyFdArray execFdArray slaveFd masterFd shellAndArgs |
187 |ptyFdArray slaveFd masterFd env remotePipeEnd result| |
186 shellPath shellArgs mbx mbxName env| |
|
187 |
188 |
188 handle notNil ifTrue:[ |
189 handle notNil ifTrue:[ |
189 "the pipe was already open ... |
190 "the pipe was already open ... |
190 this should (can) not happen." |
191 this should (can) not happen." |
191 ^ self errorAlreadyOpen |
192 ^ self errorAlreadyOpen |
192 ]. |
193 ]. |
193 |
194 |
194 lastErrorNumber := nil. |
195 lastErrorNumber := nil. |
195 exitStatus := nil. |
196 "stdio lib does not work with blocking pipes and interrupts |
196 exitSema := Semaphore new name:'pty exitSema'. |
197 for WIN, Linux, Solaris and probably any other UNIX" |
|
198 buffered := false. |
|
199 hitEOF := false. |
|
200 binary := false. |
197 |
201 |
198 OperatingSystem isVMSlike ifTrue:[ |
202 ptyFdArray := OperatingSystem makePTYPair. |
199 mbx := OperatingSystem createMailBox. |
203 ptyFdArray isNil ifTrue:[ |
200 mbx isNil ifTrue:[ |
204 lastErrorNumber := OperatingSystem lastErrorNumber. |
201 lastErrorNumber := OperatingSystem currentErrorNumber. |
205 ^ self openError:lastErrorNumber. |
202 ^ self openError |
206 ]. |
203 ]. |
207 |
204 mbxName := OperatingSystem mailBoxNameOf:mbx. |
208 masterFd := ptyFdArray at:1. |
205 "/ 'mailBox is ' print. mbx print. ' name is ' print. mbxName printCR. |
209 slaveFd := ptyFdArray at:2. |
206 |
210 |
207 shellPath := ''. |
211 remotePipeEnd := self class forFileDescriptor:slaveFd mode:#readwrite buffered:false handleType:#pipeFilePointer. |
208 shellArgs := aCommandString. |
|
209 |
|
210 execFdArray := Array with:mbx with:mbx with:mbx. |
|
211 ] ifFalse:[ |
|
212 ptyFdArray := OperatingSystem makePTYPair. |
|
213 ptyFdArray isNil ifTrue:[ |
|
214 lastErrorNumber := OperatingSystem currentErrorNumber. |
|
215 ^ self openError |
|
216 ]. |
|
217 |
|
218 shellAndArgs := OperatingSystem commandAndArgsForOSCommand:aCommandString. |
|
219 shellPath := shellAndArgs at:1. |
|
220 shellArgs := shellAndArgs at:2. |
|
221 |
|
222 masterFd := ptyFdArray at:1. |
|
223 slaveFd := ptyFdArray at:2. |
|
224 execFdArray := Array with:slaveFd with:slaveFd with:slaveFd. |
|
225 ]. |
|
226 |
212 |
227 env := Dictionary new. |
213 env := Dictionary new. |
228 env at:'TERM' put:'dumb'. |
214 env at:'TERM' put:'dumb'. |
229 env at:'SHELL' put:shellPath. |
215 env at:'SHELL' put:'/bin/sh'. |
230 |
216 |
231 "/ must block here, to avoid races due to early finishing |
217 osProcess := OSProcess new |
232 "/ subprocesses ... |
218 command:aCommandString; |
233 |
219 directory:aDirectory; |
234 blocked := OperatingSystem blockInterrupts. |
220 environment:env; |
235 |
221 inStream:remotePipeEnd; |
236 pid := Processor |
222 outStream:remotePipeEnd; |
237 monitor:[ |
223 errorStream:remotePipeEnd. |
238 OperatingSystem |
224 |
239 exec:shellPath |
225 result := osProcess startProcess. |
240 withArguments:shellArgs |
226 |
241 environment:env |
227 remotePipeEnd notNil ifTrue:[ |
242 fileDescriptors:execFdArray |
228 remotePipeEnd close. |
243 fork:true |
229 ]. |
244 newPgrp:true |
230 |
245 inDirectory:aDirectory |
231 result ifTrue:[ |
246 showWindow:nil. |
232 self setFileHandle:masterFd mode:openMode. |
247 ] |
|
248 action:[:status | |
|
249 status stillAlive ifFalse:[ |
|
250 exitStatus := status. |
|
251 OperatingSystem closePid:pid. |
|
252 pid := nil. |
|
253 exitSema signal. |
|
254 ]. |
|
255 ]. |
|
256 |
|
257 (OperatingSystem isVMSlike) ifFalse:[ |
|
258 OperatingSystem closeFd:slaveFd. |
|
259 ]. |
|
260 |
|
261 pid notNil ifTrue:[ |
|
262 (OperatingSystem isVMSlike) ifTrue:[ |
|
263 "/ |
|
264 "/ reopen the mailbox as a file ... |
|
265 "/ |
|
266 mbxName := OperatingSystem mailBoxNameOf:mbx. |
|
267 mbxName notNil ifTrue:[ |
|
268 self open:mbxName withMode:openMode |
|
269 ]. |
|
270 ] ifFalse:[ |
|
271 self setFileHandle:masterFd mode:openMode. |
|
272 ] |
|
273 ] ifFalse:[ |
233 ] ifFalse:[ |
274 lastErrorNumber := OperatingSystem currentErrorNumber. |
234 "the pipe open failed for some reason ... |
275 OperatingSystem isVMSlike ifTrue:[ |
|
276 OperatingSystem destroyMailBox:mbx |
|
277 ] ifFalse:[ |
|
278 OperatingSystem closeFd:masterFd. |
|
279 ]. |
|
280 ]. |
|
281 |
|
282 blocked ifFalse:[ |
|
283 OperatingSystem unblockInterrupts |
|
284 ]. |
|
285 |
|
286 lastErrorNumber notNil ifTrue:[ |
|
287 " |
|
288 the pipe open failed for some reason ... |
|
289 ... this may be either due to an invalid command string, |
235 ... this may be either due to an invalid command string, |
290 or due to the system running out of memory (when forking |
236 or due to the system running out of memory (when forking |
291 the unix process) |
237 the unix process)" |
292 " |
238 lastErrorNumber := OperatingSystem lastErrorNumber. |
293 ^ self openError |
239 OperatingSystem closeFd:masterFd. |
294 ]. |
240 ^ self openError:lastErrorNumber. |
295 |
241 ]. |
296 commandString := aCommandString. |
242 |
297 buffered := false. |
243 self registerForFinalization. |
298 |
|
299 hitEOF := false. |
|
300 binary := false. |
|
301 Lobby register:self. |
|
302 |
244 |
303 "Created: / 9.7.1998 / 20:21:42 / cg" |
245 "Created: / 9.7.1998 / 20:21:42 / cg" |
304 "Modified: / 9.7.1998 / 20:28:31 / cg" |
246 "Modified: / 9.7.1998 / 20:28:31 / cg" |
305 ! |
247 ! |
306 |
248 |