module SafeProcess where
import Control.Concurrent
import Control.Exception
import System.Exit
import System.IO
import System.Timeout
import System.Posix.Signals
import System.Process
import System.Process.Internals
safeReadProcessTimeout :: String -> [String] -> String -> Int -> IO (Maybe (Either String String))
safeReadProcessTimeout prog args input tout = timeout (tout*1000) $ safeReadProcess prog args input
safeCreateProcess :: String -> [String] -> StdStream -> StdStream -> StdStream
-> ( ( Maybe Handle
, Maybe Handle
, Maybe Handle
, ProcessHandle
) -> IO a )
-> IO a
safeCreateProcess prog args streamIn streamOut streamErr fun = bracket
( do
h <- createProcess (proc prog args)
{ std_in = streamIn
, std_out = streamOut
, std_err = streamErr
, create_group = True }
return h
)
(\(_, _, _, ph) -> terminateProcessGroup ph >> waitForProcess ph)
fun
safeReadProcess :: String -> [String] -> String -> IO (Either String String)
safeReadProcess prog args str =
safeCreateProcess prog args CreatePipe CreatePipe Inherit
(\(Just inh, Just outh, _, ph) -> do
hSetBinaryMode inh True
hSetBinaryMode outh True
hPutStr inh str
hClose inh
output <- hGetContents outh
outMVar <- newEmptyMVar
forkIO $ evaluate (length output) >> putMVar outMVar ()
takeMVar outMVar
hClose outh
ex <- waitForProcess ph
case ex of
ExitSuccess -> return $ Right output
ExitFailure r -> return $ Left $ prog ++ " " ++ show args ++ " failed, errorcode = " ++ show r
)
terminateProcessGroup :: ProcessHandle -> IO ()
terminateProcessGroup ph = do
let (ProcessHandle pmvar) = ph
ph_ <- readMVar pmvar
case ph_ of
OpenHandle pid -> do
signalProcessGroup 15 pid
_ -> return ()