<<>> <> <> <> <> <> <> <> <> <> <> <> <<>> DIRECTORY Args USING [ Arg, ArgRope, Error, GetRope, NArgs ], Ascii, Basics USING [HighByte, LowByte, LowHalf], BasicTime USING [ GMT, Now, Period ], Commander USING [ CommandProc, Handle, Register ], CommanderOps USING [NextArgument], Convert, CStrings USING [CString], <> IO, PFS, PFSNames, PFSPrefixMap, Process USING [ CheckForAbort, EnableAborts, GetCurrent, InitializeCondition, SecondsToTicks ], Rope USING [ Cat, Concat, Equal, Fetch, Find, FindBackward, Flatten, Index, Length, ROPE, Substr], SimpleFeedback USING [PutFL], SymTab, SystemVersion USING [GetMachineType, MachineType, release], ThisMachine USING [ ProcessorID ], UnixErrno, UnixSysCalls USING [ GetPID, SymLink, Unlink ], UnixSysCallExtensions USING [Spawn], UnixTypes USING [CHARPtr, Mode, SysCallResult], UserProfile USING [Boolean, CallWhenProfileChanges, ListOfTokens, ProfileChangedProc, Token], UXStrings; CcCommandsImpl: CEDAR MONITOR IMPORTS Args, Ascii, Basics, BasicTime, Commander, CommanderOps, Convert, --ExtendADotOut,-- IO, PFS, PFSNames, PFSPrefixMap, Process, Rope, SimpleFeedback, SymTab, SystemVersion, ThisMachine, UnixErrno, UnixSysCalls, UnixSysCallExtensions, UserProfile, UXStrings ~ { ROPE: TYPE ~ Rope.ROPE; LOR: TYPE ~ LIST OF ROPE; ShouldNotHappen: ERROR [message: ROPE] ~ CODE; ForkTrouble: ERROR ~ CODE; NYI: ERROR ~ CODE; DeleteFiles: BOOL ~ TRUE; <> <> amd29000: SystemVersion.MachineType ~ LOOPHOLE[20, SystemVersion.MachineType]; rs6000: SystemVersion.MachineType ~ LOOPHOLE[21, SystemVersion.MachineType]; mipsle: SystemVersion.MachineType ~ LOOPHOLE[22, SystemVersion.MachineType]; -- little endian version of mips r3000 mipsbe: SystemVersion.MachineType ~ LOOPHOLE[23, SystemVersion.MachineType]; -- big endian version of mips r3000 <> <> <> <> <> <> <<>> CommandNames: TYPE = REF CommandNamesRep; CommandNamesRep: TYPE = RECORD[target: SystemVersion.MachineType, compiler, loader, move, csh, include, preCName, actualCName, insert: ROPE]; commandNamesList: LIST OF CommandNames; defaultCommandNames: CommandNames; <> uid: CARD32 ¬ 0; processID: INT ~ UnixSysCalls.GetPID[]; processorID: ROPE ~ ThisMachine.ProcessorID[$Octal]; MACHINECLASS: ROPE ~ "ComplexCc.MachineClass"; NewName: ENTRY PROC [suffix: ROPE ¬ ".o", wDir: ROPE--UXIO name--] RETURNS [ fName: ROPE ] ~ { ENABLE { UNWIND => NULL }; fName ¬ IO.PutFLR["cedarCc%gFrom%gp%g%g", LIST[IO.card[uid], IO.int[processID], IO.rope[processorID], IO.rope[suffix]]]; IF NOT Rope.Equal[wDir, NIL] THEN { IF wDir.Fetch[wDir.Length[]-1] # '/ THEN wDir ¬ Rope.Concat[wDir, "/"]; fName ¬ Rope.Concat[wDir, fName]; }; uid ¬ uid.SUCC; }; <> ViewFix: PROC [cedar, insert: ROPE, isDir, simpleExt, create: BOOL, otherUnlink: LOR, log: IO.STREAM] RETURNS [unix: ROPE ¬ NIL, unlink: LOR ¬ NIL] ~ { ENABLE PFS.Error => ERROR ShouldNotHappen[IO.PutFR["Got PFS.Error[%g, %g] while UXifying %g", [atom[error.code]], [rope[error.explanation]], [rope[cedar]] ]]; RETURN RealViewFix[cedar, insert, isDir, simpleExt, create, otherUnlink, log]}; RealViewFix: PROC [cedar, insert: ROPE, isDir, simpleExt, create: BOOL, otherUnlink: LOR, log: IO.STREAM] RETURNS [unix: ROPE ¬ NIL, unlink: LOR ¬ NIL] ~ { given: PFS.PATH ~ PFS.PathFromRope[cedar]; cedarPath: PFS.PATH ¬ PFSPrefixMap.Translate[ PFS.AbsoluteName[given]]; rawRope: ROPE ¬ PFS.RopeFromPath[cedarPath].Flatten[]; --for debugging viewComp: PFSNames.Component ¬ cedarPath.Fetch[0]; view: ROPE ¬ viewComp.ComponentRope[]; IF isDir # given.IsADirectory[] THEN ERROR ShouldNotHappen[IO.PutFR1[IF isDir THEN "%g not a directory" ELSE "%g is a directory", [rope[cedar]] ]]; IF isDir AND (insert#NIL OR create OR simpleExt) THEN ERROR--not implemented because not needed--; IF create THEN { out: IO.STREAM ~ PFS.StreamOpen[fileName: cedarPath, accessOptions: create, createOptions: [keep~1]]; file: PFS.OpenFile ~ PFS.OpenFileFromStream[out]; modeProp: ROPE; dm: UnixTypes.Mode; cedarPath ¬ PFS.GetInfo[file].fullFName; modeProp ¬ PFS.GetClientProperty[file, "UnixMode"]; dm ¬ LOOPHOLE[Convert.CardFromRope[modeProp]]; dm.owner.write ¬ true; PFS.SetClientProperty[file, "UnixMode", Convert.RopeFromCard[LOOPHOLE[dm, CARD16], 8]]; out.Close[] } ELSE cedarPath ¬ PFS.FileInfo[cedarPath].fullFName; SELECT TRUE FROM view.Equal["-ux", FALSE] => { original: ROPE ~ PFS.PFSNameToUnixName[cedarPath]; IF insert#NIL THEN { parent: PFS.PATH ~ cedarPath.Parent[]; parentRope: ROPE ~ PFS.PFSNameToUnixName[parent]; last: PFSNames.Component ~ cedarPath.ShortName[]; lastRope: ROPE ~ last.ComponentRope[--PFS doesn't put in version info--]; new: ROPE ~ parentRope.Cat[insert, lastRope]; GetLink[original, new, log]; RETURN [new, CONS[new, otherUnlink]]}; RETURN [original, otherUnlink]}; view.Equal["-vux", FALSE] => { fullRope: ROPE; unix ¬ PFS.PFSNameToUnixName[cedarPath]; fullRope ¬ unix.Flatten[]; --for debugging IF isDir THEN { RETURN [unix, otherUnlink]}; IF simpleExt OR insert#NIL THEN { fullLast: PFSNames.Component ¬ cedarPath.ShortName[]; verlessLast: ROPE ¬ fullLast.ComponentRope[--PFS doesn't put in version info--]; parent: PFS.PATH ¬ cedarPath.Parent[]; parentRope: ROPE ¬ PFS.PFSNameToUnixName[parent]; uxishRope: ROPE ¬ parentRope.Cat["/", insert, verlessLast]; IF NOT parent.IsADirectory[] THEN ERROR ShouldNotHappen["PFS shouldn't be crocky!"]; IF fullLast.version.versionKind # numeric THEN ERROR ShouldNotHappen[ IO.PutFR1["Didn't expect to find %g in file system (note version!)", [rope[PFS.RopeFromPath[cedarPath]]] ]]; GetLink[unix, uxishRope, log]; RETURN [uxishRope, CONS[uxishRope, otherUnlink]]} ELSE RETURN [unix, otherUnlink]; }; ENDCASE => ERROR ShouldNotHappen[ IO.PutFR1["Can't apply UNIX tools to %g because of its view", IO.rope[PFS.RopeFromPath[cedarPath]] ]]; }; emptyComponent: PFSNames.Component ~ []; Lower: PROC [old: CHAR] RETURNS [CHAR] ~ {RETURN Ascii.Lower[old]}; LinkData: TYPE ~ REF LinkDataRec; LinkDataRec: TYPE ~ RECORD [ from: ROPE, count: NAT, aHolder: PROCESS, toCP: UnixTypes.CHARPtr ¬ NIL, change: CONDITION]; GetLink: ENTRY PROC [from, to: ROPE, log: IO.STREAM] ~ { ENABLE UNWIND => NULL; err: ROPE ~ InnerGetLink[from, to, log]; IF err#NIL THEN RETURN WITH ERROR ShouldNotHappen[err]; RETURN}; InnerGetLink: INTERNAL PROC [from, to: ROPE, log: IO.STREAM] RETURNS [ROPE] ~ { start: BasicTime.GMT ~ BasicTime.Now[]; me: PROCESS ~ Process.GetCurrent[]; DO ld: LinkData ¬ NARROW[linkTab.Fetch[to].val]; IF ld=NIL THEN { ld ¬ NEW [LinkDataRec ¬ [NIL, 0, me]]; TRUSTED { Process.InitializeCondition[@ld.change, Process.SecondsToTicks[10]]; Process.EnableAborts[@ld.change]}; IF NOT linkTab.Insert[to, ld] THEN ERROR}; SELECT TRUE FROM ld.count=0 => { fromCP: UnixTypes.CHARPtr ~ UXStrings.Create[from]; toCP: UnixTypes.CHARPtr ¬ ld.toCP ¬ UXStrings.Create[to]; res: UnixTypes.SysCallResult ¬ UnixSysCalls.SymLink[fromCP, toCP]; IF res=failure THEN RETURN [IO.PutFR["Link from %g to %g failed; errno is %g", IO.rope[from], IO.rope[to], IO.card[LOOPHOLE[UnixErrno.GetErrno[], CARD]]]]; ld.count ¬ ld.count.SUCC; ld.from ¬ from; ld.aHolder ¬ me; IF debugLinks AND log#NIL THEN log.PutF["%g -> %g: %g\n", [rope[from]], [rope[to]], [integer[ld.count]]]; RETURN [NIL]}; ld.from.Equal[from, TRUE--UNIX is case sensitive--] => { ld.count ¬ ld.count.SUCC; IF debugLinks AND log#NIL THEN log.PutF["%g -> %g: %g\n", [rope[from]], [rope[to]], [integer[ld.count]]]; RETURN [NIL]}; ld.aHolder = me => RETURN [IO.PutFR["Trying to link %g to both %g and %g", [rope[to]], [rope[from]], [rope[ld.from]] ]]; ENDCASE => { now: BasicTime.GMT ~ BasicTime.Now[]; waited: INT ~ BasicTime.Period[start, now]; IF waited > linkTimeout THEN RETURN[IO.PutFLR["Unable to link %g -> %g for %gs (timeout is %g) 'cause of conflict with %g", LIST[[rope[to]], [rope[from]], [integer[waited]], [integer[linkTimeout]], [rope[ld.from]]]]]; WAIT ld.change}; ENDLOOP; }; linkTab: SymTab.Ref ~ SymTab.Create[case: TRUE]; debugLinks: BOOL ¬ FALSE; linkTimeout: NAT ¬ 100; DropLink: ENTRY PROC [to: ROPE, log: IO.STREAM] ~ { ENABLE UNWIND => NULL; err: ROPE ~ InnerDropLink[to, log]; IF err#NIL THEN RETURN WITH ERROR ShouldNotHappen[err]; RETURN}; InnerDropLink: INTERNAL PROC [to: ROPE, log: IO.STREAM] RETURNS [ROPE] ~ { ld: LinkData ¬ NARROW[linkTab.Fetch[to].val]; IF ld=NIL OR ld.count=0 THEN RETURN [IO.PutFR1["Excess dropping of link to %g", [rope[to]] ]]; ld.count ¬ ld.count.PRED; IF debugLinks AND log#NIL THEN log.PutF["%g: %g\n", [rope[to]], [integer[ld.count]]]; IF ld.count=0 THEN { res: UnixTypes.SysCallResult ~ UnixSysCalls.Unlink[ld.toCP]; IF NOT linkTab.Delete[to] THEN ERROR; IF res = failure THEN RETURN [IO.PutFR["Unlink failed for %g; errno is %g", IO.rope[to], IO.card[LOOPHOLE[UnixErrno.GetErrno[], CARD]]]]; }; BROADCAST ld.change; RETURN [NIL]}; UnlinkList: PROC [list: LOR, log: IO.STREAM] ~ { FOR list ¬ list, list.rest WHILE list#NIL DO DropLink[list.first, log]; ENDLOOP; RETURN}; ConsComponent: PROC [name: ROPE, version: PFSNames.Version] RETURNS [PFSNames.Component] ~ { RETURN [[name: [base: name, start: 0, len: name.Length[]], version: version]]}; <> MachineTypeFromMachineClass: PROC [ machineClass: ROPE ] RETURNS [ machineType: SystemVersion.MachineType ] ~ { X: INT ¬ 1; -- for breakpoint for debugging SELECT TRUE FROM Rope.Equal[machineClass, "sparc", FALSE] => machineType ¬ sun4; Rope.Equal[machineClass, "mc68020", FALSE] => machineType ¬ sun3; Rope.Equal[machineClass, "sun4", FALSE] => machineType ¬ sun4; Rope.Equal[machineClass, "sun3", FALSE] => machineType ¬ sun3; Rope.Equal[machineClass, "amd29000", FALSE] => machineType ¬ amd29000; Rope.Equal[machineClass, "rs6000", FALSE] => machineType _ rs6000; Rope.Equal[machineClass, "mipsl", FALSE] => machineType _ mipsle; Rope.Equal[machineClass, "mips", FALSE] => machineType _ mipsbe; ENDCASE => { FOR list: LIST OF MachinePair ¬ userList, list.rest UNTIL list = NIL DO IF Rope.Equal[machineClass, list.first.machineClass, FALSE] THEN RETURN[list.first.machineType]; ENDLOOP; ERROR; }; }; MachineClassFromMachineType: PROC [ machineType: SystemVersion.MachineType ] RETURNS [ machineClass: ROPE ] ~ { SELECT machineType FROM sun4 => machineClass ¬ "sun4"; sun3 => machineClass ¬ "sun3"; amd29000 => machineClass ¬ "amd29000"; rs6000 => machineClass _ "rs6000"; mipsle => machineClass _ "mipsl"; mipsbe => machineClass _ "mips"; ENDCASE => { FOR list: LIST OF MachinePair ¬ userList, list.rest UNTIL list = NIL DO IF machineType = list.first.machineType THEN RETURN[list.first.machineClass]; ENDLOOP; machineClass _ "I don't know"; }; }; GetCommandNames: PROC [host, target: SystemVersion.MachineType] RETURNS[CommandNames] ~ { IF host # sun4 THEN ERROR ShouldNotHappen ["host is not a sun4"]; FOR cnL: LIST OF CommandNames ¬ commandNamesList, cnL.rest UNTIL cnL=NIL DO IF target = cnL.first.target THEN RETURN[cnL.first]; ENDLOOP; RETURN[defaultCommandNames]; }; OnProfileChange: UserProfile.ProfileChangedProc ~ { pList: LIST OF ROPE ~ UserProfile.ListOfTokens["MakeDo.UserClasses", NIL]; compiler, loader, move, csh, include, insertRope, preCName, actualCName: ROPE; useLinks: BOOL ¬ TRUE; this: CommandNames; userList ¬ NIL; commandNamesList ¬ NIL; FOR list: LIST OF ROPE _ pList, list.rest UNTIL list = NIL DO userList ¬ CONS[[list.first, nextMachineType], userList]; nextMachineType ¬ nextMachineType.SUCC; ENDLOOP; compiler ¬ UserProfile.Token["ComplexCc.cc", compilerDefault]; include ¬ UserProfile.Token["ComplexCc.include", includeDefault]; loader ¬ UserProfile.Token["ComplexCc.ld", loadDefault]; move ¬ UserProfile.Token["ComplexCc.mv", moveDefault]; csh ¬ UserProfile.Token["ComplexCc.csh", cshDefault]; useLinks ¬ UserProfile.Boolean["ComplexCc.useLinks", useLinks]; [preCName, actualCName] ¬ ExamineCompilerName[compiler]; defaultCommandNames ¬ NEW[CommandNamesRep ¬ [ sun4, compiler, loader, move, csh, include, preCName, actualCName, IF useLinks THEN insertRopeDefault ELSE NIL]]; FOR uL: LIST OF ROPE ¬ pList, uL.rest UNTIL uL=NIL DO class: ROPE ~ uL.first; compiler ¬ UserProfile.Token[Rope.Cat["ComplexCc.", class, ".cc"], defaultCommandNames.compiler]; include ¬ UserProfile.Token[Rope.Cat["ComplexCc.", class, ".include"], defaultCommandNames.include]; loader ¬ UserProfile.Token[Rope.Cat["ComplexCc.", class, ".ld"], defaultCommandNames.loader]; move ¬ UserProfile.Token[Rope.Cat["ComplexCc.", class, ".mv"], defaultCommandNames.move]; csh ¬ UserProfile.Token[Rope.Cat["ComplexCc.", class, ".csh"], defaultCommandNames.csh]; useLinks ¬ UserProfile.Boolean[Rope.Cat["ComplexCc.", class, ".useLinks"], TRUE]; [preCName, actualCName] ¬ ExamineCompilerName[compiler]; this ¬ NEW[CommandNamesRep ¬ [ MachineTypeFromMachineClass[class], compiler, loader, move, csh, include, preCName, actualCName, IF useLinks THEN insertRopeDefault ELSE NIL]]; commandNamesList ¬ CONS[this, commandNamesList]; ENDLOOP; }; ExamineCompilerName: PROC[cName: ROPE] RETURNS[preCName, actualCName: ROPE ¬ NIL] ~ { <> pos: INT; IF NOT Rope.Find[cName, "rsh ", 0] = 0 THEN RETURN[NIL, cName]; pos ¬ Rope.FindBackward[cName, " "]; RETURN[Rope.Substr[cName, 0, pos], Rope.Substr[cName, pos+1]]; }; UnixNil: UnixTypes.CHARPtr ~ LOOPHOLE[NIL]; MsgFromExitError: PROC [status: INT, command: ROPE] RETURNS [msg: ROPE] ~ { lowHalf: CARD16 ~ Basics.LowHalf[LOOPHOLE[status, CARD32]]; lowByte: BYTE ~ Basics.LowByte[lowHalf]; nextLowByte: BYTE ~ Basics.HighByte[lowHalf]; low7: BYTE; IF lowByte = 177B THEN { msg ¬ IO.PutFR["execution of %g stopped by signal %g\n", IO.rope[command], IO.int[nextLowByte]]; RETURN [msg]; }; IF lowByte = 0 THEN { msg ¬ IO.PutFR["execution of %g exited with %g\n", IO.rope[command], IO.int[nextLowByte]]; RETURN [msg]; }; <