<> <> <> DIRECTORY Basics USING [LongDiv], BasicTime USING [GMT], <> 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; <> 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: ROPE _ NIL; myName: ROPE = ThisMachine.Name[]; d: Disk.Channel = Disk.NextChannel[NIL]; newP: PhysicalVolume.Physical; newC: File.Volume; <> makeLabeled: BOOL _ FALSE; 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 <> <> <> <<};>> 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]; <> 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]; <> 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]; <> EXITS bailOut => { IO.PutRope[out, "\nEmpty printer type not permitted, command aborted.\n"]; }; }; machine: ROPE _ NIL; 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: ROPE _ NIL; 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 <> 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 ... "]; <> 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]; <> 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: ROPE _ NIL, out: STREAM _ NIL] RETURNS [success: BOOL _ FALSE] = { < 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: ROPE _ NIL, out: STREAM _ NIL] RETURNS [success: BOOL _ FALSE] = { <> fileName: ROPE _ NIL; 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] ~ { <> 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 { <> 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: ROPE _ NIL] = { 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] = { <> 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.