4 import Control.Concurrent ( ThreadId, myThreadId )
5 import Control.Exception ( throwTo )
6 import System.Exit ( ExitCode( ExitSuccess ) )
8 GroupEntry ( groupID ),
23 import System.Posix.Daemonize ( daemonize )
25 import Configuration (
26 Configuration( pidfile,
29 import Logging ( log_info )
31 get_user_id :: Maybe String -> IO UserID
32 get_user_id Nothing = getRealUserID
33 get_user_id (Just s) = fmap userID (getUserEntryForName s)
35 get_group_id :: Maybe String -> IO GroupID
36 get_group_id Nothing = getRealGroupID
37 get_group_id (Just s) = fmap groupID (getGroupEntryForName s)
39 graceful_shutdown :: Configuration -> ThreadId -> IO ()
40 graceful_shutdown cfg main_thread_id = do
41 log_info "SIGTERM received, removing PID file and shutting down."
42 removeLink (pidfile cfg)
43 throwTo main_thread_id ExitSuccess
45 full_daemonize :: Configuration -> IO () -> IO ()
46 full_daemonize cfg program = do
47 -- This is the 'daemonize' from System.Posix.Daemonize.
50 -- We need to do all this stuff *after* we daemonize.
52 -- First write the PID file which probably requires root.
54 writeFile (pidfile cfg) (show pid)
56 -- We need to pass the thread ID to the signal handler so it
57 -- knows which process to "exit."
59 _ <- installHandler sigTERM (Catch (graceful_shutdown cfg tid)) Nothing
61 -- Then drop privileges.
62 get_user_id (run_as_user cfg) >>= setUserID
63 get_group_id (run_as_group cfg) >>= setGroupID
65 -- Finally run the program we were asked to.