5 import Network.HTTP.Lucu
6 import Rakka.Environment
7 import Rakka.Resource.Index
8 import Rakka.Resource.Object
9 import Rakka.Resource.Render
11 import System.Console.GetOpt
12 import System.Directory
13 import System.Environment
15 import System.Posix.Files
16 import System.Posix.Types
17 import System.Posix.User
21 = OptPortNum PortNumber
29 defaultPort :: PortNumber
30 defaultPort = fromIntegral 8080
32 defaultLocalStateDir :: FilePath
33 defaultLocalStateDir = LOCALSTATEDIR -- replaced by CPP
35 defaultUserName :: String
36 defaultUserName = "daemon"
38 defaultGroupName :: String
39 defaultGroupName = "daemon"
42 options :: [OptDescr CmdOpt]
43 options = [ Option ['p'] ["port"]
44 (ReqArg (OptPortNum . fromIntegral . read) "NUM")
45 ("Port number to listen. (default: " ++ show defaultPort ++ ")")
47 , Option ['d'] ["localstatedir"]
48 (ReqArg OptLSDir "DIR")
49 ("Path to the database directory. (default: " ++ defaultLocalStateDir ++ ")")
51 , Option ['u'] ["user"]
52 (ReqArg OptUserName "USER")
53 ("Which user to setuid. (default: " ++ defaultUserName ++ ")")
55 , Option ['g'] ["group"]
56 (ReqArg OptGroupName "GROUP")
57 ("Which user to setgid. (default: " ++ defaultGroupName ++ ")")
59 , Option ['h'] ["help"]
66 printUsage = do putStrLn "Usage:"
67 putStrLn " rakka [OPTIONS...]"
69 putStr $ usageInfo "Options:" options
73 main = withSubversion $
74 do (opts, nonOpts, errors) <- return . getOpt Permute options =<< getArgs
76 when (not $ null errors)
77 $ do mapM_ putStr errors
78 exitWith $ ExitFailure 1
80 when (any (\ x -> x == OptHelp) opts)
84 when (not $ null nonOpts)
86 exitWith $ ExitFailure 1
88 portNum <- getPortNum opts
90 gid <- getGroupID opts
91 lsdir <- getLocalStateDir opts
93 createLocalStateDir lsdir uid gid
98 env <- setupEnv lsdir portNum
99 runHttpd (envLucuConf env) (resTree env) [fallbackRender env]
102 resTree :: Environment -> ResTree
104 = mkResTree [ ([] , resIndex env)
105 , (["object"], resObject env)
109 getPortNum :: [CmdOpt] -> IO PortNumber
111 = do let xs = mapMaybe (\ x -> case x of
112 OptPortNum n -> Just n
115 [] -> return defaultPort
117 _ -> error "too many --port options."
120 getUserID :: [CmdOpt] -> IO UserID
122 = do let xs = mapMaybe (\ x -> case x of
123 OptUserName n -> Just n
126 [] -> defaultUserName
128 _ -> error "too many --user options."
130 userEnt <- getUserEntryForName name
131 return $ userID userEnt
134 getGroupID :: [CmdOpt] -> IO GroupID
136 = do let xs = mapMaybe (\ x -> case x of
137 OptGroupName n -> Just n
140 [] -> defaultGroupName
142 _ -> error "too many --group options."
144 groupEnt <- getGroupEntryForName name
145 return $ groupID groupEnt
148 getLocalStateDir :: [CmdOpt] -> IO FilePath
149 getLocalStateDir opts
150 = do let xs = mapMaybe (\ x -> case x of
154 [] -> defaultLocalStateDir
156 _ -> error "too many --localstatedir options."
161 createLocalStateDir :: FilePath -> UserID -> GroupID -> IO ()
162 createLocalStateDir path uid gid
163 = do createDirectoryIfMissing True path
164 setOwnerAndGroup path uid gid