module System.Posix.Daemon.IORedirection
(
  redirectStdout,
  redirectStderr,
  redirectStdin
)
where
  
import Control.Monad
  
import System.IO
import System.Posix
  
-- Nota Bene
-- 
-- When redirecting Std* to a file, you need to disable
-- buffering. If buffering isn't disabled, redirection
-- doesn't work, and it's almost as if you redirected to
-- /dev/null, except you may exhaust memory as a bonus.
  
redirectStdout :: FilePath -> IO ()
redirectStdout newPath = do
  redirectFd newPath stdOutput
  disableBuffering stdout

redirectStderr :: FilePath -> IO ()
redirectStderr newPath = do
  redirectFd newPath stdError
  disableBuffering stderr

redirectStdin :: FilePath -> IO ()
redirectStdin newPath = do
  redirectFd newPath stdInput
  disableBuffering stdin

disableBuffering :: Handle -> IO ()
disableBuffering hdl = do
  hSetBuffering hdl NoBuffering
  seekable <- hIsSeekable hdl
  when seekable $ hSeek hdl SeekFromEnd 0

{- Internal -}

safeOpenFd :: FilePath -> IO Fd       
safeOpenFd p = do
  exists <- fileExist p
  when (not exists) $ writeFile p ""
  openFd p ReadWrite Nothing defaultFileFlags
  
redirectFd :: FilePath -> Fd -> IO ()
redirectFd newPath oldFd = void $ do
  newFd <- safeOpenFd newPath
  closeFd oldFd >> dupTo newFd oldFd
  closeFd newFd