<> <> <> <> <> <> <<>> DIRECTORY BasicTime USING[ GMT ], Booting USING[ Boot, Switches ], File USING [FindVM, FP, GetVolumeName, Handle, Info, IsDebugger, SetRoot, SystemVolume, Volume, VolumeFile], FS USING [ Close, ComponentPositions, Copy, EnumerateForInfo, EnumerateForNames, Error, ExpandName, FileInfo, InfoProc, NameProc, Open, OpenFile, Rename, SetByteCountAndCreatedTime, SetKeep, SetDefaultWDir ], FSBackdoor USING [ EnumerateCacheForNames, Flush, GetFileHandle, NameProc, ScavengeDirectoryAndCache ], GermSwap USING[ Switch ], IagoCommands, IagoOps --USING everything--, IO USING[ PutF, PutRope, STREAM ], Loader USING[ Error, IRItem, Instantiate, Start], PhysicalVolume USING[ SetPhysicalRoot ], PrincOps USING[ ControlModule, NullControl], Rope USING [ Cat, Equal, Fetch, Find, Index, Length, ROPE, Run, Substr ], SimpleTerminal USING [TurnOff, TurnOn], UserCredentials USING [ChangeState, Login, LoginOptions]; IagoCommands2Impl: CEDAR PROGRAM IMPORTS Booting, File, FS, FSBackdoor, IagoOps, IO, Loader, PhysicalVolume, Rope, SimpleTerminal, UserCredentials EXPORTS IagoCommands = { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <<******** The command subroutines (alphabetic order) ********>> FlushCache: PUBLIC PROC [in, out: STREAM] = { count: INT _ 0; DoName: FSBackdoor.NameProc = { count _ count+1; IO.PutF[out, "\nFlushing %g ... ", [rope[fullGName]]]; { ENABLE FS.Error => { IO.PutRope[out, error.explanation]; CONTINUE }; FSBackdoor.Flush[fullGName: fullGName, volName: volName]; IO.PutRope[out, "done"]; }; RETURN[TRUE]; }; v: File.Volume = IagoOps.GetLogical[in, out, "On "]; volName: ROPE = File.GetVolumeName[v]; pattern: ROPE _ IagoOps.GetFile[in: in, out: out, pattern: TRUE]; IO.PutRope[out, " ... "]; FSBackdoor.EnumerateCacheForNames[DoName, volName, pattern]; IF count = 0 THEN IO.PutRope[out, "not found"] ELSE IO.PutF[out, "\n%g files", [integer[count]] ]; }; InstallCredentials: PUBLIC PROC [in, out: STREAM] = { IO.PutRope[out, "\nDo you want to password-protect this disk? "]; [] _ UserCredentials.ChangeState[IF IagoOps.Confirm[in, out] THEN name ELSE nameHint]; }; InstallLogicalFile: PUBLIC PROC [in, out: STREAM, which: File.VolumeFile[checkpoint..bootFile]] = { v: File.Volume = IagoOps.GetLogical[in, out, "For "]; localVolume: ROPE = Rope.Cat["[]<", File.GetVolumeName[v], ">"]; createTime: BasicTime.GMT; name: ROPE = IagoOps.GetFile[ in: in, out: out, extension: IagoOps.ext[which], default: IagoOps.RemoteRootFileName[which], wDir: localVolume, check: TRUE ]; localName: ROPE _ name; fsFile: FS.OpenFile; file: File.Handle; PhysicalToo: PROC RETURNS[BOOL] = { IF which # bootFile THEN { IO.PutRope[out, "\nInstalling on the physical volume"]; RETURN[TRUE] }; IF File.IsDebugger[v] THEN RETURN[FALSE]; IO.PutRope[out, "\nDo you want to use this file when you boot the physical volume? "]; RETURN[IagoOps.Confirm[in, out]] }; <<"name" is a canonicalized FS name.>> IO.PutRope[out, " ... "]; IF name.Length[] # 0 AND name.Fetch[0] = '[ AND Rope.Run[s1: name, s2: localVolume, case: FALSE] # localVolume.Length[] AND ( v # File.SystemVolume[] OR Rope.Run[s1: name, s2: "[]<>"] # 4 ) THEN { Help: PROC = { IO.PutRope[out, "? Please type the name of an FS local file such as \"a.b\""]; }; localName _ IagoOps.LocalRootFileName[which]; IO.PutRope[out, IF name.Length[] >=1 AND name.Fetch[1] = '] THEN "that file is on another volume ..." ELSE "that file is on a server ..."]; <> DO localName _ IagoOps.GetArg[ in: in, out: out, prompt: "\nCopy to local file name (please confirm or alter): ", default: localName, help: Help]; IF localName.Length[] = 0 OR localName.Fetch[0] = '[ THEN Help[] ELSE EXIT; ENDLOOP; IO.PutRope[out, " ... copying ... "]; FS.Copy[from: name, to: localName, wDir: localVolume]; }; createTime _ FS.FileInfo[name: localName, wDir: localVolume].created; fsFile _ FS.Open[name: localName, lock: write, wDir: localVolume]; file _ FSBackdoor.GetFileHandle[fsFile]; IF File.Info[file].volume # v THEN IO.PutRope[out, "I'm confused: the file is on the wrong volume"] ELSE { IO.PutRope[out, "installing ... "]; File.SetRoot[which, file]; FS.SetByteCountAndCreatedTime[file: fsFile, created: createTime]; IO.PutRope[out, "done"]; }; FS.Close[fsFile]; IF PhysicalToo[] THEN { PhysicalVolume.SetPhysicalRoot[v, which]; IO.PutRope[out, " ... done"] }; }; ListCache: PUBLIC PROC [in, out: STREAM] = { count: INT _ 0; DoName: FSBackdoor.NameProc = { count _ count+1; IO.PutF[out, "\n %g", [rope[fullGName]]]; RETURN[TRUE]; }; v: File.Volume = IagoOps.GetLogical[in, out, "On "]; pattern: ROPE _ IagoOps.GetFile[in: in, out: out, pattern: TRUE]; IO.PutRope[out, " ... "]; FSBackdoor.EnumerateCacheForNames[DoName, File.GetVolumeName[v], pattern]; IF count = 0 THEN IO.PutRope[out, "not found"] ELSE IO.PutF[out, "\n%g files", [integer[count]] ]; }; ListFileInfo: PUBLIC PROC [in, out: STREAM] = { count: INT _ 0; DoName: FS.InfoProc = { count _ count+1; IO.PutF[out, "\n %g, keep: %g, bytes: %g, created: %g", [rope[fullFName]], [cardinal[keep]], [integer[bytes]], [time[created]] ]; IF attachedTo # NIL THEN IO.PutF[out, ", attached to %g", [rope[attachedTo]] ]; RETURN[TRUE]; }; pattern: ROPE _ IagoOps.GetFile[in: in, out: out, pattern: TRUE]; IO.PutRope[out, " ... "]; FS.EnumerateForInfo[pattern, DoName]; IF count = 0 THEN IO.PutRope[out, "not found"] ELSE IO.PutF[out, "\n%g files", [integer[count]] ]; }; ListNames: PUBLIC PROC [in, out: STREAM] = { count: INT _ 0; prevFile: ROPE _ NIL; DoName: FS.NameProc = { newFile, newPrefix: ROPE; newPos: FS.ComponentPositions; count _ count+1; [fullFName: newFile, cp: newPos] _ FS.ExpandName[fullFName]; newPrefix _ fullFName.Substr[len: newPos.ver.start]; IF prevFile # NIL AND newPos.ver.length # 0 AND prevFile.Equal[newPrefix, FALSE] THEN IO.PutF[out, ", %g", [rope[fullFName.Substr[start: newPos.ver.start, len: newPos.ver.length]]] ] ELSE { prevFile _ newPrefix; IO.PutF[out, "\n%g", [rope[fullFName]]]; }; RETURN[TRUE]; }; pattern: ROPE _ IagoOps.GetFile[in: in, out: out, pattern: TRUE]; IO.PutRope[out, " ... "]; FS.EnumerateForNames[pattern, DoName]; IF count = 0 THEN IO.PutRope[out, "not found"] ELSE IO.PutF[out, "\n%g files", [integer[count]] ]; }; Login: PUBLIC PROC [options: UserCredentials.LoginOptions] = { TurnOnProc: PROC RETURNS [in, out: STREAM] = { [in: in, out: out] _ SimpleTerminal.TurnOn[]; IO.PutRope[out, "\nPlease login ...\n"]; }; TurnOffProc: PROC [in, out: STREAM] = { SimpleTerminal.TurnOff[] }; UserCredentials.Login[startInteraction: TurnOnProc, endInteraction: TurnOffProc, options: options]; }; Rename: PUBLIC PROC [in, out: STREAM] = { from: ROPE = IagoOps.GetFile[in: in, out: out, prompt: "From ", check: TRUE]; to: ROPE = IagoOps.GetFile[in: in, out: out, prompt: "To "]; IO.PutRope[out, " ... "]; FS.Rename[from: from, to: to]; IO.PutRope[out, "done"]; }; Rollback: PUBLIC PROC [in, out: STREAM] = { v: File.Volume = IagoOps.GetLogical[in, out]; reject: ROPE; mySwitches: Booting.Switches _ ALL[FALSE]; mySwitches[r] _ TRUE; reject _ Booting.Boot[[logical[v]], mySwitches]; IF reject # NIL THEN { IO.PutRope[out, " ... couldn't: "]; IO.PutRope[out, reject] }; }; RunDiagnosticBCD: PUBLIC PROC [in, out: STREAM] = { fName: ROPE; fsFile: FS.OpenFile; cm: PrincOps.ControlModule; unboundImports: LIST OF Loader.IRItem; fName_ IagoOps.GetFile[in: in, out: out, prompt: "FileName ", check: TRUE]; fsFile_ FS.Open[fName ! FS.Error => { IO.PutRope[out, error.explanation]; GOTO noFile}]; TRUSTED { [cm, unboundImports]_ Loader.Instantiate[fsFile ! Loader.Error => { IO.PutRope[out, message]; cm_ PrincOps.NullControl; CONTINUE}]; }; IF unboundImports#NIL THEN { IO.PutRope[out, "\nThere are unbound imports; confirm to start the code anyway"]; IF ~IagoOps.Confirm[in, out] THEN RETURN; }; TRUSTED {IF cm # PrincOps.NullControl THEN Loader.Start[cm ! ABORTED => CONTINUE]}; FS.Close[fsFile ! FS.Error => CONTINUE]; EXITS noFile => NULL; }; Scavenge: PUBLIC PROC [in, out: STREAM] = { v: File.Volume = IagoOps.GetLogical[in, out]; IO.PutRope[out, " ... "]; [] _ File.FindVM[]; FSBackdoor.ScavengeDirectoryAndCache[File.GetVolumeName[v]]; IO.PutRope[out, "done"]; }; SetKeep: PUBLIC PROC [in, out: STREAM] = { count: INT _ 0; DoName: FS.NameProc = { count _ count+1; fullFName _ fullFName.Substr[start: 0, len: fullFName.Index[0, "!"]]; IO.PutF[out, "\nSetting %g ... ", [rope[fullFName]]]; { ENABLE FS.Error => { IO.PutRope[out, error.explanation]; CONTINUE }; FS.SetKeep[fullFName, k]; IO.PutRope[out, "done"]; }; RETURN[TRUE]; }; pattern: ROPE _ IagoOps.GetFile[ in: in, out: out, pattern: TRUE, prompt: "For "]; k: INT = IagoOps.GetNumber[ in, out, 1, LAST[CARDINAL]-1, "\nNumber of versions to keep: ", "? Type how many versions of each file should be kept (excess versions will be deleted)"]; IF Rope.Find[pattern, "!"] < 0 THEN pattern _ pattern.Cat["!H"]; IO.PutRope[out, " ... "]; FS.EnumerateForNames[pattern, DoName]; IF count = 0 THEN IO.PutRope[out, "not found"] ELSE IO.PutF[out, "\n%g files", [integer[count]] ]; }; SetPhysicalFile: PUBLIC PROC [in, out: STREAM, which: File.VolumeFile[checkpoint..bootFile]] = { v: File.Volume = IagoOps.GetLogical[in, out, "From "]; IO.PutRope[out, " ... "]; PhysicalVolume.SetPhysicalRoot[v, which]; IO.PutRope[out, "done"]; }; SetWDir: PUBLIC PROC [in, out: STREAM] = { Help: PROC = { IO.PutRope[out, "? Type the prefix of a file name, such as \"[]\""] }; name: ROPE = IagoOps.GetArg[ in: in, out: out, prompt: "\nWorking directory: ", default: IF IagoOps.clientVolName.Length[] # 0 THEN Rope.Cat["[]<", IagoOps.clientVolName, ">"] ELSE NIL, help: Help]; FS.SetDefaultWDir[name]; }; }.