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