6 import Network.HTTP.Lucu
7 import Rakka.Environment
8 import Rakka.Resource.Index
9 import Rakka.Resource.Object
10 import Rakka.Resource.Render
12 import System.Console.GetOpt
13 import System.Directory
14 import System.Environment
17 import System.Log.Handler.Simple
18 import System.Log.Logger
19 import System.Posix.Files
20 import System.Posix.Types
21 import System.Posix.User
27 = OptPortNum PortNumber
31 | OptLogLevel Priority
37 defaultPort :: PortNumber
38 defaultPort = fromIntegral 8080
40 defaultLocalStateDir :: FilePath
41 defaultLocalStateDir = LOCALSTATEDIR -- replaced by CPP
43 defaultUserName :: String
44 defaultUserName = "daemon"
46 defaultGroupName :: String
47 defaultGroupName = "daemon"
50 defaultLogLevel :: Priority
51 defaultLogLevel = NOTICE
54 options :: [OptDescr CmdOpt]
55 options = [ Option ['p'] ["port"]
56 (ReqArg (OptPortNum . fromIntegral . read) "NUM")
57 ("Port number to listen. (default: " ++ show defaultPort ++ ")")
59 , Option ['d'] ["localstatedir"]
60 (ReqArg OptLSDir "DIR")
61 ("Path to the database directory. (default: " ++ defaultLocalStateDir ++ ")")
63 , Option ['u'] ["user"]
64 (ReqArg OptUserName "USER")
65 ("Which user to setuid. (default: " ++ defaultUserName ++ ")")
67 , Option ['g'] ["group"]
68 (ReqArg OptGroupName "GROUP")
69 ("Which user to setgid. (default: " ++ defaultGroupName ++ ")")
71 , Option ['l'] ["log-level"]
72 (ReqArg (OptLogLevel . read) "LEVEL")
73 ("The lowest log level to show. (default: " ++ show defaultLogLevel ++ ")")
75 , Option [] ["disable-stderr-log"]
76 (NoArg OptDisableStderrLog)
77 ("Disable logging to stderr.")
79 , Option ['h'] ["help"]
86 printUsage = do putStrLn "Usage:"
87 putStrLn " rakka [OPTIONS...]"
89 putStr $ usageInfo "Options:" options
93 main = withSubversion $
94 do (opts, nonOpts, errors) <- return . getOpt Permute options =<< getArgs
96 when (not $ null errors)
97 $ do mapM_ putStr errors
98 exitWith $ ExitFailure 1
100 when (any (\ x -> x == OptHelp) opts)
104 when (not $ null nonOpts)
106 exitWith $ ExitFailure 1
108 portNum <- getPortNum opts
109 uid <- getUserID opts
110 gid <- getGroupID opts
111 lsdir <- getLocalStateDir opts
113 createLocalStateDir lsdir uid gid
119 env <- setupEnv lsdir portNum
121 noticeM logger ("Listening to " ++ show portNum ++ "/tcp...")
122 runHttpd (envLucuConf env) (resTree env) [fallbackRender env]
125 resTree :: Environment -> ResTree
127 = mkResTree [ ([] , resIndex env)
128 , (["object"], resObject env)
132 getPortNum :: [CmdOpt] -> IO PortNumber
134 = do let xs = mapMaybe (\ x -> case x of
135 OptPortNum n -> Just n
138 [] -> return defaultPort
140 _ -> error "too many --port options."
143 getUserID :: [CmdOpt] -> IO UserID
145 = do let xs = mapMaybe (\ x -> case x of
146 OptUserName n -> Just n
149 [] -> defaultUserName
151 _ -> error "too many --user options."
153 userEnt <- getUserEntryForName name
154 return $ userID userEnt
157 getGroupID :: [CmdOpt] -> IO GroupID
159 = do let xs = mapMaybe (\ x -> case x of
160 OptGroupName n -> Just n
163 [] -> defaultGroupName
165 _ -> error "too many --group options."
167 groupEnt <- getGroupEntryForName name
168 return $ groupID groupEnt
171 getLocalStateDir :: [CmdOpt] -> IO FilePath
172 getLocalStateDir opts
173 = do let xs = mapMaybe (\ x -> case x of
177 [] -> defaultLocalStateDir
179 _ -> error "too many --localstatedir options."
184 setupLogger :: [CmdOpt] -> IO ()
186 = do let disableStderrLog = find (== OptDisableStderrLog) opts /= Nothing
187 logHandlers = if disableStderrLog then
190 [verboseStreamHandler stderr DEBUG]
191 logLevel = fromMaybe defaultLogLevel
192 $ do OptLogLevel l <- find (\ x -> case x of
193 OptLogLevel _ -> True
197 logHandlers' <- sequence logHandlers
198 updateGlobalLogger rootLoggerName (setHandlers logHandlers' . setLevel logLevel)
201 createLocalStateDir :: FilePath -> UserID -> GroupID -> IO ()
202 createLocalStateDir path uid gid
203 = do createDirectoryIfMissing True path
204 setOwnerAndGroup path uid gid