DIRECTORY Basics, BasicTime, Checksum, Commander, CommandTool, FS, IO, Rope; BootSmash: CEDAR PROGRAM IMPORTS Basics, BasicTime, Checksum, Commander, CommandTool, FS, IO, Rope = { Smash: Commander.CommandProc = { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; names: LIST OF ROPE = CommandTool.ParseToList[cmd].list; bufferWords: CARDINAL = 1024; bufferBytes: CARDINAL = bufferWords+bufferWords; buffer: REF TEXT = NEW[TEXT[bufferBytes]]; store: BOOL _ FALSE; setChecksum: BOOL _ FALSE; setDate: BOOL _ TRUE; lagChecksum: CARDINAL _ 0; runningChecksum: CARDINAL _ 0; server: ROPE _ NIL; FOR each: LIST OF Rope.ROPE _ names, each.rest WHILE each # NIL DO inStream, outStream: IO.STREAM _ NIL; name: ROPE = each.first; bytes: NAT _ 0; timeBytes: PACKED ARRAY [0..3] OF CHAR = LOOPHOLE[BasicTime.ToPupTime[BasicTime.Now[]]]; IF Rope.Match["-*", name, FALSE] THEN { sense: BOOL _ TRUE; FOR i: INT IN [1..Rope.Length[name]) DO c: CHAR = Rope.Fetch[name, i]; SELECT c FROM '~ => {sense _ FALSE; LOOP}; 'C, 'c => setChecksum _ sense; 'D, 'd => setDate _ sense; 'S, 's => store _ sense; ENDCASE => IO.PutF[cmd.out, "** Warning, bogus switch: %g\n", [rope[Rope.Substr[name, i, 1]]]]; sense _ TRUE; ENDLOOP; LOOP; }; IF server = NIL AND store THEN {server _ name; LOOP}; {ENABLE UNWIND => { IF inStream # NIL THEN {IO.Close[inStream]; inStream _ NIL}; IF outStream # NIL THEN {IO.Close[outStream]; outStream _ NIL}; }; IO.PutF[cmd.out, "Open %g", [rope[name]]]; inStream _ FS.StreamOpen[name ! FS.Error => {IO.PutF[cmd.out, "\n Error - %g\n", [rope[error.explanation]]]; LOOP}; ]; outStream _ FS.StreamOpen[ fileName: "///Temp/BootSmash.temp$", accessOptions: create, keep: 4, createByteCount: IO.GetLength[inStream] ! FS.Error => { IO.PutF[cmd.out, "\n** Error - %g\n", [rope[error.explanation]]]; IO.Close[inStream]; inStream _ NIL; LOOP; }]; IO.PutRope[cmd.out, " ."]; bytes _ IO.GetBlock[inStream, buffer, 0, bufferBytes]; IF setDate THEN { buffer[6+0] _ timeBytes[2]; buffer[6+1] _ timeBytes[3]; buffer[6+2] _ timeBytes[0]; buffer[6+3] _ timeBytes[1]; }; IF setChecksum THEN TRUSTED { runningChecksum _ Checksum.ComputeChecksum[ lagChecksum _ 0, bufferWords, LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[0]]]; }; WHILE bytes > 0 DO IO.PutRope[cmd.out, "."]; IF setChecksum AND IO.GetLength[inStream] = IO.GetIndex[inStream] THEN TRUSTED { lastLoc: LONG POINTER TO CARDINAL = LOOPHOLE[buffer, LONG POINTER TO CARDINAL] + SIZE[TEXT[bytes]] - 1; words: INT = (IO.GetLength[inStream]+1) / 2; oldVal: CARDINAL = lastLoc^; newVal: CARDINAL _ lastLoc^ _ NewValueToMakeChecksumZero[ runningChecksum, oldVal, words - 1, words]; newCS: CARDINAL _ Checksum.ComputeChecksum[ lagChecksum, bytes/2, LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[0]]]; lastLoc^ _ newVal; IO.PutF[cmd.out, "\n (old last word: %bB, new last word: %bB, new checksum: %bB)", [cardinal[oldVal]], [cardinal[newVal]], [cardinal[newCS]] ]; }; IO.PutBlock[outStream, buffer, 0, bytes]; bytes _ IO.GetBlock[inStream, buffer, 0, bufferBytes ! IO.EndOfStream => EXIT]; IF setChecksum THEN TRUSTED { runningChecksum _ Checksum.ComputeChecksum[ lagChecksum _ runningChecksum, bytes/2, LOOPHOLE[buffer, LONG POINTER] + SIZE[TEXT[0]]]; }; ENDLOOP; IO.Close[outStream]; outStream _ NIL; IO.Close[inStream]; inStream _ NIL; }; IO.PutRope[cmd.out, "\n"]; IF store THEN { dest: ROPE = Rope.Cat["/" , server, "//", name]; IO.PutF[cmd.out, "Start copy to %g ...", [rope[dest]]]; [] _ FS.Copy["///Temp/BootSmash.temp$", dest]; IO.PutRope[cmd.out, " done.\n"]; }; ENDLOOP; }; NewValueToMakeChecksumZero: PROC [oldChecksum: CARDINAL, oldValue: CARDINAL, offsetOfOldValue: INT, length: INT] RETURNS [newValue: CARDINAL] = { newValue _ OnesAdd[ LeftCycle[OnesSub[0, oldChecksum], offsetOfOldValue - length], oldValue] }; OnesAdd: PROC [a, b: CARDINAL] RETURNS [c: CARDINAL] = { c _ a + b; IF c < a THEN c _ c + 1; IF c = 177777B THEN c _ 0; }; OnesSub: PROC [a, b: CARDINAL] RETURNS [CARDINAL] = { RETURN[OnesAdd[a, Basics.BITNOT[b]]]; }; LeftCycle: PROC [a: CARDINAL, b: INT] RETURNS [c: CARDINAL] = { n: INT _ b MOD 16; c _ a; IF b < 0 THEN n _ n + 16; UNTIL n = 0 DO IF c < 100000B THEN c _ c*2 ELSE c _ c*2 + 1; n _ n - 1; ENDLOOP; }; Commander.Register[ "BootSmash", Smash, "Smashes the date of a boot file so we can propagate changes."]; }. ΊBootSmash.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) May 12, 1986 9:11:04 pm PDT Switch processing done here. We set the specified switches, then loop to get another name. The ~ character can be used to invert the sense of a switch. We must scramble a certain 4 bytes in the file to be a funny-format date. This is the last page, so set the checksum in the last word of the last page. Κα˜codešœ™Kšœ Οmœ7™BK™/—˜šΟk ˜ Kšœ5žœžœ˜BK˜——šΟn œžœž˜Kšžœ6žœžœ ˜M—K˜šŸœ˜ K˜Kšžœžœžœ˜Kšžœžœžœžœ˜K˜Kšœžœžœžœ%˜8K˜Kšœ žœ˜Kšœ žœ˜0K˜Kš œžœžœžœžœ˜*K˜Kšœžœžœ˜Kšœ žœžœ˜Kšœ žœžœ˜K˜Kšœ žœ˜Kšœžœ˜K˜Kšœžœžœ˜K˜š žœžœžœžœžœžœž˜BKšœžœžœžœ˜%Kšœžœ˜Kšœžœ˜š œ žœžœžœžœ˜(Kšžœ'˜/—K˜šžœžœžœ˜'Kšœ™™™Kšœžœžœ˜šžœžœžœž˜'Kšœžœ˜šžœž˜ Kšœžœžœ˜Kšœ˜Kšœ˜Kšœ˜šžœ˜ šžœ0˜2Kšœ!˜!———Kšœžœ˜ Kšžœ˜—Kšžœ˜Kšœ˜—Kš žœ žœžœžœžœ˜5šœž˜šžœ˜ Kš žœ žœžœžœžœ˜Kšœ˜—K˜š Ÿœžœžœžœžœ˜5Kšžœžœ˜%Kšœ˜—K˜š Ÿ œžœžœžœžœžœ˜?Kšœžœžœ˜K˜Kšžœžœ ˜Kšžœž˜Kšžœ žœ žœžœ˜AKšœ˜—K˜˜KšœT˜T—K˜K˜K˜K˜—…—δ