PrinterIagoImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: April 7, 1987 11:39:44 am PDT
DIRECTORY
Basics USING [LongDiv],
BasicTime USING [GMT],
BootFile USING [MemorySizeToFileSize],
Booting USING [switches],
BootingBackdoor USING [Boot],
Disk USING [Channel, NextChannel, PageCount],
File USING [CedarVolumeSubType, GetVolumeName, Handle, Info, RC, SystemVolume, Volume, VolumeID, VolumeFile],
FileBackdoor USING [CreateLogicalVolume, CreatePhysicalVolume, EraseVolume, IsDebugger, SetRoot],
FS USING [ Close, ComponentPositions, Copy, Create, Error, ExpandName, FileInfo, GetName, Open, OpenFile, SetByteCountAndCreatedTime, StreamFromOpenFile ],
FSBackdoor USING [ GetFileHandle ],
FSPseudoServers USING [ GetPseudoServers, InsertPseudoServer, Lookup, PseudoServerList, PseudoServerFromRope, RopeFromPseudoServer ],
IagoBackdoor,
IagoCommands,
IagoOps --USING everything--,
IO USING [ int, rope, BreakProc, Close, EndOfStream, GetLineRope, GetTokenRope, PutChar, PutF, PutF1, PutFR, PutRope, STREAM, time ],
PhysicalVolume USING [ Physical, PhysicalInfo, SetPhysicalRoot ],
PrinterNames USING [DefaultNames, Get, Set],
ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses],
PupStreamBackdoor USING [maxOldGatewayBytes, SetMaxBufferSize],
Rope USING [ Cat, Concat, Equal, Length, ROPE, SkipTo, Substr ],
SystemNames USING [ LocalDir ],
SystemSite USING [ Get ],
SystemVersion USING [ machineType ],
ThisMachine USING [ Name ],
UserCredentials USING [ChangeState];
PrinterIagoImpl: CEDAR PROGRAM
IMPORTS Basics, Booting, BootingBackdoor, Disk, File, FileBackdoor, FS, FSBackdoor, FSPseudoServers, IagoBackdoor, IagoOps, IO, PhysicalVolume, PrinterNames, ProcessorFace, PupStreamBackdoor, Rope, SystemNames, SystemSite, SystemVersion, ThisMachine, UserCredentials
EXPORTS
~ BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
CreatePrinterWorld: PUBLIC PROC [in, out: STREAM] = {
Install: PROC [where: File.Volume, which: File.VolumeFile[microcode..bootFile]] = {
volumeName: ROPE ~ File.GetVolumeName[where];
remote: ROPE = RemoteRootFileName[which];
local: ROPE ← IagoOps.LocalRootFileName[which, volumeName];
fsFile: FS.OpenFile;
file: File.Handle;
createTime: BasicTime.GMT;
IO.PutF[out, "\nInstalling %g as %g ... ", IO.rope[remote], IO.rope[local] ];
local ← FS.Copy[from: remote, to: local];
createTime ← FS.FileInfo[local].created;
grab the original create time before FS.Open[... lock: write ...] changes it
fsFile ← FS.Open[name: local, lock: write];
file ← FSBackdoor.GetFileHandle[fsFile];
FileBackdoor.SetRoot[where, which, file];
FS.SetByteCountAndCreatedTime[file: fsFile, created: createTime];
FS.Close[fsFile];
IO.PutRope[out, "done"];
};
format, protect: BOOL;
altoText: ROPENIL;
myName: ROPE = ThisMachine.Name[];
d: Disk.Channel = Disk.NextChannel[NIL];
newP: PhysicalVolume.Physical;
newC: File.Volume;
memImagePages: INT; -- Room for a physical memory image plus possible junk
makeLabeled: BOOLFALSE;
minVMSize: INT;
defaultVMSize: INT;
maxVMSize: INT ~ IagoBackdoor.MaxVMSize[]; -- based on machine type (smaller on DLion)
helpVMSize: ROPE ~
IO.PutFR["? give number of VM pages in decimal (min: 0 or %g, max: %g)",
IO.int[minVMSize], IO.int[maxVMSize]];
cedarVMPages: INT ← -1;
[minVMSize, defaultVMSize] ← IagoBackdoor.DefaultVMSize[d]; -- based on real memory size and disk size
TRUSTED {
memImagePages ← BootFile.MemorySizeToFileSize[VMSideDoor.rmPages]+24;
Has to be trusted because BootFile.MemorySizeToFileSize is misdeclared!
};
IO.PutChar[out, '\n];
IO.PutRope[out, "\n\nHas your disk already been formatted? (Confirm if the disk has previously been used for Cedar or Pilot, AND you have not reduced the amount of disk reserved for Alto volumes) "];
format ← NOT IagoOps.Confirm[in, out];
makeLabeled ← FALSE;
protect ← FALSE;
WHILE cedarVMPages < minVMSize AND cedarVMPages # 0 DO
cedarVMPages ← IagoOps.GetNumber[
in: in, out: out, default: defaultVMSize, max: maxVMSize,
prompt: "\n\nSpecify VM size (in pages): ",
help: helpVMSize
];
ENDLOOP;
IO.PutRope[out, "\n\nI intend to perform the following operations:"];
IF format THEN IO.PutF1[out, "
- format the entire disk%g;", IO.rope[altoText] ];
IO.PutF[out, " - create a new %g, physical volume named \"%g\";",
IO.rope[IF makeLabeled THEN "labeled" ELSE "unLabeled"], IO.rope[myName] ];
IO.PutF[out, "
- create a %g client volume named \"Cedar\" with a %g page VM;
- install microcode, germ and boot files(s) from the release directory;
- make the \"Cedar\" volume be the physical boot volume;
- boot the volume(s) to initialize the software.
", IO.rope[IF makeLabeled THEN "labeled" ELSE "unLabeled" ], IO.int[cedarVMPages] ];
IF NOT IagoOps.ConfirmDestruction[in, out, "the entire disk on drive RD0"] THEN RETURN;
IagoBackdoor.CloseFSVolumes[];
IO.PutChar[out, '\n];
IF format THEN TRUSTED {
IagoBackdoor.DoFormatOrScan[in: in, out: out, d: d, format: TRUE, passes: 1] };
IO.PutRope[out, "\nCreating physical volume ... "];
newP ← FileBackdoor.CreatePhysicalVolume[where: d, name: myName, id: IagoOps.NewID[], useLabels: makeLabeled];
IagoOps.ReservePages[in, out, newP];
[] ← UserCredentials.ChangeState[IF protect THEN name ELSE nameHint];
IO.PutRope[out, "done"];
IO.PutRope[out, "\nCreating logical volume \"Cedar\" ... "];
newC ← FileBackdoor.CreateLogicalVolume[
id: IagoOps.NewID[],
where: LIST[newP],
size: PhysicalVolume.PhysicalInfo[newP].free,
name: "Cedar",
useLabels: makeLabeled,
subType: FS,
volatileVAM: TRUE];
IO.PutRope[out, "done. Erasing it ... "];
FileBackdoor.EraseVolume[newC];
IO.PutRope[out, "done"];
IF cedarVMPages # 0 THEN IagoBackdoor.CreateVMFile[out, newC, cedarVMPages];
[] ← WriteRemoteNames[File.GetVolumeName[newC], out];
Install[where: newC, which: microcode];
Install[where: newC, which: germ];
Install[where: newC, which: bootFile];
PhysicalVolume.SetPhysicalRoot[newC, microcode];
PhysicalVolume.SetPhysicalRoot[newC, germ];
PhysicalVolume.SetPhysicalRoot[newC, bootFile];
{
init: ROPE = InitialMicrocodeFileName[];
IO.PutRope[out, "\nInstalling "];
IO.PutRope[out, init];
IF IagoBackdoor.DoInitialMicrocodeInstallation[out, d, init] THEN
[] ← BootingBackdoor.Boot[
[logical[newC]],
[d: Booting.switches[d]] ];
};
};
SetPrinterRemoteNamesCommand: PROC [in, out: STREAM] = {
names: PrinterNames.DefaultNames = PrinterNames.Get[];
printerHost: ROPE ← StripBrackets[names.printerHost];
fontHost: ROPE ← StripBrackets[names.fontHost];
printerHost ← StripBrackets[IagoOps.GetArg[in, out, "\n Printer Host: ", printerHost, NIL]];
IF printerHost = NIL THEN GO TO bailOut;
fontHost ← StripBrackets[IagoOps.GetArg[in, out, "\n Font Host: ", fontHost, NIL]];
IF fontHost = NIL THEN GO TO bailOut;
names.printerHost ← printerHost ← Rope.Cat["[", printerHost, "]"];
names.fontHost ← fontHost ← Rope.Cat["[", fontHost, "]"];
[] ← WriteRemoteNames[NIL, out];
Write the remote names on the system volume
EXITS
bailOut => {
IO.PutRope[out, "\nEmpty host names not permitted, command aborted.\n"];
};
};
SetPrinterDirectoriesCommand: PROC [in, out: STREAM] = {
names: PrinterNames.DefaultNames = PrinterNames.Get[];
currentSystem: ROPE ← names.currentSystem;
currentFont: ROPE ← names.currentFont;
printerType: ROPE ← names.printerType;
currentSystem ← IagoOps.GetArg[in, out, "\n System Directory: ", currentSystem, NIL];
IF currentSystem = NIL THEN GO TO bailOut;
currentFont ← IagoOps.GetArg[in, out, "\n Font Directory: ", currentFont, NIL];
IF currentFont = NIL THEN GO TO bailOut;
names.currentSystem ← currentSystem;
names.currentFont ← currentFont;
[] ← WriteRemoteNames[NIL, out];
Write the remote names on the system volume
EXITS
bailOut => {
IO.PutRope[out, "\nEmpty directory names not permitted, command aborted.\n"];
};
};
SetPrinterTypeCommand: PROC [in, out: STREAM] = {
names: PrinterNames.DefaultNames = PrinterNames.Get[];
printerType: ROPE ← names.printerType;
printerType ← IagoOps.GetArg[in, out, "\n Printer Type: ", printerType, NIL];
IF printerType = NIL THEN GO TO bailOut;
names.printerType ← printerType;
[] ← WriteRemoteNames[NIL, out];
Write the remote names on the system volume
EXITS
bailOut => {
IO.PutRope[out, "\nEmpty printer type not permitted, command aborted.\n"];
};
};
machine: ROPENIL;
ExtensionArray: TYPE ~ ARRAY File.VolumeFile OF ROPE;
extension: REF ExtensionArray ← NEW [ExtensionArray ← ALL[NIL]];
localName: REF ExtensionArray ← NEW [ExtensionArray ← ALL[NIL]];
StripBrackets: PROC [name: ROPE] RETURNS [ROPE] = {
len: INT ← Rope.Length[name];
pos1: INT ← Rope.SkipTo[name, 0, "["];
pos2: INT ← Rope.SkipTo[name, 0, "]"];
nlen: INT ← pos2-pos1-1;
IF pos2 = len AND pos1 = len AND len > 0 THEN RETURN [name];
IF nlen <= 0 THEN RETURN [NIL];
RETURN [Rope.Substr[name, pos1+1, nlen]];
};
RemoteRootFileName: PUBLIC PROC [which: File.VolumeFile] RETURNS [ROPE] = {
defaultNames: PrinterNames.DefaultNames ← PrinterNames.Get[];
base: ROPE ~ SELECT which FROM
germ => machine,
microcode => Rope.Cat[defaultNames.printerType, "Cedar", machine],
bootFile => Rope.Concat["CedarPrinter", machine],
ENDCASE => "Unknown";
ext: ROPE ~ IagoOps.RootFileExtension[which];
RETURN [Rope.Cat[defaultNames.currentSystem, base, ext]];
};
InstallBootFileCommand: PROC [in, out: STREAM] = {
InstallLogicalFile[in, out, bootFile];
};
InstallGermFileCommand: PROC [in, out: STREAM] = {
InstallLogicalFile[in, out, germ];
};
InstallMicrocodeFileCommand: PROC [in, out: STREAM] = {
InstallLogicalFile[in, out, microcode];
};
InstallLogicalFile: PROC [in, out: STREAM, which: File.VolumeFile[checkpoint..bootFile]] = {
v: File.Volume = IagoOps.GetLogical[in, out, "For "];
vName: ROPE ~ File.GetVolumeName[v];
originName: ROPE ~ IagoOps.GetFile[in: in, out: out,
extension: IagoOps.RootFileExtension[which],
default: RemoteRootFileName[which],
check: TRUE
];
localName: ROPENIL;
fsFile: FS.OpenFile;
file: File.Handle;
createTime: BasicTime.GMT;
PhysicalToo: PROC RETURNS[BOOL] = {
IF which # bootFile THEN {
IO.PutRope[out, "\nInstalling on the physical volume"];
RETURN[TRUE];
};
IF FileBackdoor.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]]
};
OnVolume: PROC [name: ROPE] RETURNS [BOOL] ~ {
cp: FS.ComponentPositions;
[fullFName: name, cp: cp] ← FS.ExpandName[name];
IF cp.server.length#0 THEN RETURN [FALSE]; -- not local
IF cp.dir.length=0
THEN RETURN [File.SystemVolume[]=v] -- no explicit volume
ELSE RETURN [Rope.Equal[name.Substr[cp.dir.start, cp.dir.length], vName, FALSE]];
};
IO.PutRope[out, " ... "];
createTime ← FS.FileInfo[name: originName].created;
IO.PutF1[out, "%u ...", IO.time[createTime]];
{
Help: PROC = {
IO.PutF1[out, "? Please type the name of a local file on the %g volume", IO.rope[vName]];
};
localName ← IagoOps.LocalRootFileName[which, vName]; -- the default
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 OnVolume[localName] THEN EXIT ELSE Help[];
ENDLOOP;
IO.PutRope[out, " ... copying ... "];
before doing the copy, zap the entry in the root
FileBackdoor.SetRoot[v, which, NIL, [0]];
Pause[1000];  -- wait for logger to do its thing
localName ← FS.Copy[from: originName, to: localName];
};
createTime ← FS.FileInfo[localName].created;
fsFile ← FS.Open[name: localName, lock: write];
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 ... "];
FileBackdoor.SetRoot[v, which, file];
FS.SetByteCountAndCreatedTime[file: fsFile, created: createTime];
Restore the original create time; it was clobbered by FS.Open[... lock: write ...]
Pause[1000];  -- wait for logger to do its thing
IO.PutRope[out, "done"];
};
FS.Close[fsFile];
IF PhysicalToo[] THEN {
PhysicalVolume.SetPhysicalRoot[v, which];
IO.PutRope[out, " ... done"] };
};
InitialMicrocodeFileName: PUBLIC PROC RETURNS [ROPE] = {
defaultNames: PrinterNames.DefaultNames ← PrinterNames.Get[];
shortName: ROPE ← "InitialUnknown.eb";
SELECT SystemVersion.machineType FROM
dolphin => shortName ← "InitialPilotD0.eb";
dorado => shortName ← "InitialDiskDorado.eb";
dandelion => shortName ← "InitialDiskDLion.db";
dicentra => shortName ← "InitialEtherDicentra.eb";
ENDCASE;
RETURN [Rope.Concat[defaultNames.currentSystem, shortName]];
};
WriteRemoteNames: PUBLIC PROC [volume: ROPENIL, out: STREAMNIL] RETURNS [success: BOOLFALSE] = {
Writes the remote names on the given volume (NIL => systems volume), and write messages to the out stream (default: no messages).
WriteRemoteNamesInner: PROC ~ {
remoteNames: PrinterNames.DefaultNames ~ PrinterNames.Get[];
localDir: ROPE ~ SystemNames.LocalDir[volumeName: volume, subDirs: "DontDeleteMe"];
openFile: FS.OpenFile ~ FS.Create[Rope.Concat[localDir, "PrinterNames"]];
fileName: ROPE ~ FS.GetName[openFile].fullFName;
stream: STREAM ~ FS.StreamFromOpenFile[openFile: openFile, accessRights: $write];
IO.PutF1[stream, "PrinterHost: %g\n", [rope[remoteNames.printerHost]] ];
IO.PutF1[stream, "FontHost: %g\n", [rope[remoteNames.fontHost]] ];
IO.PutF1[stream, "CurrentSystem: %g\n", [rope[remoteNames.currentSystem]] ];
IO.PutF1[stream, "CurrentFont: %g\n", [rope[remoteNames.currentFont]] ];
IO.PutF1[stream, "PrinterType: %g\n", [rope[remoteNames.printerType]] ];
FOR each: FSPseudoServers.PseudoServerList ← FSPseudoServers.GetPseudoServers[], each.rest WHILE each # NIL DO
IO.PutRope[stream, FSPseudoServers.RopeFromPseudoServer[each]];
IO.PutRope[stream, "\n"];
ENDLOOP;
IO.Close[stream];
IF out#NIL THEN IO.PutF1[out, "\nRemote names saved to %g\n", [rope[fileName]]];
success ← TRUE;
};
IF NOT Booting.switches[n] THEN WriteRemoteNamesInner[!
FS.Error => {
IF out#NIL THEN out.PutF1["\nRemote names set, but not saved to disk:\n %g\n", [rope[error.explanation]] ];
CONTINUE
};
];
SetPupBufferSize[SystemSite.Get[].registry];
};
ReadRemoteNames: PROC [volume: ROPENIL, out: STREAMNIL]
RETURNS [success: BOOLFALSE] = {
Reads the remote names from the given volume (default: system volume).
fileName: ROPENIL;
Malformed: ERROR ~ CODE;
ReadRemoteNamesInner: PROC ~ {
names: PrinterNames.DefaultNames ← PrinterNames.Get[];
localDir: ROPE ~ SystemNames.LocalDir[volumeName: volume, subDirs: "DontDeleteMe"];
openFile: FS.OpenFile ~ FS.Open[Rope.Concat[localDir, "PrinterNames"]];
stream: STREAM ~ FS.StreamFromOpenFile[openFile: openFile, accessRights: $read];
GetKey: PROC [stream: STREAM, key: ROPE] RETURNS [BOOL] ~ {
token: ROPE ~ GetToken[stream];
RETURN [Rope.Equal[token, key, FALSE]];
};
fileName ← FS.GetName[openFile].fullFName;
IF NOT GetKey[stream, "PrinterHost:"] THEN ERROR Malformed;
names.printerHost ← GetToken[stream];
IF NOT GetKey[stream, "FontHost:"] THEN ERROR Malformed;
names.fontHost ← GetToken[stream];
IF NOT GetKey[stream, "CurrentSystem:"] THEN ERROR Malformed;
names.currentSystem ← GetToken[stream];
IF NOT GetKey[stream, "CurrentFont:"] THEN ERROR Malformed;
names.currentFont ← GetToken[stream];
IF NOT GetKey[stream, "PrinterType:"] THEN ERROR Malformed;
names.printerType ← GetToken[stream];
PrinterNames.Set[names];
[] ← IO.GetLineRope[stream ! IO.EndOfStream => CONTINUE];
DO -- Parse the pseudo-servers
line: ROPE ~ IO.GetLineRope[stream ! IO.EndOfStream => EXIT];
new: FSPseudoServers.PseudoServerList ← FSPseudoServers.PseudoServerFromRope[line].new;
IF new = NIL THEN EXIT;
FSPseudoServers.InsertPseudoServer[new];
ENDLOOP;
IO.Close[stream];
success ← TRUE;
};
IF NOT Booting.switches[n] THEN ReadRemoteNamesInner[!
FS.Error => {
IF out#NIL THEN out.PutF1["\nUnable to read remote names from disk:\n %g\n", [rope[error.explanation]] ];
CONTINUE;
};
Malformed, IO.EndOfStream => {
IF out#NIL THEN out.PutF1["\nTrouble reading remote names:\n The content of %g is malformed.\n", [rope[fileName]] ];
CONTINUE;
};
];
EnsureServer["Cedar", "Cyan", TRUE];
EnsureServer["Printer", "Cyan", TRUE];
EnsureServer["Fonts", "Cyan", TRUE];
SetPupBufferSize[SystemSite.Get[].registry];
};
SetPupBufferSize: PROC [registry: ROPE] ~ {
DKW: We assume for now that communication with sites outside the pa registry involves gateways that cannot yet cope with large buffers. When large buffers are accepted throughout the internet, this crock can go away. Presumably you will notice this when the PupStreamBackdoor interface disappears.
IF NOT Rope.Equal["pa", registry, FALSE] THEN
PupStreamBackdoor.SetMaxBufferSize[PupStreamBackdoor.maxOldGatewayBytes];
};
EnsureServer: PROC [server: ROPE, defaultHost: ROPE, noWrite: BOOL] = {
IF FSPseudoServers.Lookup[server] = NIL THEN {
This is a standard name that needs to be defined.
write: ROPE ~ IF noWrite THEN "$" ELSE defaultHost;
read: ROPE ~ defaultHost;
rope: ROPE ~ IO.PutFR["%g %g %g", IO.rope[server], IO.rope[write], IO.rope[read]];
FSPseudoServers.InsertPseudoServer[FSPseudoServers.PseudoServerFromRope[rope].new];
};
};
GetToken: PROC [st: STREAM] RETURNS [token: ROPENIL] = {
MyBreak: IO.BreakProc = {
[char: CHAR] RETURNS [IO.CharClass]
SELECT char FROM
' , '\t, '\n, ',, '; => RETURN [sepr];
ENDCASE;
RETURN [other];
};
token ← IO.GetTokenRope[st, MyBreak ! IO.EndOfStream => CONTINUE].token;
};
pulsesPerMilli: CARDINAL =
Basics.LongDiv[100000, ProcessorFace.microsecondsPerHundredPulses];
Pause: PROC [msecs: CARDINAL ← 10] = {
A simple processor-independent pausing routine.
THROUGH [0..msecs) DO
init: CARD = ProcessorFace.GetClockPulses[];
DO
current: CARD = ProcessorFace.GetClockPulses[];
IF current-init > pulsesPerMilli THEN EXIT;
ENDLOOP;
ENDLOOP;
};
InitializeNames: PROC ~ {
machine ← SELECT SystemVersion.machineType FROM
dolphin => "D0",
dorado => "Dorado",
dandelion => "DLion",
dicentra => "Dicentra",
daybreak => "Dove",
ENDCASE => "UnknownMachine";
extension[checkpoint] ← ".outload";
extension[germ] ← ".germ";
extension[microcode] ← (SELECT SystemVersion.machineType FROM
dandelion, dicentra => ".db", ENDCASE => ".eb");
extension[bootFile] ← ".boot";
localName[checkpoint] ← "Checkpoint";
localName[microcode] ← "Microcode";
localName[germ] ← "Germ";
localName[bootFile] ← "BootFile";
localName[debugger] ← "Debugger";
localName[debuggee] ← "Debuggee";
localName[VM] ← "VM";
localName[VAM] ← "VAM";
localName[fs] ← "FS";
localName[alpine] ← "Alpine";
};
Init: PROC [] = BEGIN
InitializeNames[];
[] ← ReadRemoteNames[];
IagoOps.RegisterCommand[[CreatePrinterWorld, "Create Printer World", TRUE]];
IagoOps.RegisterCommand[[SetPrinterRemoteNamesCommand, "Set Printer Names", TRUE]];
IagoOps.RegisterCommand[[SetPrinterDirectoriesCommand, "Set Printer Directories", TRUE]];
IagoOps.RegisterCommand[[SetPrinterTypeCommand, "Set Printer Type", TRUE]];
IagoOps.RegisterCommand[[InstallBootFileCommand, "Install Boot File"]];
IagoOps.RegisterCommand[[InstallGermFileCommand, "Install Germ"]];
IagoOps.RegisterCommand[[InstallMicrocodeFileCommand, "Install Cedar Microcode"]];
END;
Init[];
END.