moduleData.Conduit.Process.Unix(forkExecuteFile,killProcess,waitForProcess,ProcessStatus(..))whereimportControl.Concurrent(forkIO)importControl.Exception(finally,mask,onException)importControl.Monad(unless,void)importControl.Monad.Trans.Class(lift)importData.ByteString(ByteString,null)importData.ByteString.Unsafe(unsafePackCStringFinalizer,unsafeUseAsCStringLen)importData.Conduit(Sink,Source,yield,($$))importData.Conduit.List(mapM_)importForeign.Marshal.Alloc(free,mallocBytes)importForeign.Ptr(castPtr)importPrelude(Bool(..),IO,Maybe(..),Monad(..),flip,fromIntegral,fst,maybe,snd,($),(.))importSystem.Posix.Directory.ByteString(changeWorkingDirectory)importSystem.Posix.IO.ByteString(closeFd,createPipe,dupTo,fdReadBuf,fdWriteBuf,stdError,stdInput,stdOutput)importSystem.Posix.Process.ByteString(ProcessStatus(..),executeFile,forkProcess,getProcessStatus)importSystem.Posix.Signals(sigKILL,signalProcess)importSystem.Posix.Types(ProcessID)-- | Kill a process by sending it the KILL (9) signal.---- Since 0.1.0killProcess::ProcessID->IO()killProcess=signalProcesssigKILL-- | Fork a new process and execute the given command.---- This is a wrapper around with fork() and exec*() syscalls, set up to work-- with @conduit@ datatypes for standard input, output, and error. If @Nothing@-- is provided for any of those arguments, then the original file handles will-- remain open to the child process.---- If you would like to simply discard data provided by the child process,-- provide @sinkNull@ for stdout and/or stderr. To provide an empty input-- stream, use @return ()@.---- Since 0.1.0forkExecuteFile::ByteString-- ^ command->Bool-- ^ search on PATH?->[ByteString]-- ^ args->Maybe[(ByteString,ByteString)]-- ^ environment->MaybeByteString-- ^ working directory->Maybe(SourceIOByteString)-- ^ stdin->Maybe(SinkByteStringIO())-- ^ stdout->Maybe(SinkByteStringIO())-- ^ stderr->IOProcessIDforkExecuteFilecmdpathargsmenvmwdirmstdinmstdoutmstderr=domin<-withInmstdinmout<-withOutmstdoutmerr<-withOutmstderrpid<-forkProcess$domaybe(return())changeWorkingDirectorymwdircaseminofNothing->return()Just(fdRead,fdWrite)->docloseFdfdWritevoid$dupTofdReadstdInputletgoOutNothing_=return()goOut(Just(fdRead,fdWrite))dest=docloseFdfdReadvoid$dupTofdWritedestgoOutmoutstdOutputgoOutmerrstdErrorexecuteFilecmdpathargsmenvmaybe(return())(closeFd.fst)minmaybe(return())(closeFd.snd)moutmaybe(return())(closeFd.snd)merrreturnpidwherewithInNothing=returnNothingwithIn(Justsrc)=do(fdRead,fdWrite)<-createPipeletsink=mapM_$flipunsafeUseAsCStringLen$\(ptr,size)->void$fdWriteBuffdWrite(castPtrptr)(fromIntegralsize)void$forkIO$(src$$sink)`finally`closeFdfdWritereturn$Just(fdRead,fdWrite)withOutNothing=returnNothingwithOut(Justsink)=do(fdRead,fdWrite)<-createPipeletbuffSize=4096letsrc=dobs<-lift$mask$\restore->doptr<-mallocBytesbuffSizebytesRead<-restore(fdReadBuffdReadptr$fromIntegralbuffSize)`onException`freeptrunsafePackCStringFinalizerptr(fromIntegralbytesRead)(freeptr)unless(nullbs)$doyieldbssrcvoid$forkIO$(src$$sink)`finally`closeFdfdReadreturn$Just(fdRead,fdWrite)-- | Wait until the given process has died, and return its @ProcessStatus@.---- Since 0.1.0waitForProcess::ProcessID->IOProcessStatuswaitForProcesspid=loopwhereloop=getProcessStatusTrueFalsepid>>=maybeloopreturn