+-- | Non-portable code for daemonizing on unix.
+--
module Unix
where
getUserEntryForName,
installHandler,
removeLink,
+ setFileCreationMask,
setGroupID,
setUserID,
sigTERM )
run_as_user ))
import Logging ( log_info )
+-- | Retrieve the uid associated with the given system user name. We
+-- take a Maybe String as an argument so the user name can be passed
+-- in directly from the config.
+--
get_user_id :: Maybe String -> IO UserID
get_user_id Nothing = getRealUserID
get_user_id (Just s) = fmap userID (getUserEntryForName s)
+
+-- | Retrieve the gid associated with the given system group name. We
+-- take a Maybe String as an argument so the group name can be
+-- passed in directly from the config.
+--
get_group_id :: Maybe String -> IO GroupID
get_group_id Nothing = getRealGroupID
get_group_id (Just s) = fmap groupID (getGroupEntryForName s)
+
+-- | This function will be called in response to a SIGTERM; i.e. when
+-- someone tries to kill our process. We simply delete the PID file
+-- and signal our parent thread to quit (successfully).
graceful_shutdown :: Configuration -> ThreadId -> IO ()
graceful_shutdown cfg main_thread_id = do
log_info "SIGTERM received, removing PID file and shutting down."
removeLink (pidfile cfg)
throwTo main_thread_id ExitSuccess
+
+-- | Write a PID file, install a SIGTERM handler, drop privileges, and
+-- finally do the daemonization dance.
+--
full_daemonize :: Configuration -> IO () -> IO ()
full_daemonize cfg program = do
+ -- The call to 'daemonize' will set the umask to zero, but we want
+ -- to retain it. So, we set the umask to zero before 'daemonize'
+ -- can, so that we can record the previous umask value (returned by
+ -- setFileCreationMask).
+ orig_umask <- setFileCreationMask 0
-- This is the 'daemonize' from System.Posix.Daemonize.
- daemonize program'
+ daemonize (program' orig_umask)
where
-- We need to do all this stuff *after* we daemonize.
- program' = do
+ program' orig_umask = do
-- First write the PID file which probably requires root.
pid <- getProcessID
+
+ -- The PID file needs to be read-only for anyone but its
+ -- owner. Hopefully the umask accomplishes this!
+ _ <- setFileCreationMask orig_umask
writeFile (pidfile cfg) (show pid)
-- We need to pass the thread ID to the signal handler so it