OS.Process.failure)
| SOME m =>
case m of
- MsgYes => (print "Package exists.\n";
- OS.Process.success)
+ MsgAptQuery {section,description} => (print "Package exists.\n";
+ print ("Section: " ^ section ^ "\n");
+ print ("Description: " ^ description ^ "\n");
+ OS.Process.success)
| MsgNo => (print "Package does not exist.\n";
- OS.Process.failure)
+ OS.Process.failure
+ (* It might be the Wrong Thing (tm) to use MsgNo like this *))
| MsgError s => (print ("APT existence query failed: " ^ s ^ "\n");
OS.Process.failure)
| _ => (print "Unexpected server reply.\n";
fun answerQuery q =
case q of
QApt pkg => if Apt.installed pkg then MsgYes else MsgNo
- | QAptExists pkg => if Apt.exists pkg then MsgYes else MsgNo
+ | QAptExists pkg => (case Apt.info pkg of
+ SOME {section, description} => MsgAptQuery {section = section, description = description}
+ | NONE => MsgNo)
| QCron user => if Cron.allowed user then MsgYes else MsgNo
| QFtp user => if Ftp.allowed user then MsgYes else MsgNo
| QTrustedPath user => if TrustedPath.query user then MsgYes else MsgNo
| MsgReUsers => OpenSSL.writeInt (bio, 41)
| MsgVmailChanged => OpenSSL.writeInt (bio, 42)
| MsgFirewallRegen => OpenSSL.writeInt (bio, 43)
+ | MsgAptQuery {section, description} => (OpenSSL.writeInt (bio, 44);
+ OpenSSL.writeString (bio, section);
+ OpenSSL.writeString (bio, description))
fun checkIt v =
case v of
| 41 => SOME MsgReUsers
| 42 => SOME MsgVmailChanged
| 43 => SOME MsgFirewallRegen
+ | 44 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of
+ (SOME section, SOME description) => SOME (MsgAptQuery {section = section, description = description})
+ | _ => NONE)
| _ => NONE)
end
(* Server tells slave that vmail user information has changed *)
| MsgFirewallRegen
(* Regenerate firewall on user machines *)
+ | MsgAptQuery of {section : string, description : string}
+ (* Answer to QAptExists query *)
end
signature APT = sig
- val exists : string -> bool
- (* Does the package exist on this host? *)
+ val info : string -> {section : string, description : string} option
+ (* Package information *)
val installed : string -> bool
(* Is the named package installed on this host? *)
(* Copyed from the portal, doesn't exactly go out this in the most
direct way, or does it? *)
-fun exists name =
- validName name andalso let
- val proc = Unix.execute ("/usr/bin/apt-cache", ["show", name])
- val inf = Unix.textInstreamOf proc
-
- val _ = TextIO.inputLine inf (* in every let* lies an imperative program in disguise *)
-
- fun loop _ =
- case TextIO.inputLine inf of
- NONE => false
- | SOME line =>
- if size line >= 9 andalso String.substring (line, 0, 9) = "Section: " then
- true
- else if size line >= 13 andalso String.substring (line, 0, 13) = "Description: " then
- false
- else
- loop ()
- in
- loop ()
- before ignore (Unix.reap proc)
- end
+fun info name =
+ if not (validName name) then
+ NONE
+ else
+ let
+ val proc = Unix.execute ("/usr/bin/apt-cache", ["show", name])
+ val inf = Unix.textInstreamOf proc
+
+ val _ = TextIO.inputLine inf (* in every let* lies an imperative program in disguise *)
+
+ fun loop (section, descr) =
+ case TextIO.inputLine inf of
+ NONE => (section, descr)
+ | SOME line =>
+ if size line >= 9 andalso String.substring (line, 0, 9) = "Section: " then
+ loop (SOME (String.substring (line, 9, size line - 10)), descr)
+ else if size line >= 13 andalso String.substring (line, 0, 13) = "Description: " then
+ loop (section, SOME (String.substring (line, 13, size line - 14)))
+ else
+ loop (section, descr)
+ in
+ (case loop (NONE, NONE) of
+ (SOME section, SOME descr) => SOME {section = section, description = descr}
+ | _ => NONE)
+ before ignore (Unix.reap proc)
+ end
fun installed name =
validName name