]> gitweb @ CieloNegro.org - Rakka.git/blobdiff - Main.hs
lockfile and pidfile
[Rakka.git] / Main.hs
diff --git a/Main.hs b/Main.hs
index 02a4cf4702996013cfdcc6dc07c6646b1d707bb0..8ea363baec82c90e24be4f3485e9cf8d2a269da4 100644 (file)
--- a/Main.hs
+++ b/Main.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP #-}
+import           Control.Exception
 import           Control.Monad
 import           Data.List
 import           Data.Maybe
@@ -7,6 +8,7 @@ import           Network.HTTP.Lucu
 import           OpenSSL
 import           Rakka.Environment
 import           Rakka.Resource.CheckAuth
+import           Rakka.Resource.DumpRepos
 import           Rakka.Resource.Index
 import           Rakka.Resource.JavaScript
 import           Rakka.Resource.PageEntity
@@ -14,17 +16,21 @@ import           Rakka.Resource.Object
 import           Rakka.Resource.Render
 import           Rakka.Resource.Search
 import           Rakka.Resource.SystemConfig
-import           Rakka.Resource.TrackBack
+-- import           Rakka.Resource.TrackBack
+import           Rakka.Resource.Users
 import           Rakka.Storage
 import           Subversion
 import           System.Console.GetOpt
 import           System.Directory
 import           System.Environment
 import           System.Exit
+import           System.FilePath
 import           System.IO
 import           System.Log.Handler.Simple
 import           System.Log.Logger
 import           System.Posix.Files
+import           System.Posix.IO
+import           System.Posix.Process
 import           System.Posix.Types
 import           System.Posix.User
 
@@ -39,7 +45,7 @@ data CmdOpt
     | OptUserName  String
     | OptGroupName String
     | OptLogLevel  Priority
-    | OptDisableStderrLog
+    | OptVerbose
     | OptRebuildIndex
     | OptHelp
     deriving (Eq, Show)
@@ -83,13 +89,13 @@ options = [ Option ['p'] ["port"]
                    (ReqArg (OptLogLevel . read) "LEVEL")
                    ("The lowest log level to show. (default: " ++ show defaultLogLevel ++ ")")
 
-          , Option [] ["disable-stderr-log"]
-                   (NoArg OptDisableStderrLog)
-                   ("Disable logging to stderr.")
+          , Option ['v'] ["verbose"]
+                   (NoArg OptVerbose)
+                   "Enable logging to stderr."
 
-          , Option [] ["rebuild-index"]
+          , Option ['r'] ["rebuild-index"]
                    (NoArg OptRebuildIndex)
-                   ("Rebuild the index database.")
+                   "Rebuild the index database."
 
           , Option ['h'] ["help"]
                    (NoArg OptHelp)
@@ -109,7 +115,7 @@ main = withOpenSSL $
        withSubversion $
        do (opts, nonOpts, errors) <- return . getOpt Permute options =<< getArgs
 
-          when (not $ null errors)
+          unless (null errors)
                    $ do mapM_ putStr errors
                         exitWith $ ExitFailure 1
 
@@ -117,7 +123,7 @@ main = withOpenSSL $
                    $ do printUsage
                         exitWith ExitSuccess
 
-          when (not $ null nonOpts)
+          unless (null nonOpts)
                    $ do printUsage
                         exitWith $ ExitFailure 1
 
@@ -126,24 +132,30 @@ main = withOpenSSL $
           gid     <- getGroupID opts
           lsdir   <- getLocalStateDir opts
 
+          -- Create our localstatedir *before* dropping privileges.
           createLocalStateDir lsdir uid gid
 
           setGroupID gid
           setUserID  uid
 
-          setupLogger opts
-          env <- setupEnv lsdir portNum
+          -- Now that we have our localstatedir. Let's acquire a lock
+          -- on the lockfile. Then create other files.
+          withSystemLock (lsdir </> "lock") $
+            withPidFile (lsdir </> "pid") $
+              do setupLogger opts
+                 env <- setupEnv lsdir portNum
 
-          rebuildIndexIfRequested env opts
+                 rebuildIndexIfRequested env opts
 
-          infoM logger ("Listening to " ++ show portNum ++ "/tcp...")
-          runHttpd (envLucuConf env) (resTree env) [fallbackPageEntity env]
+                 infoM logger ("Listening to " ++ show portNum ++ "/tcp...")
+                 runHttpd (envLucuConf env) (resTree env) [fallbackPageEntity env]
 
           
 resTree :: Environment -> ResTree
 resTree env
     = mkResTree [ ([]              , resIndex        env)
                 , (["checkAuth"   ], resCheckAuth    env)
+                , (["dumpRepos"   ], resDumpRepos    env)
                 , (["js"          ], javaScript         )
                 , (["object"      ], resObject       env)
                 , (["render"      ], resRender       env)
@@ -151,7 +163,8 @@ resTree env
                 , (["search.html" ], resSearch       env)
                 , (["search.xml"  ], resSearch       env)
                 , (["systemConfig"], resSystemConfig env)
-                , (["trackback"   ], resTrackBack    env)
+                -- , (["trackback"   ], resTrackBack    env)
+               , (["users"       ], resUsers        env)
                 ]
 
 
@@ -209,16 +222,16 @@ getLocalStateDir opts
 
 setupLogger :: [CmdOpt] -> IO ()
 setupLogger opts
-    = do let disableStderrLog = find (== OptDisableStderrLog) opts /= Nothing
-             logHandlers      = if disableStderrLog then
-                                    []
-                                else
-                                    [verboseStreamHandler stderr DEBUG]
-             logLevel         = fromMaybe defaultLogLevel
-                                $ do OptLogLevel l <- find (\ x -> case x of
-                                                                     OptLogLevel _ -> True
-                                                                     _             -> False) opts
-                                     return l
+    = do let verbose     = find (== OptVerbose) opts /= Nothing
+             logHandlers = if verbose then
+                               [verboseStreamHandler stderr DEBUG]
+                           else
+                               [] -- FIXME: enable file log
+             logLevel    = fromMaybe defaultLogLevel
+                           $ do OptLogLevel l <- find (\ x -> case x of
+                                                                OptLogLevel _ -> True
+                                                                _             -> False) opts
+                                return l
 
          logHandlers' <- sequence logHandlers
          updateGlobalLogger rootLoggerName (setHandlers logHandlers' . setLevel logLevel)
@@ -237,3 +250,29 @@ rebuildIndexIfRequested env opts
                                                _               -> False) opts
          when rebuild
                   $ rebuildIndex (envStorage env)
+
+withSystemLock :: FilePath -> IO a -> IO a
+withSystemLock lockfile = bracket lock' unlock' . const
+    where
+      lock' :: IO Fd
+      lock' = do fd <- openFd
+                       lockfile
+                       ReadWrite
+                       (Just 420) -- 0644, -rw-r--r--
+                       defaultFileFlags
+                 setLock fd (WriteLock, AbsoluteSeek, 0, 0)
+                 return fd
+
+      unlock' :: Fd -> IO ()
+      unlock' = closeFd
+
+withPidFile :: FilePath -> IO a -> IO a
+withPidFile lockfile = bracket mkPid' (const delPid') . const
+    where
+      mkPid' :: IO ()
+      mkPid' = withFile lockfile WriteMode $ \ h ->
+               do pid <- getProcessID
+                  hPutStrLn h (show pid)
+
+      delPid' :: IO ()
+      delPid' = removeFile lockfile