module Shell where import System.Posix.Process import System.Posix.IO import Control.Concurrent import IO launch :: String -> [String] -> String -> IO (ProcessStatus, String, String) launch prog args inputStr = do (childIn, parentIn) <- createPipe (parentOut, childOut) <- createPipe (parentErr, childErr) <- createPipe forkProcess >>= \pid -> case pid of Nothing -> do -- child closeFd parentIn closeFd parentOut closeFd parentErr closeFd 0 -- FIXME: What if some of 0,1,2 are already closed? closeFd 1 closeFd 2 childIn `dupTo` 0 childOut `dupTo` 1 childErr `dupTo` 2 closeFd childIn closeFd childOut closeFd childErr executeFile prog True args Nothing fail "launch: executeFile failed" Just child -> do -- parent closeFd childIn closeFd childOut closeFd childErr input <- fdToHandle parentIn output <- fdToHandle parentOut err <- fdToHandle parentErr outputCS <- hGetContents output errCS <- hGetContents err outputMV <- newEmptyMVar errMV <- newEmptyMVar inputMV <- newEmptyMVar forkIO $ hPutStr input inputStr >> hClose input >> putMVar inputMV () forkIO $ foldr seq () outputCS `seq` hClose output >> putMVar outputMV () forkIO $ foldr seq () errCS `seq` hClose err >> putMVar errMV () takeMVar outputMV takeMVar errMV takeMVar inputMV mStatus <- getProcessStatus True False child case mStatus of Nothing -> fail "launch: can't get child process status" Just stat -> return (stat, outputCS, errCS)