+datatype file_action' =
+ Add' of {src : string, dst : string}
+ | Delete' of string
+ | Modify' of {src : string, dst : string}
+
+fun findDiffs (site, dom, acts) =
+ let
+ val gp = getPath dom
+ val realPath = gp (Config.resultRoot, site)
+ val tmpPath = gp (Config.tmpDir, site)
+
+ (*val _ = print ("getDiffs(" ^ site ^ ", " ^ dom ^ ")... " ^ realPath ^ "; " ^ tmpPath ^ "\n")*)
+
+ val dir = Posix.FileSys.opendir realPath
+
+ fun loopReal acts =
+ case Posix.FileSys.readdir dir of
+ NONE => (Posix.FileSys.closedir dir;
+ acts)
+ | SOME fname =>
+ let
+ val real = OS.Path.joinDirFile {dir = realPath,
+ file = fname}
+ val tmp = OS.Path.joinDirFile {dir = tmpPath,
+ file = fname}
+ in
+ if Posix.FileSys.ST.isDir (Posix.FileSys.stat real) then
+ loopReal acts
+ else if Posix.FileSys.access (tmp, []) then
+ if Slave.shell [Config.diff, " ", real, " ", tmp] then
+ loopReal acts
+ else
+ loopReal ((site, dom, realPath, Modify' {src = tmp, dst = real}) :: acts)
+ else
+ loopReal ((site, dom, realPath, Delete' real) :: acts)
+ end
+
+ val acts = loopReal acts
+
+ val dir = Posix.FileSys.opendir tmpPath
+
+ fun loopTmp acts =
+ case Posix.FileSys.readdir dir of
+ NONE => (Posix.FileSys.closedir dir;
+ acts)
+ | SOME fname =>
+ let
+ val real = OS.Path.joinDirFile {dir = realPath,
+ file = fname}
+ val tmp = OS.Path.joinDirFile {dir = tmpPath,
+ file = fname}
+ in
+ if Posix.FileSys.ST.isDir (Posix.FileSys.stat tmp) then
+ loopTmp acts
+ else if Posix.FileSys.access (real, []) then
+ loopTmp acts
+ else
+ loopTmp ((site, dom, realPath, Add' {src = tmp, dst = real}) :: acts)
+ end
+
+ val acts = loopTmp acts
+ in
+ acts
+ end
+
+fun findAllDiffs () =
+ let
+ val dir = Posix.FileSys.opendir Config.tmpDir
+ val len = length (String.fields (fn ch => ch = #"/") Config.tmpDir) + 1
+
+ fun exploreSites diffs =
+ case Posix.FileSys.readdir dir of
+ NONE => diffs
+ | SOME site =>
+ let
+ fun explore (dname, diffs) =
+ let
+ val dir = Posix.FileSys.opendir dname
+
+ fun loop diffs =
+ case Posix.FileSys.readdir dir of
+ NONE => diffs
+ | SOME name =>
+ let
+ val fname = OS.Path.joinDirFile {dir = dname,
+ file = name}
+ in
+ loop (if Posix.FileSys.ST.isDir (Posix.FileSys.stat fname) then
+ let
+ val dom = String.fields (fn ch => ch = #"/") fname
+ val dom = List.drop (dom, len)
+ val dom = String.concatWith "." (rev dom)
+
+ val dname' = OS.Path.joinDirFile {dir = dname,
+ file = name}
+ in
+ explore (dname',
+ findDiffs (site, dom, diffs))
+ end
+ else
+ diffs)
+ end
+ in
+ loop diffs
+ before Posix.FileSys.closedir dir
+ end
+ in
+ exploreSites (explore (OS.Path.joinDirFile {dir = Config.tmpDir,
+ file = site}, diffs))
+ end
+ in
+ exploreSites []
+ before Posix.FileSys.closedir dir
+ end
+
+val masterNode : string option ref = ref NONE
+fun dnsMaster () = !masterNode
+
+val _ = Env.containerV_one "domain"
+ ("domain", Env.string)
+ (fn (evs, dom) =>
+ let
+ val kind = Env.env dnsKind (evs, "DNS")
+ val ttl = Env.env Env.int (evs, "TTL")
+ val aliases = Env.env (Env.list Env.string) (evs, "Aliases")
+
+ val path = getPath dom
+
+ val () = (current := dom;
+ currentsAli := Slave.remove (Slave.removeDups aliases, dom);
+ currentPath := (fn site => path (Config.tmpDir, site));
+ currentPathAli := (fn (dom, site) => getPath dom (Config.tmpDir, site)))
+
+ fun saveSoa (kind, soa : soa) node =
+ let
+ val {write, writeDom, close} = domainsFile {node = node, name = "soa"}
+ in
+ write kind;
+ write "\n";
+ write (Int.toString ttl);
+ write "\n";
+ write (#ns soa);
+ write "\n";
+ case #serial soa of
+ NONE => ()
+ | SOME n => write (Int.toString n);
+ write "\n";
+ write (Int.toString (#ref soa));
+ write "\n";
+ write (Int.toString (#ret soa));
+ write "\n";
+ write (Int.toString (#exp soa));
+ write "\n";
+ write (Int.toString (#min soa));
+ write "\n";
+ close ()
+ end
+
+ fun saveNamed (kind, soa : soa, masterIp, slaveIps) node =
+ if dom = "localhost" then
+ ()
+ else let
+ val {write, writeDom, close} = domainsFile {node = node, name = "named.conf"}
+ in
+ write "\nzone \"";
+ writeDom ();
+ write "\" {\n\ttype ";
+ write kind;
+ write ";\n\tfile \"";
+ write Config.Bind.zonePath_real;
+ write "/";
+ writeDom ();
+ write ".zone\";\n";
+ case kind of
+ "master" => (write "\tallow-transfer {\n";
+ app (fn ip => (write "\t\t";
+ write ip;
+ write ";\n")) slaveIps;
+ write "\t};\n")
+ | _ => (write "\tmasters { ";
+ write masterIp;
+ write "; };\n");
+ write "};\n";
+ close ()
+ end
+ in
+ case kind of
+ NoDns => masterNode := NONE
+ | UseDns dns =>
+ let
+ val masterIp =
+ case #master dns of
+ InternalMaster node => nodeIp node
+ | ExternalMaster ip => ip
+
+ val slaveIps = map nodeIp (#slaves dns)
+ in
+ app (saveSoa ("slave", #soa dns)) (#slaves dns);
+ app (saveNamed ("slave", #soa dns, masterIp, slaveIps)) (#slaves dns);
+ case #master dns of
+ InternalMaster node =>
+ (masterNode := SOME node;
+ saveSoa ("master", #soa dns) node;
+ saveNamed ("master", #soa dns, masterIp, slaveIps) node)
+ | _ => masterNode := NONE;
+ !befores dom
+ end
+ end,