IagoCommands2Impl.mesa - Iago commands implementation
Copyright © 1984 by Xerox Corporation. All rights reserved.
Andrew Birrell December 7, 1983 4:07 pm
Levin, September 22, 1983 1:32 pm
Russ Atkinson, June 18, 1984 6:20:08 pm PDT
Willie-Sue, August 10, 1984 10:26:03 am PDT
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 ..."];
See what local name the user would like
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: ROPENIL;
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 \"[]<volume>\""] };
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];
};
}.