5 import Network.HTTP.Lucu
6 import Rakka.Environment
7 import Rakka.Resource.Index
8 import Rakka.Resource.Object
9 import Rakka.Resource.Render
10 import System.Console.GetOpt
11 import System.Directory
12 import System.Environment
14 import System.Posix.Files
15 import System.Posix.Types
16 import System.Posix.User
20 = OptPortNum PortNumber
28 defaultPort :: PortNumber
29 defaultPort = fromIntegral 8080
31 defaultLocalStateDir :: FilePath
32 defaultLocalStateDir = LOCALSTATEDIR -- replaced by CPP
34 defaultUserName :: String
35 defaultUserName = "daemon"
37 defaultGroupName :: String
38 defaultGroupName = "daemon"
41 options :: [OptDescr CmdOpt]
42 options = [ Option ['p'] ["port"]
43 (ReqArg (OptPortNum . fromIntegral . read) "NUM")
44 ("Port number to listen. (default: " ++ show defaultPort ++ ")")
46 , Option ['d'] ["localstatedir"]
47 (ReqArg OptLSDir "DIR")
48 ("Path to the database directory. (default: " ++ defaultLocalStateDir ++ ")")
50 , Option ['u'] ["user"]
51 (ReqArg OptUserName "USER")
52 ("Which user to setuid. (default: " ++ defaultUserName ++ ")")
54 , Option ['g'] ["group"]
55 (ReqArg OptGroupName "GROUP")
56 ("Which user to setgid. (default: " ++ defaultGroupName ++ ")")
58 , Option ['h'] ["help"]
65 printUsage = do putStrLn "Usage:"
66 putStrLn " rakka [OPTIONS...]"
68 putStr $ usageInfo "Options:" options
72 main = do (opts, nonOpts, errors) <- return . getOpt Permute options =<< getArgs
74 when (not $ null errors)
75 $ do mapM_ putStr errors
76 exitWith $ ExitFailure 1
78 when (any (\ x -> x == OptHelp) opts)
82 when (not $ null nonOpts)
84 exitWith $ ExitFailure 1
86 portNum <- getPortNum opts
88 gid <- getGroupID opts
89 lsdir <- getLocalStateDir opts
91 createLocalStateDir lsdir uid gid
96 env <- setupEnv lsdir portNum
97 runHttpd (envLucuConf env) (resTree env) [fallbackRender env]
100 resTree :: Environment -> ResTree
102 = mkResTree [ ([] , resIndex env)
103 , (["object"], resObject env)
107 getPortNum :: [CmdOpt] -> IO PortNumber
109 = do let xs = mapMaybe (\ x -> case x of
110 OptPortNum n -> Just n
113 [] -> return defaultPort
115 _ -> error "too many --port options."
118 getUserID :: [CmdOpt] -> IO UserID
120 = do let xs = mapMaybe (\ x -> case x of
121 OptUserName n -> Just n
124 [] -> defaultUserName
126 _ -> error "too many --user options."
128 userEnt <- getUserEntryForName name
129 return $ userID userEnt
132 getGroupID :: [CmdOpt] -> IO GroupID
134 = do let xs = mapMaybe (\ x -> case x of
135 OptGroupName n -> Just n
138 [] -> defaultGroupName
140 _ -> error "too many --group options."
142 groupEnt <- getGroupEntryForName name
143 return $ groupID groupEnt
146 getLocalStateDir :: [CmdOpt] -> IO FilePath
147 getLocalStateDir opts
148 = do let xs = mapMaybe (\ x -> case x of
152 [] -> defaultLocalStateDir
154 _ -> error "too many --localstatedir options."
159 createLocalStateDir :: FilePath -> UserID -> GroupID -> IO ()
160 createLocalStateDir path uid gid
161 = do createDirectoryIfMissing True path
162 setOwnerAndGroup path uid gid