]> gitweb.michael.orlitzky.com - dead/htsn.git/commitdiff
Add error handling in the daemonization process.
authorMichael Orlitzky <michael@orlitzky.com>
Tue, 24 Dec 2013 00:41:54 +0000 (19:41 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Tue, 24 Dec 2013 00:41:54 +0000 (19:41 -0500)
src/Unix.hs

index 9b0ddaac9d3bbc10dc532b87c233378be2dd19cb..96ec79a8ae798776606678c2971a7464ea7fa406 100644 (file)
@@ -6,12 +6,14 @@ where
 import Control.Concurrent ( ThreadId, myThreadId )
 import Control.Exception ( throwTo )
 import System.Exit ( ExitCode( ExitSuccess ) )
+import System.IO.Error ( catchIOError )
 import System.Posix (
   GroupEntry ( groupID ),
   GroupID,
   Handler ( Catch ),
   UserEntry ( userID ),
   UserID,
+  exitImmediately,
   getGroupEntryForName,
   getProcessID,
   getRealGroupID,
@@ -29,7 +31,8 @@ import Configuration (
   Configuration( pidfile,
                  run_as_group,
                  run_as_user ))
-import Logging ( log_info )
+import Logging ( log_info, log_error )
+import Terminal ( display_error )
 
 -- | 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
@@ -52,11 +55,20 @@ 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).
+--
+--   If that doesn't work, report the error and quit rudely.
+--
 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
+  catchIOError try_nicely (\e -> do
+                             display_error (show e)
+                             log_error (show e)
+                             exitImmediately ExitSuccess )
+  where
+    try_nicely = do
+      removeLink (pidfile cfg)
+      throwTo main_thread_id ExitSuccess
 
 
 -- | Write a PID file, install a SIGTERM handler, drop privileges, and
@@ -69,27 +81,38 @@ full_daemonize cfg program = do
   -- 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' orig_umask)
+  -- This is the 'daemonize' from System.Posix.Daemonize. If it
+  -- doesn't work, we report the error and do not much else.
+  catchIOError (daemonize (program' orig_umask))
+                 (\e -> do
+                    display_error (show e)
+                    log_error (show e))
   where
     -- We need to do all this stuff *after* we daemonize.
     program' orig_umask = do
-      -- First write the PID file which probably requires root.
+      -- First we install a signal handler for sigTERM. We need to
+      -- pass the thread ID to the signal handler so it knows which
+      -- process to "exit."
+      tid <- myThreadId
+      _ <- installHandler sigTERM (Catch (graceful_shutdown cfg tid)) Nothing
+
+      -- Next we drop privileges. Group ID has to go first, otherwise
+      -- you ain't root to change groups.
+      get_group_id (run_as_group cfg) >>= setGroupID
+      get_user_id  (run_as_user cfg) >>= setUserID
+
+      -- Now we create the PID file.
       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
-      -- knows which process to "exit."
-      tid <- myThreadId
-      _ <- installHandler sigTERM (Catch (graceful_shutdown cfg tid)) Nothing
-
-      -- Then drop privileges.
-      get_user_id  (run_as_user cfg)  >>= setUserID
-      get_group_id (run_as_group cfg) >>= setGroupID
+      -- When we later attempt to delete the PID file, it requires
+      -- write permission to the parent directory and not to the PID
+      -- file itself. Therefore, if that's going to work, this has to
+      -- work, even as a limited user.
+      writeFile (pidfile cfg) (show pid)
 
       -- Finally run the program we were asked to.
       program