-- HelloVIIA.mesa from VolumeInitImplA.mesa edited by: -- Masinter 21-Aug-84 19:51:52 Make Describe ignore nonPilot volumes -- Lichtenberg 14-Jul-84 16:16:45 some Lisp stuff -- Johnsson 2-Dec-83 18:21:20 -- Sweet 17-Oct-83 14:53:35 DIRECTORY Device USING [PilotDisk, Type], DeviceTypes USING [ q2000, q2010, q2020, q2030, q2040, q2080, sa1000, sa1004, sa4000, sa4008, t300, t80], Environment USING [wordsPerPage], File USING [ Delete, File, GetAttributes, ID, nullFile, PageNumber, Type, Unknown, GetSize, PageCount], Heap USING [systemZone], Inline USING [BITROTATE], OthelloDefs USING [ AbortingCommand, CloseFetch, CommandProcessor, Confirm, GetName, IndexTooLarge, LeaderPage, leaderPages, lpVersion, MyNameIs, NewLine, PackedTimeFromString, Question, ReadNumber, RegisterCommandProc, SetCommandString, WriteChar, WriteFixedWidthNumber, WriteLine, WriteLongNumber, WriteOctal, WriteString, Yes], OthelloOps USING [ BadSwitches, BootFileType, DecodeSwitches, DeleteTempFiles, GetDriveSize, GetNextSubVolume, GetPhysicalVolumeBootFile, GetSwitches, GetVolumeBootFile, nullSubVolume, SetDebugger, SetDebuggerSuccess, SetExpirationDate, SetExpirationDateSuccess, SetGetSwitchesSuccess, SetPhysicalVolumeBootFile, SetSwitches, SubVolume, VoidPhysicalVolumeBootFile, VoidVolumeBootFile], PhysicalVolume USING [ AssertPilotVolume, DamageStatus, Error, GetAttributes, GetHandle, GetNext, GetNextBadPage, GetNextDrive, GetNextLogicalVolume, Handle, ID, InterpretHandle, MarkPageBad, maxNameLength, noProblems, nullBadPage, nullDeviceIndex, nullID, Offline, PageNumber, RepairType, Scavenge, ScavengerStatus], Process USING [MsecToTicks], Runtime USING [IsBound], Scavenger USING [ BootFileType, Error, FileEntry, Header, Problem, RepairType, Scavenge], Space USING [CopyIn, Map, ScratchMap, Unmap], SpecialVolume USING [OpenVolume], String USING [ AppendCharAndGrow, AppendLongNumber, AppendString, CopyToNewString, Equivalent, Length, Replace], System USING [ defaultSwitches, GetLocalTimeParameters, gmtEpoch, GreenwichMeanTime, PowerOff, Switches], TemporaryBooting USING [BootButton, BootFromVolume], Volume USING [ Close, Erase, GetAttributes, GetLabelString, GetType, ID, NeedsScavenging, NotOnline, nullID, Open, Type], VolumeVersion USING [Examine]; VolumeInitImplA: PROGRAM IMPORTS File, Heap, Inline, OthelloDefs, OthelloOps, PhysicalVolume, Process, Runtime, Scavenger, Space, SpecialVolume, System, String, TemporaryBooting, Volume, VolumeVersion EXPORTS OthelloDefs SHARES File = BEGIN OPEN OthelloOps, OthelloDefs; commandProcessor: CommandProcessor ← [CommonCommands]; CommonCommands: PROC [index: CARDINAL] = { SELECT index FROM 0 => BootBoot[]; 1 => DeleteBootFiles[]; 2 => DeleteTempFilesUser[]; 3 => DescribePhysicalVolumes[]; 4 => Erase[]; 5 => ListBadPages[]; 6 => ListBootFiles[]; 7 => ListDrives[]; 8 => ListLogicalVolumes[]; 9 => ListPhysicalVolumes[]; 10 => MakeBad[]; 11 => Offline[]; 12 => Online[]; 13 => PowerOff[]; 14 => PVScavenge[]; 15 => Quit[]; 16 => Scavenge[]; 17 => SetBootFileSwitches[]; 18 => SetDebuggerUser[]; 19 => SetExpirationDateUser[]; 20 => SetPvBoot[]; 21 => WizardMode[]; ENDCASE => IndexTooLarge}; logicalVolumeTypeString: ARRAY Volume.Type OF STRING ← [ "normal", "debugger", "debuggerDebugger", "nonPilot"]; inputDriveString: LONG STRING ← NIL; inputLogicalString: LONG STRING ← NIL; debuggerLogicalString: LONG STRING ← NIL; inputPhysString: LONG STRING ← NIL; switches: LONG STRING ← NIL; lvTypeString: LONG STRING ← NIL; expirationString: LONG STRING ← NIL; maxNameLength: CARDINAL = PhysicalVolume.maxNameLength; BootBoot: PROC = BEGIN lvID: Volume.ID; ts: System.Switches; lispFile: File.File; size: File.PageCount; MyNameIs[ myNameIs: "Boot"L, myHelpIs: "Boot From Logical Volume"L]; lvID ← GetLvIDFromUser[].lvID; lispFile ← GetVolumeBootFile[lvID, BootFileType.hardMicrocode].file; IF lispFile # File.nullFile THEN { SpecialVolume.OpenVolume[lispFile.volumeID,read]; size ← File.GetSize[lispFile]; Volume.Close[lispFile.volumeID]; IF size > 1000 THEN { IF Yes["Boot Lisp from this volume? "L] THEN { Volume.Open[lispFile.volumeID]; SetPhysicalVolumeBootFile[lispFile, BootFileType.hardMicrocode,leaderPages]; IF Runtime.IsBound[LOOPHOLE[CloseFetch]] THEN CloseFetch[]; Volume.Close[lispFile.volumeID]; TemporaryBooting.BootButton[]; } }; Volume.Close[lispFile.volumeID]; }; GetSetBootFileSwitches[get, lvID ! Volume.NeedsScavenging, File.Unknown => { WriteLine["(can't get default switches)"L]; CONTINUE}; AbortingCommand => { WriteLine[reason]; WriteLine["(can't get default switches)"L]; CONTINUE}]; DO GetName["switches: "L, @switches, echo, TRUE ! Question => { WriteLine[ "See Pilot Users Handbook for list of valid switches."L]; RESUME}]; ts ← DecodeSwitches[switches ! BadSwitches => {WriteLine["bad switches"L]; LOOP}]; EXIT; ENDLOOP; IF Runtime.IsBound[LOOPHOLE[CloseFetch]] THEN CloseFetch[]; TemporaryBooting.BootFromVolume[lvID, ts]; END; DeleteBootFiles: PROC = BEGIN lvID: Volume.ID; pvID: PhysicalVolume.ID; IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Delete Boot Files"L, myHelpIs: "Delete all boot files from volume"L]; [pvID: pvID, lvID: lvID] ← GetLvIDFromUser[]; FOR t: BootFileType IN [hardMicrocode..pilot] DO file: File.File = GetVolumeBootFile[lvID, t].file; IF file = File.nullFile THEN LOOP; Volume.Open[file.volumeID]; BEGIN ENABLE File.Unknown => CONTINUE; File.Delete[file]; END; VoidVolumeBootFile[lvID, t]; IF GetPhysicalVolumeBootFile[pvID, t].file = file THEN VoidPhysicalVolumeBootFile[pvID, t]; Volume.Close[lvID]; ENDLOOP; END; DeleteTempFilesUser: PROC = { IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Delete Temporary Files"L, myHelpIs: "Delete Temporary Files"L]; DeleteTempFiles[GetLvIDFromUser[].lvID]}; DescribePhysicalVolumes: PROC = BEGIN pvID: PhysicalVolume.ID ← PhysicalVolume.nullID; pvFound: BOOLEAN ← FALSE; nonPID: Volume.Type ← nonPilot; MyNameIs[ myNameIs: "Describe Physical Volumes"L, myHelpIs: "Describe OnLine disk(s) and Volumes"L]; DO h: PhysicalVolume.Handle; s: STRING ← [maxNameLength]; sV: SubVolume ← nullSubVolume; sVFound: BOOLEAN ← FALSE; IF (pvID ← PhysicalVolume.GetNext[pvID]) = PhysicalVolume.nullID THEN EXIT; pvFound ← TRUE; h ← PhysicalVolume.GetAttributes[pvID, s].instance; WriteString["Physical Volume "L]; WriteString[s]; WriteString[" on drive "L]; WriteString[GetDriveStringName[h]]; WriteString[" ("L]; WriteString[ SELECT GetDriveType[h] FROM DeviceTypes.sa1004, DeviceTypes.sa1000 => "Shugart 1000"L, DeviceTypes.sa4000, DeviceTypes.sa4008 => "Shugart 4000"L, DeviceTypes.q2000, DeviceTypes.q2010, DeviceTypes.q2020, DeviceTypes.q2030, DeviceTypes.q2040, DeviceTypes.q2080 => "Quantum 2000"L, DeviceTypes.t80 => "T80"L, DeviceTypes.t300 => "T300"L, ENDCASE => "unknown type"L]; DO needsScavenging: BOOLEAN ← FALSE; nonP: BOOLEAN ← FALSE; freePages, volumeSize: LONG CARDINAL; sV ← GetNextSubVolume[pvID, sV]; IF sV = nullSubVolume THEN EXIT; IF ~sVFound THEN WriteLine[") contains:"L]; sVFound ← TRUE; WriteString["Volume "L]; [volumeSize: volumeSize, freePageCount: freePages] ← Volume.GetAttributes[sV.lvID ! Volume.NeedsScavenging => { needsScavenging ← TRUE; volumeSize ← 0; -- don't really know CONTINUE }]; IF volumeSize # sV.subVolumeSize AND volumeSize # 0 THEN WriteString["piece "L]; GetLogicalVolumeName[sV.lvID, s]; WriteString[s]; WriteString[" (type = "L]; WriteString[GetLogicalVolumeTypeName[sV.lvID]]; WriteString[") "L]; nonP ← GetLogicalVolumeType[sV.lvID]=nonPID; IF ~nonP AND volumeSize = sV.subVolumeSize THEN { WriteLongNumber[freePages]; WriteString[" of "L]; WriteLongNumber[volumeSize]; WriteString[" pages free"L]} ELSE {WriteLongNumber[sV.subVolumeSize]; WriteString[" pages"L]}; IF needsScavenging THEN WriteString[" *** Needs Scavenging ***"L]; NewLine[]; WriteString[" starting at physical address "L]; WriteLongNumber[sV.firstPVPageNumber]; NewLine[]; IF ~nonP AND ~needsScavenging THEN ShowBootFiles[pvID, sV.lvID]; ENDLOOP; IF ~sVFound THEN WriteLine[") no subvolumes"L]; ENDLOOP; IF ~pvFound THEN WriteLine["No physical Volumes found"L]; END; Erase: PROC = { lvID: Volume.ID; pvID: PhysicalVolume.ID; MyNameIs[ myNameIs: "Erase"L, myHelpIs: "Erase logical volume"L]; [pvID: pvID, lvID: lvID] ← GetLvIDFromUser[]; Confirm[]; Volume.Close[lvID]; SELECT VolumeVersion.Examine[lvID] FROM otherVersion => IF Yes["That volume is not in the current format. Do you want to convert it? "L] THEN Confirm[twice] ELSE RETURN; ENDCASE; WriteString["Erasing..."L]; Volume.Erase[lvID]; FOR t: BootFileType IN [hardMicrocode..pilot] DO IF GetPhysicalVolumeBootFile[pvID, t].file.volumeID = lvID THEN VoidPhysicalVolumeBootFile[pvID, t]; ENDLOOP; WriteLine["complete"L]}; ListBadPages: PROC = BEGIN id: PhysicalVolume.ID; page: PhysicalVolume.PageNumber ← PhysicalVolume.nullBadPage; badSpots: BOOLEAN ← FALSE; col: CARDINAL ← 0; MyNameIs[ myNameIs: "List Bad Pages"L, myHelpIs: "List known bad pages on volume"L]; id ← GetPvIDFromUser[].id; WHILE (page ← PhysicalVolume.GetNextBadPage[id, page]) # PhysicalVolume.nullBadPage DO IF col = 6 THEN BEGIN NewLine[]; col ← 0; END; WriteFixedWidthNumber[page, 11]; col ← col + 1; badSpots ← TRUE; ENDLOOP; WriteLine[IF badSpots THEN NIL ELSE "No known bad spots"L]; END; ListBootFiles: PROC = BEGIN lvID: Volume.ID; pvID: PhysicalVolume.ID; MyNameIs[ myNameIs: "List Boot Files"L, myHelpIs: "List boot files currently on logical volume"L]; [pvID: pvID, lvID: lvID] ← GetLvIDFromUser[]; ShowBootFiles[pvID, lvID]; END; ListDrives: PROC = { index: CARDINAL ← PhysicalVolume.nullDeviceIndex; first: BOOLEAN ← TRUE; MyNameIs[myNameIs: "List Drives"L, myHelpIs: "List disk drives"L]; DO index ← PhysicalVolume.GetNextDrive[index]; IF index = PhysicalVolume.nullDeviceIndex THEN EXIT; IF ~first THEN WriteString[", "L]; first ← FALSE; WriteString[GetDriveStringName[PhysicalVolume.GetHandle[index]]]; ENDLOOP; NewLine[]}; ListLogicalVolumes: PROC = BEGIN first: BOOLEAN ← TRUE; pID: PhysicalVolume.ID ← PhysicalVolume.nullID; MyNameIs[ myNameIs: "List Logical Volumes"L, myHelpIs: "List logical volumes"L]; DO sV: SubVolume ← nullSubVolume; pID ← PhysicalVolume.GetNext[pID]; IF pID = PhysicalVolume.nullID THEN EXIT; DO s: STRING ← [maxNameLength]; sV ← GetNextSubVolume[pID, sV]; IF sV = nullSubVolume THEN EXIT; IF sV.firstLVPageNumber # 0 THEN LOOP; IF ~first THEN WriteString[", "L]; WriteString[GetDriveStringName[ PhysicalVolume.GetAttributes[pID].instance]]; WriteChar[':]; GetLogicalVolumeName[sV.lvID, s]; WriteString[s]; first ← FALSE; ENDLOOP; ENDLOOP; WriteLine[IF first THEN "No logical volumes found"L ELSE NIL]; END; ListPhysicalVolumes: PROC = BEGIN s: STRING = [maxNameLength]; driveString: STRING; first: BOOLEAN ← TRUE; pID: PhysicalVolume.ID ← PhysicalVolume.nullID; MyNameIs[ myNameIs: "List Physical Volumes"L, myHelpIs: "List physical volumes"L]; DO pID ← PhysicalVolume.GetNext[pID]; IF pID = PhysicalVolume.nullID THEN EXIT; driveString ← GetDriveStringName[ PhysicalVolume.GetAttributes[pID, s].instance]; IF ~first THEN WriteString[", "L]; WriteString[driveString]; WriteChar[':]; WriteString[s]; first ← FALSE; ENDLOOP; WriteLine[IF ~first THEN NIL ELSE "No physical volumes found"L]; END; MakeBad: PROC = BEGIN h: PhysicalVolume.Handle; id: PhysicalVolume.ID; page: PhysicalVolume.PageNumber; IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Make Page Bad"L, myHelpIs: "Enter page into bad page table"L]; [id, h] ← GetPvIDFromUser[]; page ← ReadNumber["Decimal Page Number: "L, 0, GetDriveSize[h] - 1]; PhysicalVolume.MarkPageBad[id, page]; WriteLine["Consider scavenging some logical volumes."L]; END; Offline: PROC = { MyNameIs[ myNameIs: "Offline"L, myHelpIs: "Bring physical volume offline"L]; PhysicalVolume.Offline[GetPvIDFromUser[].id]}; Online: PROC = { pvID: PhysicalVolume.ID; MyNameIs[ myNameIs: "Online"L, myHelpIs: "Bring drive online"L]; pvID ← PhysicalVolume.AssertPilotVolume[GetDriveFromUser[] ! PhysicalVolume.Error => IF error = alreadyAsserted THEN CONTINUE]; -- (maybe) update time parameters on disk [] ← System.GetLocalTimeParameters[pvID]}; PowerOff: PROC = { MyNameIs[ myNameIs: "Power Off", myHelpIs: "Ready system for power off"L]; Confirm[]; CloseFetch[]; System.PowerOff[]}; PVScavenge: PROC = BEGIN OPEN PV: PhysicalVolume; convert: BOOLEAN ← FALSE; s: PV.ScavengerStatus; h: PV.Handle; repair: PV.RepairType; p: PV.ID ← PV.nullID; PrintDamageStatus: PROC [s: STRING, d: PV.DamageStatus] = { IF d=okay THEN RETURN; WriteString[s]; WriteLine[IF d=damaged THEN " damaged"L ELSE " lost"L]}; IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Physical Volume Scavenge"L, myHelpIs: "Attempt to scavenge physical volume"L]; h ← GetDriveFromUser[]; repair ← IF ~Yes["Repair? "L] THEN checkOnly ELSE IF Yes["Risky repair? "L] THEN riskyRepair ELSE safeRepair; Confirm[]; DO IF (p←PhysicalVolume.GetNext[p]) = PhysicalVolume.nullID THEN EXIT; IF h = PhysicalVolume.GetAttributes[p].instance THEN { PhysicalVolume.Offline[p]; EXIT}; ENDLOOP; BEGIN ENABLE PhysicalVolume.Error => IF error = needsConversion AND ~convert THEN IF (convert ← Yes["That volume is not in the current format. Do you want to convert it? "L]) THEN {Confirm[]; RETRY} ELSE AbortingCommand["Volume cannot be scavenged"L]; WriteString["Scavenging..."L]; s ← PV.Scavenge[h, repair, convert]; WriteLine["Complete"L]; END; -- ENABLE IF s = PV.noProblems THEN {WriteLine["No problems detected"L]; RETURN}; WriteString["Damage detected: "L]; IF s.internalStructures # okay THEN { WriteString["Internal structures "L]; WriteLine[ IF s.internalStructures=damaged THEN IF repair=safeRepair THEN "damaged -- contact hardware support for risky repair"L ELSE "damaged"L ELSE "repaired"L]}; PrintDamageStatus["Bad page list"L, s.badPageList]; PrintDamageStatus["Boot file"L, s.bootFile]; PrintDamageStatus["Germ"L, s.germ]; PrintDamageStatus["Pilot microcode"L, s.softMicrocode]; PrintDamageStatus["Sysout or diagnostic microcode"L, s.hardMicrocode]; END; Quit: PROC = { IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Quit"L, myHelpIs: "Push the boot button"L]; Confirm[]; CloseFetch[]; TemporaryBooting.BootButton[]}; Scavenge: PROC = { convert: BOOLEAN ← FALSE; lvID: Volume.ID; logFile: File.File; logPage: File.PageNumber ← 0; logWd: CARDINAL ← Environment.wordsPerPage; buffer: LONG POINTER TO ARRAY [0..Environment.wordsPerPage) OF UNSPECIFIED ← NIL; GetWds: PROC [p: POINTER, c: CARDINAL] = { WHILE c#0 DO IF logWd=Environment.wordsPerPage THEN { [] ← Space.CopyIn[buffer, [logFile, logPage, 1]]; logPage ← logPage + 1; logWd ← 0}; p↑ ← buffer[logWd]; p ← p+1; c ← c-1; logWd ← logWd+1; ENDLOOP}; DisplayScavLog: PROC = { fileCount: LONG CARDINAL; problems: BOOLEAN ← FALSE; BEGIN hd: Scavenger.Header; GetWds[@hd, SIZE[Scavenger.Header]]; WriteString["volume"L]; IF ~hd.repaired THEN WriteString[" not"L]; WriteString[" repaired, log file"L]; IF hd.incomplete THEN WriteString[" not"L]; WriteLine[" complete "L]; WriteLongNumber[fileCount ← hd.numberOfFiles]; WriteLine[" files on volume"L]; END; WHILE fileCount#0 DO OpenID: TYPE = ARRAY [0..SIZE[File.ID]) OF CARDINAL; fe: Scavenger.FileEntry; GetWds[@fe, SIZE[Scavenger.FileEntry]]; THROUGH [0..fe.numberOfProblems) DO fp: Scavenger.Problem; GetWds[@fp, SIZE[Scavenger.Problem]]; WriteChar['[]; FOR i: CARDINAL IN [0..SIZE[File.ID]-1) DO WriteOctal[LOOPHOLE[fe.file, OpenID][i]]; WriteString[", "L] ENDLOOP; WriteOctal[LOOPHOLE[fe.file, OpenID][SIZE[File.ID]-1]]; WriteString["] type = "L]; BEGIN ENABLE File.Unknown => GOTO noType; f: File.Type = File.GetAttributes[[fe.file, lvID]].type; WriteLongNumber[LONG[LOOPHOLE[f, CARDINAL]]]; EXITS noType => WriteString["unknown"L]; END; WriteString["; "L]; WITH fp SELECT FROM unreadable => { WriteString["unreadable"L]; WriteString[" pages ["L]; WriteLongNumber[first]; WriteString[".."L]; WriteLongNumber[first+count]; WriteLine[")"L]}; missing => { WriteString["missing"L]; WriteString[" pages ["L]; WriteLongNumber[first]; WriteString[".."L]; WriteLongNumber[first+count]; WriteLine[")"L]}; duplicate => { WriteString["duplicate"L]; WriteLine[" page found"L]}; orphan => { WriteString["orphan"L]; WriteLine[" page found"L]}; ENDCASE => WriteLine["unknown problem"L]; problems ← TRUE; ENDLOOP; fileCount ← fileCount-1; ENDLOOP; WriteLine[IF ~problems THEN "No problems found"L ELSE NIL]}; IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Scavenge"L, myHelpIs: "Attempt to scavenge logical volume"L]; lvID ← GetLvIDFromUser[].lvID; Confirm[]; Volume.Close[lvID ! ANY => CONTINUE]; BEGIN ENABLE Scavenger.Error => IF error = needsConversion AND ~convert THEN IF (convert ← Yes["That volume is not in the current format. Do you want to convert it? "L]) THEN {Confirm[twice]; RETRY} ELSE AbortingCommand["Volume cannot be scavenged"L]; WriteString["Scavenging..."L]; logFile ← Scavenger.Scavenge[lvID, lvID, safeRepair, convert]; WriteLine["Complete"L]; END; -- ENABLE SpecialVolume.OpenVolume[lvID, read]; buffer ← Space.ScratchMap[1]; DisplayScavLog[ ! UNWIND => {[] ← Space.Unmap[buffer]; Volume.Close[lvID]}]; [] ← Space.Unmap[buffer]; Volume.Close[lvID]}; SetBootFileSwitches: PROC = BEGIN ts: System.Switches; lvID: Volume.ID; IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Set Boot File Default Switches"L, myHelpIs: "Set default switches for boot file on volume"L]; lvID ← GetLvIDFromUser[].lvID; GetSetBootFileSwitches[get, lvID]; -- volume.needsScav (caught higher up) DO GetName["switches: "L, @switches, echo, TRUE ! Question => {WriteLine[ "See Pilot Users Handbook for list of valid switches."L]; RESUME}]; ts ← DecodeSwitches[switches ! BadSwitches => {WriteLine["bad switches"L]; LOOP}]; EXIT; ENDLOOP; Confirm[]; GetSetBootFileSwitches[set, lvID, ts]; END; SetDebuggerUser: PROC = BEGIN file: File.File; firstPage: File.PageNumber; lvID: Volume.ID; dLvID: Volume.ID; dH: PhysicalVolume.Handle; dT: Device.Type; dO: CARDINAL; outcome: SetDebuggerSuccess; IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Set Debugger Pointers"L, myHelpIs: "Set up pointers to debugger for volume"L]; lvID ← GetLvIDFromUser["for debuggee Logical Volume: "L].lvID; [file, firstPage] ← GetVolumeBootFile[lvID, pilot]; IF file = File.nullFile THEN AbortingCommand["No boot file found."L]; [, dLvID, dH] ← GetLvIDFromUser["for debugger Logical Volume: "L, TRUE]; IF dLvID=Volume.nullID THEN WriteLine["(Clear existing pointers)"L] ELSE {dT ← GetDriveType[dH]; dO ← GetDriveNumber[dH]}; Confirm[]; Volume.Open[lvID]; outcome ← SetDebugger[ debuggeeFile: file, debuggeeFirstPage: firstPage, debugger: dLvID, debuggerType: dT, debuggerOrdinal: dO]; Volume.Close[lvID]; WriteSetDebuggerSuccess[outcome]; END; SetExpirationDateUser: PROC = BEGIN file: File.File; firstPage: File.PageNumber; time: System.GreenwichMeanTime; lvID: Volume.ID; outcome: SetExpirationDateSuccess; IF ~CanOthello[] THEN RETURN; MyNameIs[ myNameIs: "Set Hardware Clock Upper Limit"L, myHelpIs: "Set last believable hardware clock date for boot file on logical volume"L]; lvID ← GetLvIDFromUser[].lvID; [file, firstPage] ← GetVolumeBootFile[lvID, pilot]; IF file = File.nullFile THEN AbortingCommand["No boot file found."L]; DO GetName["Date (DD-MMM-YY): "L, @expirationString]; IF expirationString.length=0 THEN { WriteLine["(setting no upper limit on hardware clock)"L]; time ← System.gmtEpoch; EXIT} ELSE { time ← PackedTimeFromString[s: expirationString, justDate: TRUE]; IF time=System.gmtEpoch THEN WriteLine["invalid date"L] ELSE EXIT}; ENDLOOP; Confirm[]; Volume.Open[lvID]; outcome ← SetExpirationDate[file, firstPage, time]; Volume.Close[lvID]; WriteSetDebuggerSuccess[outcome]; END; SetPvBoot: PROC = BEGIN lvID: Volume.ID; set: ARRAY BootFileType[hardMicrocode..pilot] OF BOOLEAN ← ALL[FALSE]; found, changed: BOOLEAN ← FALSE; size: File.PageCount; file: File.File; Smash: PROC [s: STRING, t: BootFileType] = { file ← GetVolumeBootFile[lvID, t].file; IF file = File.nullFile THEN RETURN; SpecialVolume.OpenVolume[lvID, read]; size ← File.GetSize[file]; Volume.Close[lvID]; found ← TRUE; WriteString["Set physical volume "L]; IF size > 1000 AND t = BootFileType.hardMicrocode THEN WriteString["Lisp sysout"L] ELSE WriteString[s]; IF (set[t] ← Yes[" from this logical volume? "L]) THEN changed ← TRUE}; MyNameIs[ myNameIs: "Set Physical Volume Boot Files"L, myHelpIs: "Set Physical Volume Boot Files"L]; lvID ← GetLvIDFromUser[].lvID; Smash["boot file"L, pilot]; Smash["pilot microcode"L, softMicrocode]; Smash["germ file"L, germ]; Smash["diagnostic microcode"L, hardMicrocode]; IF ~found THEN AbortingCommand["Logical volume has null boot files"L]; IF ~changed THEN RETURN; Confirm[]; SpecialVolume.OpenVolume[lvID, read]; FOR t: BootFileType IN [hardMicrocode..pilot] DO IF set[t] THEN { file: File.File; firstPage: File.PageNumber; [file, firstPage] ← GetVolumeBootFile[lvID, t]; SetPhysicalVolumeBootFile[file, t, firstPage]}; ENDLOOP; Volume.Close[lvID]; END; ShowBootFiles: PROC [pv: PhysicalVolume.ID, lv: Volume.ID] = { bootNames: ARRAY BootFileType[hardMicrocode..pilot] OF STRING ← [ hardMicrocode: "Diagnostic microcode"L, softMicrocode: "Pilot microcode"L, germ: "Germ"L, pilot: "Pilot bootfile"L]; SpecialVolume.OpenVolume[lv, read ! Volume.NeedsScavenging => GOTO scavenge]; FOR t: BootFileType IN BootFileType[hardMicrocode..pilot] DO ENABLE UNWIND => Volume.Close[lv]; file: File.File; firstPage: File.PageNumber; [file: file, firstPage: firstPage] ← GetVolumeBootFile[lv, t]; IF file = File.nullFile THEN LOOP; WriteString[" "L]; IF GetPhysicalVolumeBootFile[pv, t].file = file THEN WriteString["(PV) "L]; IF File.GetSize[file] > 1000 AND t = hardMicrocode THEN WriteString["Lisp sysout"L] ELSE WriteString[bootNames[t]]; WriteString[": "L]; IF firstPage = OthelloDefs.leaderPages THEN ShowLeaderNote[file] ELSE WriteLine["(no information available)"L]; ENDLOOP; Volume.Close[lv]; EXITS scavenge => NULL}; ShowLeaderNote: PROC [file: File.File] = { lp: LONG POINTER TO OthelloDefs.LeaderPage; lp ← Space.Map[window:[file, 0, OthelloDefs.leaderPages], access: readOnly].pointer; IF lp.version = OthelloDefs.lpVersion THEN FOR i: CARDINAL IN [0..lp.length) DO WriteChar[lp.note[i]] ENDLOOP ELSE WriteString["(no information available)"L]; NewLine[]; [] ← Space.Unmap[lp]}; WizardMode: PROC = { password: LONG STRING ← NIL; IF wizardMode THEN RETURN; MyNameIs[ myNameIs: "Wizard Mode"L, myHelpIs: "Enable special commands"L]; GetName["Password: "L, @password, stars]; IF Hash[password] = wizardPassword THEN {wizardMode ← TRUE; WriteLine[" ok"L]} ELSE WriteLine[" incorrect password"L]}; -- Wizard Supporting Procedures wizardMode: BOOLEAN ← Process.MsecToTicks[2000] # 39; --FALSE for DLion only. wizardPassword: CARDINAL = 17777; -- was 18939 Hash: PROCEDURE [s: LONG STRING] RETURNS [h: CARDINAL] = BEGIN h ← 17777; FOR i: CARDINAL IN [0..String.Length[s]) DO c: CHARACTER; IF (c ← s[i]) IN ['A..'Z] THEN c ← c + ('a-'A); h ← Inline.BITROTATE[h, 1] + (c-0C); ENDLOOP; END; Wizard: PUBLIC PROC RETURNS [BOOLEAN] = {RETURN[wizardMode]}; CanOthello: PUBLIC PROC RETURNS [BOOLEAN] = {RETURN[TRUE]}; -- may want to turn off Othello/non-Hello commands at some time -- Volume Init Supporting Procedures unknown: STRING = "Unknown"; GetSetBootFileSwitches: PROC [ getSet: {get, set}, lvID: Volume.ID, ts: System.Switches ← System.defaultSwitches] = { outcome: SetGetSwitchesSuccess; file: File.File; firstPage: File.PageNumber; Heap.systemZone.FREE[@switches]; IF getSet=get THEN SpecialVolume.OpenVolume[lvID, read] ELSE Volume.Open[lvID]; [file, firstPage] ← GetVolumeBootFile[lvID, pilot]; IF file = File.nullFile THEN AbortingCommand["No boot file found."L]; IF getSet=get THEN [outcome, ts] ← GetSwitches[file, firstPage] ELSE outcome ← SetSwitches[file, firstPage, ts]; Volume.Close[lvID]; WriteSetDebuggerSuccess[outcome]; IF getSet=set THEN RETURN; FOR c: CHARACTER IN [0C..377C] DO IF ts[c]=up THEN LOOP; SELECT c FROM '~, '-, '\\, '', '" => NULL; IN ['a..'z], IN ['A..'Z], IN (' ..'?] => { String.AppendCharAndGrow[@switches, c, Heap.systemZone]; LOOP}; ENDCASE => NULL; String.AppendCharAndGrow[@switches, '\\, Heap.systemZone]; String.AppendCharAndGrow[@switches, (c-0C)/64 + '0, Heap.systemZone]; String.AppendCharAndGrow[@switches, ((c-0C)/8 MOD 8) + '0, Heap.systemZone]; String.AppendCharAndGrow[@switches, ((c-0C) MOD 8) + '0, Heap.systemZone]; ENDLOOP}; WriteSetDebuggerSuccess: PROC [outcome: SetDebuggerSuccess] = { SELECT outcome FROM success => NULL; nullBootFile, cantWriteBootFile, notInitialBootFile => AbortingCommand["Boot file broken."L]; cantFindStartListHeader, startListHeaderHasBadVersion => AbortingCommand["file built by incompatible version of StartPilot"L]; noDebugger => AbortingCommand["No debugger installed."L]; ENDCASE => ERROR}; GetDriveFromUser: PUBLIC PROC RETURNS [h: PhysicalVolume.Handle] = { DO index: CARDINAL ← PhysicalVolume.nullDeviceIndex; GetName[ "Drive Name: "L, @inputDriveString, echo, TRUE ! Question => {ListDrives[]; RESUME}]; IF inputDriveString[inputDriveString.length - 1] = ': THEN inputDriveString.length ← inputDriveString.length - 1; DO index ← PhysicalVolume.GetNextDrive[index]; IF index = PhysicalVolume.nullDeviceIndex THEN EXIT; h ← PhysicalVolume.GetHandle[index]; IF String.Equivalent[GetDriveStringName[h], inputDriveString] THEN RETURN; ENDLOOP; WriteLine["Drive not found!"L] ENDLOOP}; GetDriveNumber: PUBLIC PROC [h: PhysicalVolume.Handle] RETURNS [CARDINAL] = { RETURN[PhysicalVolume.InterpretHandle[h].index]}; GetDriveStringName: PROC [h: PhysicalVolume.Handle] RETURNS [s: STRING] = BEGIN s ← SELECT TRUE FROM -- damn compiler won't allow t IN Device.PilotDisk LOOPHOLE[GetDriveType[h], CARDINAL] IN Device.PilotDisk => "Rd?", ENDCASE => "UnknownType?"; s[s.length - 1] ← GetDriveNumber[h] + '0; END; GetDriveType: PUBLIC PROC [h: PhysicalVolume.Handle] RETURNS [Device.Type] = { RETURN[PhysicalVolume.InterpretHandle[h].type]}; GetLogicalVolumeName: PROC [vid: Volume.ID, s: STRING] = { s.length ← 0; Volume.GetLabelString[vid, s ! Volume.NeedsScavenging => GOTO bad]; EXITS bad => { IDRep: TYPE = RECORD [p: ARRAY [0..3) OF CARDINAL, n: LONG CARDINAL]; String.AppendString[s, "NeedsScavenging"L]; String.AppendLongNumber[s, LOOPHOLE[vid, IDRep].n, 8]}}; GetLogicalVolumeTypeName: PROC [vid: Volume.ID] RETURNS [STRING] = { RETURN[logicalVolumeTypeString[Volume.GetType[vid ! ANY => GOTO signal]]]; EXITS signal => RETURN[unknown]}; GetLogicalVolumeType: PROC [vid: Volume.ID] RETURNS [Volume.Type] = { RETURN[Volume.GetType[vid ! ANY => GOTO signal]]; EXITS signal => RETURN[nonPilot]}; -- Accept string of Form LogicalVolumeName OR -- Drive:LogicalVolumeName GetLvIDFromUser: PUBLIC PROC [ prompt: STRING ← NIL, calledFromSetDebuggerPtrs: BOOLEAN ← FALSE] RETURNS [ pvID: PhysicalVolume.ID, lvID: Volume.ID, drive: PhysicalVolume.Handle] = BEGIN IF prompt = NIL THEN prompt ← "Logical Volume Name: "L; DO ptmpID: PhysicalVolume.ID ← PhysicalVolume.nullID; inputString: LONG STRING; matches: CARDINAL ← 0; GetName[ prompt: prompt, how: echo, signalQuestion: TRUE, dest: IF calledFromSetDebuggerPtrs THEN @debuggerLogicalString ELSE @inputLogicalString ! Question => {ListLogicalVolumes[]; RESUME}]; IF calledFromSetDebuggerPtrs THEN { IF debuggerLogicalString.length=0 THEN {lvID ← Volume.nullID; RETURN} ELSE inputString ← debuggerLogicalString} ELSE {inputString ← inputLogicalString}; DO driveTemp: PhysicalVolume.Handle; ltmpID: Volume.ID ← Volume.nullID; IF (ptmpID ← PhysicalVolume.GetNext[ptmpID]) = PhysicalVolume.nullID THEN EXIT; driveTemp ← PhysicalVolume.GetAttributes[ptmpID].instance; DO s: STRING = [maxNameLength]; IF (ltmpID ← PhysicalVolume.GetNextLogicalVolume[ptmpID, ltmpID]) = Volume.nullID THEN EXIT; GetLogicalVolumeName[ltmpID, s ! Volume.NotOnline => LOOP]; IF FunnyEqual[driveTemp, s, inputString] THEN { matches ← matches + 1; lvID ← ltmpID; pvID ← ptmpID; drive ← driveTemp}; ENDLOOP; ENDLOOP; SELECT matches FROM 0 => WriteString["Not found\r"L]; 1 => RETURN; ENDCASE => WriteLine["Ambigous; please specify Device:LogicalName"L]; ENDLOOP; END; FunnyEqual: PROC [ h: PhysicalVolume.Handle, name: STRING, userName: LONG STRING, mode: {checkNakedPName, dontCheckNakedPName} ← dontCheckNakedPName] RETURNS[BOOLEAN] = { driveName: STRING; SameChar: PROC [a, b: CHARACTER] RETURNS [BOOLEAN] = { IF a=b THEN RETURN[TRUE] ELSE IF a IN ['a..'z] AND b IN ['A..'Z] AND (a-'a+'A)=b THEN RETURN[TRUE] ELSE IF a IN ['A..'Z] AND b IN ['a..'z] AND (a-'A+'a)=b THEN RETURN[TRUE] ELSE RETURN[FALSE]}; IF String.Equivalent[name, userName] THEN RETURN[TRUE]; driveName ← GetDriveStringName[h]; IF userName.length < driveName.length THEN RETURN [FALSE]; FOR i: CARDINAL IN [0..driveName.length) DO IF ~SameChar[driveName[i], userName[i]] THEN RETURN[FALSE] ENDLOOP; IF mode=checkNakedPName THEN { IF (userName.length=driveName.length) OR (userName.length=driveName.length+1 AND userName[driveName.length] = ':) THEN RETURN[TRUE]}; IF driveName.length+name.length+1 # userName.length THEN RETURN[FALSE]; IF userName[driveName.length] # ': THEN RETURN[FALSE]; FOR i: CARDINAL IN [0..name.length) DO IF ~SameChar[name[i], userName[driveName.length+1+i]] THEN RETURN[FALSE] ENDLOOP; RETURN[TRUE]}; GetLvTypeFromUser: PUBLIC PROC [ prompt: STRING, defaultType: Volume.Type] RETURNS [Volume.Type] = BEGIN ListTypes: PROC = { FOR t: Volume.Type IN [normal..nonPilot] DO WriteString[logicalVolumeTypeString[t]]; WriteString[IF t = nonPilot THEN "\r"L ELSE ", "L]; ENDLOOP}; String.Replace[@lvTypeString, logicalVolumeTypeString[defaultType], Heap.systemZone]; DO GetName[prompt, @lvTypeString, echo, TRUE ! Question => {ListTypes[]; RESUME}]; FOR t: Volume.Type IN [normal..nonPilot] DO IF String.Equivalent[logicalVolumeTypeString[t], lvTypeString] THEN RETURN[t] ENDLOOP; WriteLine["Illegal type"L]; ENDLOOP; END; -- Accept string of Form PhysicalVolumeName OR -- Drive:PhysicalVolumeName OR Drive GetPvIDFromUser: PROC RETURNS [id: PhysicalVolume.ID, drive: PhysicalVolume.Handle] = BEGIN DO tmpID: PhysicalVolume.ID ← PhysicalVolume.nullID; matches: CARDINAL ← 0; GetName["Physical Volume Name: "L, @inputPhysString, , TRUE ! Question => {ListPhysicalVolumes[]; RESUME}]; DO s: STRING = [maxNameLength]; match: BOOLEAN; driveTemp: PhysicalVolume.Handle; IF (tmpID ← PhysicalVolume.GetNext[tmpID]) = PhysicalVolume.nullID THEN EXIT; driveTemp ← PhysicalVolume.GetAttributes[tmpID, s].instance; match ← FunnyEqual[driveTemp, s, inputPhysString, checkNakedPName]; IF match THEN {matches ← matches + 1; id ← tmpID; drive ← driveTemp}; ENDLOOP; SELECT matches FROM 0 => WriteLine["Not Found"L]; 1 => RETURN; ENDCASE => WriteLine["Ambigous; please specify Device:PhysicalName"L]; ENDLOOP; END; StringInit: PROC = { SetCommandString[String.CopyToNewString["Online RD0"L, Heap.systemZone]]}; debuggerLogicalString ← String.CopyToNewString["CoPilot"L, Heap.systemZone]; RegisterCommandProc[@commandProcessor]; StringInit[]; END..... March 19, 1980 3:47 PM Forrest Delete newly created temporary files when fetch fails; ome indentation changing April 16, 1980 12:16 PM Gobbel Addd diagnostic microcode fetch May 31, 1980 11:49 PM Forrest Shuffle around VolumeInitImplA and B July 30, 1980 4:33 PM Luniewski Permit Online'ing an already online volume September 18, 1980 12:04 PM McJones Don't bother to open volume to boot from September 19, 1980 11:24 AM Luniewski physicalVolumeOverhead ← 2 for new physical volume format. September 29, 1980 2:07 PM Jose Add SA800 format and scan, USING clauses. October 10, 1980 3:17 PM Forrest Version 5.0. January 5, 1981 10:14 PM Forrest Made use String for appendChar, equivilantString, appendLongNumber. Add TemporaryBooting.invalid paramater catch. January 31, 1981 9:19 PM Jose Fix format prompt. March 1, 1981 12:59 PM Luniewski Version => 6.0b. March 13, 1981 7:22 PM Yokota Version => 6.0c, trouple => trouble (correction), "Boot file header broken" => "Error: Debuggee built by incompatible version of StartPilot". March 25, 1981 8:28 PM Fay Version => 6.0. April 14, 1981 11:38 AM Bruce @ added. 11-Jun-81 10:53:01 Taft Remove all machine- and device-dependent code to separate module OthelloDeviceImplD*.mesa 17-Jul-81 15:34:33 Glassman Merged OthelloDevice into OthelloDefs 12-Aug-81 12:33:54 Yokota Added a catch phrase for Volume.GetAttributes and commented it out for Volume.GetLabelString 5-Dec-81 17:30:28 Fay Converted from PhysicalVolumeExtras to PhysicalVolume for PV scavenger. 11-Dec-82 15:10:21 Johnsson Removed Storage. 13-Apr-83 12:27:04 Johnsson Klamath conversion 15-Aug-84 Lichtenberg/Masinter Convert to Hello, Lisp specific modifications