-- File: CedarSnapshotUPDriver.mesa
-- last edited by Levin: November 12, 1982 1:40 pm
DIRECTORY
Boot USING [DiskFileID, LVBootFiles],
CedarSnapshot USING [Delete, RollBack],
CedarSnapshotPrivate USING [ValidateSnapshot], -- should come from CedarSnapshot
Device USING [nullType, Type],
DeviceTypes USING [sa4000],
File USING [nullID],
PhysicalVolume USING [
AssertPilotVolume, Error, GetHandle, GetNextDrive, Handle, InterpretHandle,
nullDeviceIndex],
PilotClient USING [],
PilotSwitches USING [switches --.s--],
ProcessorFace USING [SetMP],
SpecialVolume USING [GetLogicalVolumeBootFiles],
TemporaryBooting USING [BootFromVolume],
Volume USING [GetNext, GetType, ID, nullID, TypeSet];
CedarSnapshotUPDriver: PROGRAM
IMPORTS
CedarSnapshot, CedarSnapshotPrivate, PilotSwitches, PhysicalVolume, ProcessorFace,
SpecialVolume, TemporaryBooting, Volume
EXPORTS PilotClient =
BEGIN
-- This module is designed to be bound with UtilityPilot and used to trigger
-- a rollback to a previously checkpointed client volume.
CauseOfDeath: TYPE = MACHINE DEPENDENT {
cantFindRD0(2001), cantOpenRD0(2002), noClientVolume(2003), cantBoot(2004),
unexpectedSignal(2005), (9999)};
Die: PROCEDURE [reason: CauseOfDeath] =
BEGIN
ProcessorFace.SetMP[LOOPHOLE[reason]];
DO ENDLOOP;
END;
BringRD0Online: PROCEDURE =
BEGIN
t: Device.Type ← Device.nullType;
index: CARDINAL ← PhysicalVolume.nullDeviceIndex;
DO
h: PhysicalVolume.Handle;
[t, index] ← PhysicalVolume.GetNextDrive[t, index];
IF t = Device.nullType AND index = PhysicalVolume.nullDeviceIndex THEN Die[cantFindRD0];
h ← PhysicalVolume.GetHandle[t, index];
IF PhysicalVolume.InterpretHandle[h].type = DeviceTypes.sa4000 AND index = 0 THEN
[] ← PhysicalVolume.AssertPilotVolume[h ! PhysicalVolume.Error =>
IF error = alreadyAsserted THEN CONTINUE ELSE Die[cantOpenRD0]];
EXIT;
ENDLOOP;
END;
GetBootFile: PUBLIC PROC [volume: Volume.ID] RETURNS [Boot.DiskFileID] = {
bootFiles: Boot.LVBootFiles;
SpecialVolume.GetLogicalVolumeBootFiles[volume, @bootFiles];
RETURN[bootFiles[pilot]]
};
EnumerateNormalVolumes: PROCEDURE [proc: PROC [Volume.ID] RETURNS [BOOL]]
RETURNS [volume: Volume.ID] =
BEGIN
-- Guess what, sports fans? TypeSets don't work in UtilityPilot, due to an
-- ugly crock in VolumeImpl.GetNext that essentially ignores them. So, we have
-- to do it ourselves.
allVolumes: Volume.TypeSet = ALL[TRUE];
volume ← Volume.nullID;
UNTIL (volume ← Volume.GetNext[volume, allVolumes]) = Volume.nullID DO
IF Volume.GetType[volume] = normal AND proc[volume] THEN RETURN [volume];
ENDLOOP;
RETURN [Volume.nullID]
END;
Run: PUBLIC PROCEDURE =
BEGIN
-- If there are multiple volumes of type normal, we will rollback the first one that
-- appears to have a valid checkpoint (booting it if that doesn't work). If there are
-- none with valid checkpoints, we boot the first volume.
ENABLE ANY => Die[unexpectedSignal];
volume: Volume.ID;
FindACheckpoint: PROC [vol: Volume.ID] RETURNS [BOOL] =
{RETURN[CedarSnapshotPrivate.ValidateSnapshot[vol]]};
DeleteBogusCheckpoint: PROC [vol: Volume.ID] RETURNS [BOOL ← FALSE] =
{CedarSnapshot.Delete[vol]};
FindAClientVolume: PROC [vol: Volume.ID] RETURNS [BOOL] =
{RETURN[GetBootFile[vol].fID ~= File.nullID]};
BringRD0Online[];
IF (volume ← EnumerateNormalVolumes[FindACheckpoint]) ~= Volume.nullID THEN
-- We've got what appears to be a valid checkpoint. If the user asked to have it
-- deleted, do so and then boot the volume. Otherwise, do a rollback.
IF PilotSwitches.switches.s = down THEN CedarSnapshot.Delete[volume]
ELSE CedarSnapshot.RollBack[volume]
ELSE {
IF PilotSwitches.switches.s = down THEN [] ← EnumerateNormalVolumes[DeleteBogusCheckpoint];
IF (volume ← EnumerateNormalVolumes[FindAClientVolume]) = Volume.nullID THEN
Die[noClientVolume];
};
-- If we get here, we are supposed to boot the chosen volume.
-- Note that the switches (including "s") are passed through intact.
TemporaryBooting.BootFromVolume[volume, PilotSwitches.switches];
Die[cantBoot];
END;
END.