+-- | Signal handler for reopening log files.
+handleSigHup :: FilePath -> IO ()
+handleSigHup path = do
+ setupDaemonFDs (Just path)
+ logInfo "Reopening log files after receiving SIGHUP"
+
+-- | Sets up a daemon's standard file descriptors.
+setupDaemonFDs :: Maybe FilePath -> IO ()
+setupDaemonFDs logfile = do
+ null_in_handle <- openFile devNull ReadMode
+ null_out_handle <- openFile (fromMaybe devNull logfile) AppendMode
+ hDuplicateTo null_in_handle stdin
+ hDuplicateTo null_out_handle stdout
+ hDuplicateTo null_out_handle stderr
+ hClose null_in_handle
+ hClose null_out_handle
+
+-- | Computes the default bind address for a given family.
+defaultBindAddr :: Int -- ^ The port we want
+ -> Socket.Family -- ^ The cluster IP family
+ -> Result (Socket.Family, Socket.SockAddr)
+defaultBindAddr port Socket.AF_INET =
+ Ok (Socket.AF_INET,
+ Socket.SockAddrInet (fromIntegral port) Socket.iNADDR_ANY)
+defaultBindAddr port Socket.AF_INET6 =
+ Ok (Socket.AF_INET6,
+ Socket.SockAddrInet6 (fromIntegral port) 0 Socket.iN6ADDR_ANY 0)
+defaultBindAddr _ fam = Bad $ "Unsupported address family: " ++ show fam
+
+-- | Default hints for the resolver
+resolveAddrHints :: Maybe Socket.AddrInfo
+resolveAddrHints =
+ Just Socket.defaultHints { Socket.addrFlags = [Socket.AI_NUMERICHOST,
+ Socket.AI_NUMERICSERV] }
+
+-- | Resolves a numeric address.
+resolveAddr :: Int -> String -> IO (Result (Socket.Family, Socket.SockAddr))
+resolveAddr port str = do
+ resolved <- Socket.getAddrInfo resolveAddrHints (Just str) (Just (show port))
+ return $ case resolved of
+ [] -> Bad "Invalid results from lookup?"
+ best:_ -> Ok (Socket.addrFamily best, Socket.addrAddress best)
+
+-- | Based on the options, compute the socket address to use for the
+-- daemon.
+parseAddress :: DaemonOptions -- ^ Command line options
+ -> Int -- ^ Default port for this daemon
+ -> IO (Result (Socket.Family, Socket.SockAddr))
+parseAddress opts defport = do
+ let port = maybe defport fromIntegral $ optPort opts
+ def_family <- Ssconf.getPrimaryIPFamily Nothing
+ case optBindAddress opts of
+ Nothing -> return (def_family >>= defaultBindAddr port)
+ Just saddr -> Control.Exception.catch
+ (resolveAddr port saddr)
+ (ioErrorToResult $ "Invalid address " ++ saddr)
+
+-- | Run an I\/O action that might throw an I\/O error, under a
+-- handler that will simply annotate and re-throw the exception.
+describeError :: String -> Maybe Handle -> Maybe FilePath -> IO a -> IO a
+describeError descr hndl fpath =
+ modifyIOError (\e -> annotateIOError e descr hndl fpath)
+
+-- | Run an I\/O action as a daemon.