import System.Posix.Process
import System.Posix.Signals
import System.Posix.Types
import System.Directory
import System.Exit
import Control.Monad
import Text.Printf

initrc :: [String]
initrc = ["/bin/rc.init"]

main :: IO ()
main = do
  setCurrentDirectory "/"
  actOnPid
  blockSignals fullSignalSet
  spawn initrc -- Spawn rc.init
  installSIGCHLD
  slumber

slumber :: IO ()
slumber = awaitSignal (Just fullSignalSet) >> slumber

reapAll :: IO ()
reapAll = do
  children <- getAnyProcessStatus False False
  case children of
   Nothing -> return ()
   Just (x, y) -> reapAll

installSIGCHLD :: IO Handler
installSIGCHLD = installHandler sigCHLD (Catch reapAll) Nothing

-- Print a "fail" message.
failm :: String -> IO ()
failm s = printf ("[FAIL] " ++ s ++ "\n")

-- Print an "ok" message.
okm :: String -> IO ()
okm s = printf ("[OK] " ++ s ++ "\n")

-- Checks current PID against 1.
checkPid :: IO Bool
checkPid = (== 1) <$> getProcessID

-- Exits if we're not running as PID 1.
actOnPid :: IO ()
actOnPid = checkPid >>=
  (\v -> if v
        then
          okm "Acquired PID 1."
        else
          failm "Assigned invalid PID!" >>
          exitFailure)

-- Spawn a child process and set up its environment
spawn :: [String] -> IO ProcessID
spawn cmd = forkProcess $
              actions
              >> (executeFile prog True args Nothing)
              >> exitImmediately (ExitFailure 1)
  where prog = head cmd
        args = tail cmd
        actions :: IO ProcessGroupID
        actions = do
          unblockSignals fullSignalSet
          createSession
