-- 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