5 import Network.HTTP.Lucu
6 import Rakka.Environment
7 import Rakka.Resource.Index
8 import Rakka.Resource.Object
9 import Rakka.Resource.Page
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
19 = OptPortNum PortNumber
27 defaultPort :: PortNumber
28 defaultPort = fromIntegral 8080
30 defaultLocalStateDir :: FilePath
31 defaultLocalStateDir = LOCALSTATEDIR -- replaced by CPP
33 defaultUserName :: String
34 defaultUserName = "daemon"
36 defaultGroupName :: String
37 defaultGroupName = "daemon"
40 options :: [OptDescr CmdOpt]
41 options = [ Option ['p'] ["port"]
42 (ReqArg (OptPortNum . fromIntegral . read) "NUM")
43 ("Port number to listen. (default: " ++ show defaultPort ++ ")")
45 , Option ['d'] ["localstatedir"]
46 (ReqArg OptLSDir "DIR")
47 ("Path to the database directory. (default: " ++ defaultLocalStateDir ++ ")")
49 , Option ['u'] ["user"]
50 (ReqArg OptUserName "USER")
51 ("Which user to setuid. (default: " ++ defaultUserName ++ ")")
53 , Option ['g'] ["group"]
54 (ReqArg OptGroupName "GROUP")
55 ("Which user to setgid. (default: " ++ defaultGroupName ++ ")")
57 , Option ['h'] ["help"]
64 printUsage = do putStrLn "Usage:"
65 putStrLn " rakka [OPTIONS...]"
67 putStr $ usageInfo "Options:" options
71 main = do (opts, nonOpts, errors) <- return . getOpt Permute options =<< getArgs
73 when (not $ null errors)
74 $ do mapM_ putStr errors
75 exitWith $ ExitFailure 1
77 when (any (\ x -> x == OptHelp) opts)
81 when (not $ null nonOpts)
83 exitWith $ ExitFailure 1
85 portNum <- getPortNum opts
87 gid <- getGroupID opts
88 lsdir <- getLocalStateDir opts
90 createLocalStateDir lsdir uid gid
95 env <- setupEnv lsdir portNum
96 runHttpd (envLucuConf env) (resTree env) [fallbackPage env]
99 resTree :: Environment -> ResTree
101 = mkResTree [ ([] , resIndex env)
102 , (["object"], resObject env)
106 getPortNum :: [CmdOpt] -> IO PortNumber
108 = do let xs = mapMaybe (\ x -> case x of
109 OptPortNum n -> Just n
112 [] -> return defaultPort
114 _ -> error "too many --port options."
117 getUserID :: [CmdOpt] -> IO UserID
119 = do let xs = mapMaybe (\ x -> case x of
120 OptUserName n -> Just n
123 [] -> defaultUserName
125 _ -> error "too many --user options."
127 userEnt <- getUserEntryForName name
128 return $ userID userEnt
131 getGroupID :: [CmdOpt] -> IO GroupID
133 = do let xs = mapMaybe (\ x -> case x of
134 OptGroupName n -> Just n
137 [] -> defaultGroupName
139 _ -> error "too many --group options."
141 groupEnt <- getGroupEntryForName name
142 return $ groupID groupEnt
145 getLocalStateDir :: [CmdOpt] -> IO FilePath
146 getLocalStateDir opts
147 = do let xs = mapMaybe (\ x -> case x of
151 [] -> defaultLocalStateDir
153 _ -> error "too many --localstatedir options."
158 createLocalStateDir :: FilePath -> UserID -> GroupID -> IO ()
159 createLocalStateDir path uid gid
160 = do createDirectoryIfMissing True path
161 setOwnerAndGroup path uid gid