2 Domtool (http
://hcoop
.sf
.net
/)
3 Copyright (C
) 2004 Adam Chlipala
5 This program is free software
; you can redistribute it
and/or
6 modify it under the terms
of the GNU General Public License
7 as published by the Free Software Foundation
; either version
2
8 of the License
, or (at your option
) any later version
.
10 This program is distributed
in the hope that it will be useful
,
11 but WITHOUT ANY WARRANTY
; without even the implied warranty
of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
. See the
13 GNU General Public License for more details
.
15 You should have received a copy
of the GNU General Public License
16 along
with this program
; if not
, write to the Free Software
17 Foundation
, Inc
., 59 Temple Place
- Suite
330, Boston
, MA
02111-1307, USA
.
20 (* Main domtool
structure *)
26 val uid
= Posix
.ProcEnv
.wordToUid (SysWord
.fromInt uid
)
28 val dprint
= if debug
then (fn x
=> print (x ^
"\n")) else (fn _
=> ())
31 ((*dprint ("Open " ^ fname ^
"....");*)
35 ((*dprint ("Open dir " ^ fname ^
"....");*)
36 Posix
.FileSys
.opendir fname
)
40 val s
= TextIO.inputLine fl
42 if size s
= 0 orelse String.sub (s
, 0) <> #
"#" then
57 type map
= string StringMap
.map
58 type set
= StringSet
.set
60 type handlerData
= {path
: string,
67 type mkdomData
= {path
: string,
69 type handler
= {init
: unit
-> unit
,
70 file
: handlerData
-> unit
,
71 finish
: unit
-> unit
,
72 publish
: unit
-> OS
.Process
.status
,
73 mkdom
: mkdomData
-> OS
.Process
.status
}
75 val nullHandler
= {init
= fn () => (),
76 file
= fn (_
: handlerData
) => (),
78 publish
= fn () => OS
.Process
.success
,
79 mkdom
= fn (_
: mkdomData
) => OS
.Process
.success
}
81 val vhostHandler
= ref nullHandler
82 fun setVhostHandler f
= vhostHandler
:= f
84 val handlers
= ref (StringMap
.empty
: handler StringMap
.map
)
85 fun setHandler (fname
, handler
) = handlers
:= StringMap
.insert (!handlers
, fname
, handler
)
87 fun error (path
, msg
) = print (path ^
": " ^ msg ^
"\n")
91 val vhostHandler
= !vhostHandler
93 val _
= Posix
.FileSys
.mkdir (lockFile
, Posix
.FileSys
.S
.irwxu
)
95 fun readDir (path
, prefix
, vars
, paths
, users
, groups
) =
97 val _
= dprint ("readDir: " ^ path
)
98 val dir
= opendir path
101 if Posix
.FileSys
.access (path ^
"/.vars", []) then
103 val vf
= openIn (path ^
"/.vars")
107 val line
= inputLine vf
112 (case String.tokens
Char.isSpace line
of
115 loop (StringMap
.insert (vars
, n
, v
))
117 (error (path ^
"/.vars", "Invalid variable declaration: " ^
118 String.substring (line
, 0, size line
- 1));
124 before TextIO.closeIn vf
129 val pp
= path ^
"/.paths"
131 if Posix
.FileSys
.access (pp
, []) then
132 (if Posix
.FileSys
.ST
.uid (Posix
.FileSys
.stat pp
) = uid
then
138 val line
= inputLine vf
143 (case String.tokens
Char.isSpace line
of
144 [path
] => loop (StringSet
.add (paths
, path
))
149 before TextIO.closeIn vf
152 (error (pp
, "wrong owner to be used");
157 val up
= path ^
"/.users"
159 if Posix
.FileSys
.access (up
, []) then
160 (if Posix
.FileSys
.ST
.uid (Posix
.FileSys
.stat up
) = uid
then
166 val line
= inputLine vf
171 (case String.tokens
Char.isSpace line
of
172 [user
] => loop (StringSet
.add (users
, user
))
177 before TextIO.closeIn vf
180 (error (up
, ": wrong owner to be used.");
185 val gp
= path ^
"/.groups"
187 if Posix
.FileSys
.access (gp
, []) then
188 (if Posix
.FileSys
.ST
.uid (Posix
.FileSys
.stat gp
) = uid
then
194 val line
= inputLine vf
199 (case String.tokens
Char.isSpace line
of
200 [group
] => loop (StringSet
.add (groups
, group
))
205 before TextIO.closeIn vf
208 (error (gp
, "wrong owner to be used.");
213 fun loop (name
, ()) =
215 val path
' = path ^
"/" ^ name
216 val prefix
' = domPrep (name
, prefix
)
218 if not (Posix
.FileSys
.access (path
', [])) then
220 else if Posix
.FileSys
.ST
.isDir (Posix
.FileSys
.stat path
') then
221 readDir (path
', prefix
', vars
, paths
, users
, groups
)
222 else if isTmp name
then
224 else case StringMap
.find (!handlers
, name
) of
225 NONE
=> if validHost name
andalso path
' <> defaultWebPath
then
226 #file vhostHandler
{path
= path
',
235 | SOME
{file
, ...} => file
{path
= path
',
244 ioOptLoop (fn () => Posix
.FileSys
.readdir dir
) loop ();
245 Posix
.FileSys
.closedir dir
246 end handle Io
=> error (path
, "IO error")
248 #init
vhostHandler ();
249 StringMap
.app (fn {init
, ...} => init ()) (!handlers
);
250 readDir (dataDir
, "", StringMap
.empty
,
251 StringSet
.empty
, StringSet
.empty
, StringSet
.empty
);
252 StringMap
.app (fn {finish
, ...} => finish ()) (!handlers
);
253 #finish
vhostHandler ();
254 Posix
.FileSys
.rmdir lockFile
;
255 print
"Processing complete.\n";
256 OS
.Process
.system dompub
257 end handle Io
=> (print
"IO error. Is domtool already running?\n";
260 fun combineStatus (a
, b
) =
261 if OS
.Process
.isSuccess a
andalso OS
.Process
.isSuccess b
then
267 StringMap
.foldl (fn ({publish
, ...}, status
) =>
268 combineStatus (status
, publish ()))
269 (#
publish (!vhostHandler
) ())
274 fun mkd (tokens
, acc
) =
279 val dir
= acc ^
"/" ^ dir
281 if not (Posix
.FileSys
.access (dir
, []))
282 andalso OS
.Process
.system ("mkdir " ^ dir
) = OS
.Process
.failure
then
283 (print ("Can't created directory " ^ dir ^
"\n");
289 mkd (String.tokens (fn ch
=> ch
= #
"/") dir
, dataDir
)
292 fun mkdom (dom
, user
) =
293 if not (validDomain dom
) then
294 (print
"Invalid domain\n";
296 else if not (validUser user
) then
297 (print
"Invalid user\n";
302 val dir
= dataDir ^ dir
'
305 orelse OS
.Process
.system ("echo " ^ user ^
" >" ^ dir ^
"/.users") = OS
.Process
.failure
306 orelse OS
.Process
.system ("echo " ^ user ^
" >" ^ dir ^
"/.groups") = OS
.Process
.failure
307 orelse OS
.Process
.system ("echo /home/" ^ user ^
" >" ^ dir ^
"/.paths") = OS
.Process
.failure
308 orelse OS
.Process
.system ("chown -R " ^ user ^
"." ^ user ^
" " ^ dir
) = OS
.Process
.failure
309 orelse OS
.Process
.system ("chmod -R g+w " ^ dir
) = OS
.Process
.failure
310 orelse OS
.Process
.system ("chown domains.adm " ^ dir ^
"/.users " ^ dir ^
"/.groups " ^ dir ^
"/.paths") = OS
.Process
.failure
then
311 (print
"Setup failed\n";
313 else if not (OS
.Process
.isSuccess
314 (StringMap
.foldl (fn ({mkdom
, ...}, status
) =>
315 combineStatus (status
, mkdom
{path
= dir
, domain
= dom
}))
316 (#
mkdom (!vhostHandler
) {path
= dir
, domain
= dom
})
318 (print
"Setup failed\n";
321 (print
"Domain created\n";