<> <> <> <> <> <> DIRECTORY Atom, BasicTime USING [GMT], Booting, Convert, FingerLog, FS USING[StreamOpen, Error], IO, Rope; FingerLogImpl: CEDAR MONITOR IMPORTS Atom, Booting, Convert, FS, IO EXPORTS FingerLog = BEGIN OPEN FingerLog; fingerLogName: Rope.ROPE = "///Temp/Finger.Log"; fingerStream: IO.STREAM; <> stateChangeAtom: ATOM = Atom.MakeAtom["StateChange"]; userPropChangeAtom: ATOM = Atom.MakeAtom["UserPropChange"]; machinePropChangeAtom: ATOM = Atom.MakeAtom["MachinePropChange"]; addMachinePropAtom: ATOM = Atom.MakeAtom["AddMachineProp"]; addUserPropAtom: ATOM = Atom.MakeAtom["AddUserProp"]; deleteMachinePropAtom: ATOM = Atom.MakeAtom["DeleteMachineProp"]; deleteUserPropAtom: ATOM = Atom.MakeAtom["DeleteUserProp"]; FlushLog: PUBLIC ENTRY PROC[] ~ { IF fingerStream # NIL THEN fingerStream.Close[]; fingerStream _ FS.StreamOpen[fingerLogName, $write]; fingerStream.SetLength[0]; fingerStream.Close[]; fingerStream _ NIL }; Log: PUBLIC ENTRY PROC[ logEntry: LogEntry ] = TRUSTED { <> IF fingerStream = NIL THEN fingerStream _ FS.StreamOpen[fingerLogName, $append]; WITH entry: logEntry SELECT FROM StateChange => { fingerStream.Put[IO.atom[stateChangeAtom], IO.rope[" "]]; fingerStream.Put[IO.atom[IF entry.event = login THEN $login ELSE $logout], IO.rope[" "]]; fingerStream.Put[IO.rope[entry.user], IO.rope[" "]]; fingerStream.Put[IO.time[entry.time], IO.rope[" "]]; fingerStream.Put[IO.rope[entry.machine], IO.rope["\n"]] }; UserPropChange => { fingerStream.Put[IO.atom[userPropChangeAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.user]], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.val]], IO.rope[" "]]; fingerStream.Put[IO.time[entry.time], IO.rope["\n"]] }; MachinePropChange => { fingerStream.Put[IO.atom[machinePropChangeAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.machine]], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.val]], IO.rope["\n"]] }; AddMachineProp => { fingerStream.Put[IO.atom[addMachinePropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]] }; AddUserProp => { fingerStream.Put[IO.atom[addUserPropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]] }; DeleteUserProp => { fingerStream.Put[IO.atom[deleteUserPropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]] }; DeleteMachineProp => { fingerStream.Put[IO.atom[deleteMachinePropAtom], IO.rope[" "]]; fingerStream.Put[IO.rope[Convert.RopeFromRope[entry.name]], IO.rope[" "]]; fingerStream.Put[IO.int[entry.version], IO.rope["\n"]]}; ENDCASE; fingerStream.Flush[] }; ParseLog: PUBLIC ENTRY PROC[] RETURNS[ stateLog: LIST OF LogEntry ] ~ { ENABLE FS.Error => GOTO Quit; IF fingerStream # NIL THEN fingerStream.Close[]; fingerStream _ FS.StreamOpen[fingerLogName, $read]; BEGIN ENABLE IO.EndOfStream, IO.Error => CONTINUE; op: ATOM; nextEntry: LogEntry; WHILE TRUE DO op _ fingerStream.GetAtom[]; SELECT op FROM stateChangeAtom => { what: ATOM = fingerStream.GetAtom[]; name: Rope.ROPE = fingerStream.GetRopeLiteral[]; when: BasicTime.GMT = fingerStream.GetTime[]; machine: Rope.ROPE = fingerStream.GetRopeLiteral[]; nextEntry _ NEW[ StateChange LogEntryObject _ [StateChange[event: IF what = $login THEN login ELSE logout, user: name, time: when, machine: machine ]] ] }; userPropChangeAtom => { user: Rope.ROPE = fingerStream.GetRopeLiteral[]; name: Rope.ROPE = fingerStream.GetRopeLiteral[]; val: Rope.ROPE = fingerStream.GetRopeLiteral[]; time: BasicTime.GMT = fingerStream.GetTime[]; nextEntry _ NEW[ UserPropChange LogEntryObject _ [UserPropChange[user: user, name: name, val: val, time: time ]] ] }; machinePropChangeAtom => { machine: Rope.ROPE = fingerStream.GetRopeLiteral[]; name: Rope.ROPE = fingerStream.GetRopeLiteral[]; val: Rope.ROPE = fingerStream.GetRopeLiteral[]; nextEntry _ NEW[ MachinePropChange LogEntryObject _ [MachinePropChange[machine: machine, name: name, val: val]] ] }; addMachinePropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ AddMachineProp LogEntryObject _ [AddMachineProp[name: name, version: version]] ] }; addUserPropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ AddUserProp LogEntryObject _ [AddUserProp[name: name, version: version]] ] }; deleteUserPropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ DeleteUserProp LogEntryObject _ [DeleteUserProp[name: name, version: version]] ] }; deleteMachinePropAtom => { name: Rope.ROPE = fingerStream.GetRopeLiteral[]; version: INT = fingerStream.GetInt[]; nextEntry _ NEW[ DeleteMachineProp LogEntryObject _ [DeleteMachineProp[name: name, version: version]] ] }; ENDCASE; IF stateLog = NIL THEN stateLog _ LIST[nextEntry] ELSE { log: LIST OF LogEntry _ stateLog; WHILE log.rest # NIL DO log _ log.rest ENDLOOP; log.rest _ LIST[nextEntry] } ENDLOOP END; fingerStream.Close[! IO.Error, FS.Error => CONTINUE]; fingerStream _ NIL EXITS Quit => {IF fingerStream # NIL THEN fingerStream.Close[! IO.Error, FS.Error => CONTINUE]; fingerStream _ NIL} }; CloseDown: Booting.CheckpointProc ~ { IF fingerStream # NIL THEN { fingerStream.Close[! IO.Error, FS.Error => CONTINUE]; fingerStream _ NIL }; }; Booting.RegisterProcs[c: CloseDown]; END. <> <> <<>>