Trailing-Edge
-
PDP-10 Archives
-
bb-d868c-bm_tops20_v4_2020_distr
-
language-sources/qsrt20.mac
There are 36 other files named qsrt20.mac in the archive. Click here to see a list.
TITLE QSRT20 -- Operating System Interface for QUASAR-20
;
;
; COPYRIGHT (c) 1975,1976,1977,1978,1979
; DIGITAL EQUIPMENT CORPORATION
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
; AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE
; AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS
; SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR
; OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO
; AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE
; WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
; BY DIGITAL EQUIPMENT CORPORATION.
;
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
; OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY
; DIGITAL.
SEARCH QSRMAC,GLXMAC,ORNMAC ;PARAMETER FILE
PROLOGUE(QSRT20) ;GENERATE THE NECESSARY SYMBOLS
IFE FTJSYS,<
PASS2 ;DON'T BOTHER FOR TOPS-10 ASSEMBLY
END
> ;END OF IFE FTJSYS
COMMENT \
TOPS20 Field Interpretation
1) External Owner ID is a User Name
2) Owner ID (Internal) is a User Number
\
SUBTTL Module Storage
LVL1PC: BLOCK 1 ;PC AT INTERRUPT
FILJFN: BLOCK 1 ;JFN OF MASTER QUEUE FILE
FSPAGN: BLOCK 1 ;SCRATCH PAGE FOR I$READ/I$WRIT
FSADDR: BLOCK 1 ; SAME AS FSPAGN BUT AS AN ADDRESS
UNILST: BLOCK 1 ;LIST NUMBER OF UNIQUE LIST
; DIRECTORY FOR /UNIQUE CHECK
;LEVTAB AND CHNTAB MUST BE CONTIGUOUS AND IN THE FOLLOWING ORDER.
INTBLK==:<XWD LEVTAB,CHNTAB> ;USED FOR INTIALIZATION
LEVTAB: EXP LVL1PC ;POINTER TO OLD PC STORAGE
0 ;2ND AND
0 ;3RD LEVELS ARE UNUSED
CHNTAB: XWD INT.PL,C$INT## ;IPCF ON CHANNEL 0
0,,0 ;NOTHING ON CHANNEL 1
XWD INT.PL,N$INT## ;NETWORK CHANGE INTRPTS ON CHANNEL 2
BLOCK ^D33 ;FILL IN REST OF TABLE
INTERN USR ;THESE 2 ITEXTS ARE USED BY THE QUEUE'S
INTERN STRUCT ; LISTING ROUTINES IN QSRDSP
INTERN MNTUSR ;SAME AS USR EXCEPT FOR MOUNT DISPLAYS
USR: ITEXT (<^T/.QEOWN(AP)/>) ;ASCIZ TOPS-20 OWNER NAME.
MNTUSR: ITEXT (<^T/.MRNAM(AP)/>) ;ASCIZ TOPS-20 USER NAME
STRUCT: ITEXT (<^T/STRNAM(S1)/>) ;ASCIZ TOPS-20 STRUCTURE NAME
DEFINE X(QUE),<
<SIXBIT/QUE/>!<.OT'QUE> >
RETSEQ: BLOCK 1 ;SEQUENCE COUNTER FOR RET QUEUE
QLIST: DEVQUE
NDEVS==.-QLIST
SUBTTL Initialization Routine
;ROUTINE TO INITIALIZE THE WORLD. I$INIT INITIALIZES THE I/O
; SYSTEM.
;
I$INIT:: CIS ;CLEAR THE INTERRUPT SYSTEM
PUSHJ P,.SAVET ;SAVE T REGS
MOVEI S1,.MUMPS ;FUNCTION FOR MAX PACKET SIZE
MOVEM S1,INIT.B ;STORE AWAY
ZERO INIT.B+1 ;CLEAR SECOND WORD
MOVEI S1,2 ;GET BLOCK SIZE
MOVEI S2,INIT.B ;AND ADDRESS OF BLOCK
MUTIL ;GET THE INFO
$STOP(CGP,CAN'T GET PACKET SIZE)
MOVE S1,INIT.B+1 ;GET THE ANSWER
MOVEM S1,G$MPS## ;SAVE IT
SKIPE DEBUGW ;ARE WE [PRIVATE]QUASAR?
JRST INIT.1 ;YES, NO NEED TO QUERY <SPOOL>
MOVX S1,RC%EMO ;EXACT MATCH ONLY
HRROI S2,[ASCIZ /PS:<SPOOL>/] ;DIRECTORY OF SPOOL
RCDIR ;RECOGNIZE IT
TXNE S1,RC%NOM ;MATCH?
$STOP(NSD,NO SPOOLING DIRECTORY)
MOVE S1,T1 ;COPY DIR NUMBER INTO S1
MOVEI S2,TMPBFR ;LOAD ADDR OF BLOCK
ZERO T1 ;DON'T WANT THE PASSWORD
GTDIR ;GET DIRECTORY INFO
ERCAL S..NSD ;
HRRZ S1,TMPBFR+7 ;GET DEFAULT PROTECTION
MOVEM S1,G$SPRT## ;AND STORE IT
INIT.1: ZERO G$MCOR## ;THERE IS NO SYSTEM MINIMUM
MOVEI S1,777777 ;512 PAGES
MOVEM S1,G$XCOR## ;IS MAXIMUM CORE LIMIT
SETO S1, ;-1 = MY JOB
HRROI S2,T2 ;POINT TO ARG BLOCK
SETZ T1, ;WORD 0
GETJI ;GET MY JOB NUMBER
$STOP(CGJ,CANT GET JOB NUMBER)
$SITEM T2,QJOB ;AND STORE IT
PUSHJ P,I%ION ;ENABLE INTERRUPTS
PUSHJ P,L%CLST ;CREATE A LIST
MOVEM S1,UNILST ;SAVE LIST NAME
MOVX S1,.SFAVR ;GET ACCOUNT VALIDATION CODE
TMON ;FIND OUT IF ITS SET
ERJMP .+2 ;NO GOOD,,VALIDATION NOT ON !!!
SETOM G$ACTV## ;ELSE WE'RE ACCOUNT VALIDATING..
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
;FLUSH THE RETREIVAL QUEUES FOR JOBS WHICH WERE WAITING.
SETOM G$APID## ;SET ACCOUNTING PID TO -1
ZERO P1 ; and initialize sequence number
MOVEI H,HDRRET## ; Point to RET queue header
LOAD E,.QHLNK(H),QH.PTF ; Point to first entry
INIT.2: JUMPE E,INIT.4 ; Quit if end of queue
LOAD P2,.QESEQ(E),QE.SEQ ; Get sequence number
CAMGE P1,P2 ; Biggest yet?
MOVE P1,P2 ; Yes, update max
LOAD P3,.QESEQ(E),QE.PRI ; Get priority
CAIE P3,.RETRW ; Was this job waiting?
JRST INIT.3 ; No, skip it
LOAD S1,.QESTN(E),QE.DPA
MOVE AP,E
PUSHJ P,F$RLRQ## ; Release failsoft copy
MOVE AP,E ; To be safe
LOAD E,.QELNK(E),QE.PTN ; Do this before freeing
PUSHJ P,M$RFRE## ; Delink and free the cell
INIT.3: LOAD E,.QELNK(E),QE.PTN ; Point to next in Q
JRST INIT.2 ; Continue
INIT.4: MOVEM P1,RETSEQ ; Remember sequence number
MOVE S1,G$LNAM## ;GET THE HOST NODE NAME
STORE S1,COMSTA##+.OHDRS+ARG.DA+OBJ.ND ;SAVE IT
MOVEI S1,.OTXFR ;GET THE FILE TRANSFER OBJ TYPE
STORE S1,COMSTA##+.OHDRS+ARG.DA+OBJ.TY ;SAVE IT
MOVEI M,COMSTA## ;ISSUE THE STARTUP COMMAND
PUSHJ P,A$OSTA## ;FOR THE FILE TRANSFER PROCESSOR
MOVEI S1,.OTRET ;GET THE RETRIEVAL OBJ TYPE
STORE S1,COMSTA##+.OHDRS+ARG.DA+OBJ.TY ;SAVE IT
MOVEI M,COMSTA## ;ISSUE THE STARTUP COMMAND
PUSHJ P,A$OSTA## ;FOR THE RETRIEVAL PROCESSOR
MOVEI S1,.OTNOT ;GET THE NOTIFICATION OBJ TYPE
STORE S1,COMSTA##+.OHDRS+ARG.DA+OBJ.TY ;SAVE IT
MOVEI M,COMSTA## ;ISSUE THE STARTUP COMMAND
PUSHJ P,A$OSTA## ;FOR THE NOTIFICATION PROCESSOR
PUSHJ P,NTIMER ;GO SET THE NOTIFICATION TIMER
$RETT ;RETURN WHEN DONE
INIT.B: BLOCK 2 ;MUTIL BLOCK
TMPBFR: BLOCK ^D14 ;GTDIR BLOCK
SUBTTL Information
;ENTRY POINTS
INTERN I$SYSV ;READ AND REMEMBER TIME-DEPENDENT SYSTEM VARIABLES
INTERN I$WHEEL ;CHECK IF CURRENT SENDER IS SOME FLAVOR OF OPERATOR
INTERN I$AGE ;COMPUTE AGE USING INTERNAL FORMAT DATE/TIME
INTERN I$AFT ;MODIFY AN INTERNAL TIME BY ADDITION
INTERN I$CHAC ;CHECK ACCESS
INTERN I$NINT ;TURN ON NETWORK CHANGE INTERRUPTS
SUBTTL I$SYSV -- Read time-dependent system variables
;I$SYSV is called to read and remember all relevent system variables
; which could change with time. On TOPS20 these are:
;
; Variable Memeory
; -------- -------
;
; Time till KSYS G$KSYS = > 0 --- seconds till KSYS
; = = 0 --- no KSYS set
; = < 0 --- timesharing is over
; Batch logins allowed G$LOGN = 0 --- no
; = -1 --- yes
; Time of day G$NOW
I$SYSV: PUSHJ P,I%NOW ;GET TIME OF DAY
MOVEM S1,G$NOW## ;STORE IT
MOVE S1,[SIXBIT/DWNTIM/] ;THE SYSTEM TABLE NAME
SYSGT ;GET THE TABLE NUMBER AND ENTRY 0
SKIPN S2 ;SKIP IF THE TABLE EXISTS
ZERO S1 ;ELSE RETURN A ZERO
JUMPE S1,SYSV.2 ;EXIT IF NONE PENDING
PUSH P,S1 ;SAVE TIME FOR NOW
MOVEI S1,1 ;FIND NOW PLUS 1 MINUTE
PUSHJ P,I$AFT ;COMPUTE IT
POP P,S2 ;NOW GET WHEN SCHEDULED
SUB S2,S1 ;CALC # OF JIFFIES TILL SHUTDOWN
IDIVI S2,3 ;CALC # OF SECONDS TILL SHUTDOWN
SKIPN S1,S2 ;GET # OF SECONDS IN S1
SETOM S1 ;IF 0,,THEN MAKE IT NEGATIVE
SYSV.2: MOVEM S1,G$KSYS## ;AND STORE RESULT
SETOM G$LOGN## ;ASSUME LOGINS ALLOWED
MOVX S1,.SFPTY ;PTY LOGINS BIT
TMON ;TEST IT
SKIPN S2 ;CAN WE?
SETZM G$LOGN## ;NOPE!
$RETT ;AND RETURN
SUBTTL I$WHEEL -- Determine whether sender of current message is privileged
;Call to determine whether the send of the current IPCF message has lots of
; privs.
;Call: No arguments
;T Ret: If caller is a wheel (or operator)
;F Ret: If caller has no special privs
I$WHEEL:
MOVE S1,G$PRVS## ;GET PRIVS WORD
SKIPN DEBUGW ;IF DEBUGGING, ALWAYS SUCCEED
TXNE S1,MD.PWH!MD.POP ;WHEEL OR OPERATOR?
$RETT ;YES, RETURN TRUE
$RETF ;NOW RETURN FALSE
SUBTTL I$AGE -- Routine to compare two times in internal format
;ROUTINE TO COMPUTE THE AGE IN SECONDS BASED ON THE INTERNAL DATE/TIME FORMAT
;
;CALL:
; S1 AND S2 ARE THE TIMES TO COMPUTE AGES
; PUSHJ P,I$AGE
; RETURNS HERE WITH AGE IN SECONDS IN S1
;DESTROYS S1,S2 IN THE PROCESS
I$AGE: CAMGE S1,S2 ;ORDERING CHECK
EXCH S1,S2 ;WANT THE LARGEST IN S1
SUB S1,S2 ;SUBTRACT THEM
IDIVI S1,3 ;RESOLUTION IS APPROX. 1/3 SEC
SKIPG S1 ;ANY TIME HERE ???
MOVEI S1,1 ;NO,,RETURN 1 SECOND
$RETT ;RETURN
SUBTTL I$AFT -- Routine to modify an internal time
;ROUTINE TO RETURN G$NOW + A SPECIFIED INTERVAL.
;
;CALL:
; S1 CONTAINS INTERVAL IN MINUTES
; PUSHJ P,I$AFT
; RETURN HERE WITH S1=G$NOW+SPECIFIED INTERVAL
I$AFT: ZERO S2 ;ZERO FOR A SHIFT
ASHC S1,-^D17 ;GENERATE DOUBLE CONSTANT
; = ARG*2^18
DIVI S1,^D1440 ;DIVIDE BY MIN/DAY
ADD S1,G$NOW## ;ADD IN NOWTIM
$RETT ;AND RETURN
SUBTTL I$CHAC -- Routine to Check File Access
;ROUTINE TO CHECK FILE AND QUEUE REQUEST ACCESS
;
;CALL:
; MOVE S1,[ACCESS CODE,,PROTECTION]
; MOVE S2,DIRECTORY OF FILE OR REQUEST
; PUSHJ P,I$CHAC
; RETURN HERE ALWAYS
;
;CHECK IS MADE AGAINST SENDER OF CURRENT REQUEST
;TRUE RETURN: ACCESS ALLOWED
;FALSE RETURN: ACCESS NOT ALLOWED
I$CHAC: LOAD S1,G$SID## ;GET SENDER'S ID
CAME S1,S2 ;IS HE THE OWNER
PJRST I$WHEEL ;NO, WIN ONLY IF WHEEL
$RETT ;YES, LET HIM DO IT
SUBTTL I$NINT - ROUTINE TO SETUP FOR NETWORK CHANGE INTERRUPTS
I$NINT: MOVX S1,.NDSIC ;GET ADD CHANNEL TO INTRPT SYS FUNCTION
MOVEI S2,T1 ;GET THE ARGUMENT BLOCK ADDRESS
MOVEI T1,2 ;WANT INTERRUPTS ON CHANNEL 2
NODE ;TELL THE SYSTEM WHAT WE WANT
ERJMP .RETT ;ON AN ERROR,,JUST IGNORE IT
MOVX S1,.FHSLF ;GET MY PROCESS HANDLE
MOVX S2,1B2 ;WANT CHANNEL 2
AIC ;ACTIVATE NETWORK CHANGE INTERRUPTS
ERJMP .+1 ;IGNORE ANY ERROR
$RETT ;AND RETURN
SUBTTL IPCF Interface
;ENTRY POINTS
INTERN I$IPS ;IPCF SEND
SUBTTL I$IPS -- Send an IPCF Message
;ROUTINE TO SEND AN IPCF MESSAGE.
;CALL:
; MOVE S1,PDB SIZE
; MOVE S2,ADDRESS OF PDB
; PUSHJ P,I$IPS
;
;TRUE RETURN: IF SEND IS OK
;FALSE RETURN: IF SEND FAILS, ERROR CODE IN S1
I$IPS: MSEND ;SEND THE MESSAGE
$RETF ;ERROR RETURN
$RETT ;WIN, RETURN ALL OK
SUBTTL FD Manipulation Routines
INTERN I$CSM ;Create a Canonical SPOOL Message
INTERN I$CLM ;Create a Canonical LOGOUT Message
SUBTTL I$CSM -- Create a Canonical SPOOL Message
;CALL I$CSM TO CONVERT A SPOOL MESSAGE RECEIVED FROM THE OPERATING SYSTEM
; INTO A CANONICAL FORM WHICH EVERYONE CAN USE.
;CALL: M/SPOOL MESSAGE ADDRESS
; PUSHJ P,I$CSM
; RETURN HERE WITH S1 CONTAINING THE ADR OF THE CSM
I$CSM: PUSHJ P,.SAVET ;SAVE T1-T4 FOR USE HERE
MOVE T1,[CSM.A,,CSM.A+1] ;SET UP TO ZERO CSM AREA
ZERO CSM.A ;ZERO FIRST WORD
BLT T1,CSM.A+CSMSIZ-1 ;AND ALL THE REST
LOAD T1,SPL.JB(M),SP.JOB ;GET THE JOB NUMBER
STORE T1,CSM.A+CSM.JB,CS.JOB ;AND SAVE IT IN CSM
LOAD T1,SPL.FL(M),SP.DFR ;GET THE DEFER BIT
STORE T1,CSM.A+CSM.JB,CS.DFR ;AND SAVE IT@IN SPOOL MESSAGE
LOAD T1,SPL.FL(M),SP.LOC ;GET THE STATION NUMBER
STORE T1,CSM.A+CSM.JB,CS.LOC ;AND SAVE IT IN CSM
MOVE S1,[POINT 7,G$LOCN##] ;POINT TO THE JOBS LOCATION (IN ASCII)
PUSHJ P,S%SIXB ;CONVERT IT TO SIXBIT
STORE S2,CSM.A+CSM.RO+.ROBND ;SAVE IT AS THE DESTINATION NODE
LOAD T1,G$SID## ;GET THE USERS ID
STORE T1,CSM.A+CSM.OI ;STORE IT IN CSM
LOAD T1,SPL.BV(M),SP.SIZ ;GET THE FILE SIZE IN PAGES
STORE T1,CSM.A+CSM.FS ;SAVE IT IN CSM
MOVE T1,CSM.F ;GET THE STANDARD FLAGS FOR SPOOLING
STORE T1,CSM.A+CSM.FP ;INTO THE CSM
MOVEI S1,SPL.FI-1(M) ;GET THE ADDRESS OF THE FD
SETZM .FDLEN(S1) ;CLEAR THE COUNT FOR NOW
MOVEI T1,.FDSTG(S1) ;POINT T1 TO THE FILESPEC
STORE S1,CSM.A+CSM.FD,CS.FDA ;AND SAVE IT AS THE ADDRESS OF THE CSM FD
HRLI T1,(POINT 7,0) ;MAKE T1 A BYTE POINTER TO THE FD
ZERO T2 ;BUT DON'T STORE THIS
MOVX T3,<76,,0> ;TERMINATE ON RIGHT ANGLE BRACKET
ZERO T4 ;NO COUNT
PUSHJ P,FBREAK ;SKIP TO END OF DIRECTORY
SKIPN S1 ;IF NOT NULL,,OK.
PUSHJ P,CSM.3 ;ELSE LEAVE A TRACK AND STOPCODE.
MOVE T2,[POINT 6,CSM.A+CSM.RO+.ROBTY] ;STORE NEXT STUFF AS DEVICE
MOVEI T4,6 ;ONLY 6 CAHRACTERS
MOVE T3,["-",,"A"-'A'] ;STOP ON -, CONVERT TO SIXBIT
PUSHJ P,FBREAK ;PICK UP DEVICE NAME
SKIPN S1 ;IF NOT NULL,,OK.
PUSHJ P,CSM.3 ;ELSE LEAVE A TRACK AND STOPCODE.
ZERO T2 ;DON'T STORE ANYTHING
ZERO T4 ;NO COUNT
MOVSI T3,"-" ;STOP ON MINUS
PUSHJ P,FBREAK ;SKIP THE STATION NUMBER
SKIPN S1 ;IF NOT NULL,,OK.
PUSHJ P,CSM.3 ;ELSE LEAVE A TRACK AND STOPCODE.
;"I$CSM" IS CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
ZERO T4 ;NO COUNT
ZERO T2 ;NO DESTINATION
MOVSI T3,"-" ;STOP ON MINUS
PUSHJ P,FBREAK ;AND THE DIRECTORY NUMBER
SKIPN S1 ;IF NOT NULL,,OK.
PUSHJ P,CSM.3 ;ELSE LEAVE A TRACK AND STOPCODE.
MOVE T2,[POINT 6,CSM.A+CSM.EN] ;SET UP TO STORE THE ENTERED NAME
MOVEI T4,6 ;ONLY 6 CHARACTERS
MOVE T3,[".",,"A"-'A'] ;ENDED WITH ., CONVERTED TO SIXBIT
PUSHJ P,FBREAK ;PICK UP THE ENTERED NAME
SKIPN S1 ;IF NOT NULL,,OK
PUSHJ P,CSM.3 ;ELSE LEAVE A TRACK AND STOPCODE.
SKIPN S1,CSM.A+CSM.EN ;GET ENTERED NAME INTO S1
LOAD S1,SPL.PG(M) ;IF NO ENTERED NAME,USE PROGRAM NAME
STORE S1,CSM.A+CSM.EN ;SAVE AS ENTERED NAME
CSM.1: ILDB T2,T1 ;PICK UP NEXT CHARACTER
JUMPN T2,CSM.1 ;LOOP UNTIL A NUL
TLZ T1,-1 ;CONVERT BYTE POINTER TO ADDRESS
SUBI T1,SPL.FI-2(M) ;AND MAKE INTO LENGTH OF FD
LOAD T2,CSM.A+CSM.FD,CS.FDA ;GET ADDRESS OF THE FD
STORE T1,.FDLEN(T2),FD.LEN ;AND STORE THE LENGTH
MOVSI S1,-NDEVS ;CREATE AN AOBJN AC.
HLLZ T1,CSM.A+CSM.RO+.ROBTY ;GET THE DEVICE NAME.
HRRZ T2,CSM.A+CSM.RO+.ROBTY ;GET THE DEVICE NUMBER
CSM.2: HLLZ S2,QLIST(S1) ;FIND THE DEVICE TYPE
CAME S2,T1 ; FROM THE SPOOL MSG IN THE LIST OF Q'S
JRST [AOBJN S1,CSM.2 ;NO MATCH,,TRY THE NEXT ENTRY
PUSHJ P,CSM.3 ] ;NO THERE,,LEAVE A TRACK AND STOPCODE.
HRRZ S2,QLIST(S1) ;PICK UP THE .OT??? SYMBOL (Q TYPE)
MOVEM S2,CSM.A+CSM.RO+.ROBTY ;SAVE IT AS THE OBJECT TYPE.
JUMPE T2,CSM.2A ;NO DEVICE SPECIFIED,,JUST RETURN
LSH T2,-^D12 ;RIGHT JUSTIFY THE DEVICE NUMBER
SUBI T2,'0' ;MAKE IT BINARY
TXO T2,RO.PHY ;TURN ON PHYSICAL BIT
STORE T2,CSM.A+CSM.RO+.ROBAT ;SAVE AS DEVICE ATTRIBUTES
CSM.2A: MOVEI S1,CSM.A ;PUT ADDRESS OF CSM IN S1 FOR CALLER
$RETT ;AND RETURN
CSM.3: $STOP(BSD,Bad SPOOL data)
CSM.A: BLOCK CSMSIZ ;PLACE FOR CSM
CSM.F: INSVL.(.FPFAS,FP.FFF)!INSVL.(1,FP.FSP)!FP.DEL!FP.SPL!INSVL.(1,FP.FCY)
SUBTTL I$CLM -- Create a Canonical LOGOUT Message
;CALL I$CLM TO CONVERT A LOGOUT MESSAGE RECEIVED FROM THE OPERATING SYSTEM
; INTO A CANONICAL FORM WHICH EVERYONE CAN USE.
;CALL:
; MOVE S1,[ADR OF LOGOUT MESSAGE FROM OPERATING SYSTEM]
; PUSHJ P,I$CLM
; RETURN HERE WITH S1 CONTAINING THE ADR OF THE CLM
I$CLM: MOVX S2,.IPCSL ;GET FUNCTION CODE
STORE S2,<CLM.A+CLM.FC> ;STORE THE FUNCTION
LOAD S2,LGO.JB(S1),LG.JOB ;GET JOB NUMBER
STORE S2,<CLM.A+CLM.JB>,CL.JOB ;STORE IT
LOAD S2,LGO.FL(S1),LG.BAT ;GET THE BATCH BIT
STORE S2,<CLM.A+CLM.JB>,CL.BAT ;STORE IT
MOVEI S1,CLM.A ;LOAD ADR OF THE CLM
$RETT ;AND RETURN
CLM.A: BLOCK CLMSIZ ;BLOCK TO RETURN CLM
SUBTTL Routines to handle system dependent fields
INTERN I$EQQE ;Move fields from EQ to QE
INTERN I$QESM ;Move fields from QE to CSM
INTERN I$SMEQ ;Move fields from CSM to EQ
INTERN I$RMCH ;Match a request and an RDB
INTERN I$DFEQ ;Default and check an EQ
INTERN I$LGFD ;BUILD A LOG FILE FD.
INTERN I$MUSR ;MOVE A USER ID TO AN RDB.
INTERN I$ONOD ;Default the batch ONOD limit word
INTERN I$CACV ;'CREATE' ACCT STRING VALIDATION
INTERN I$SACV ;'SCHEDULE' ACCT STRING VALIDATION
INTERN I$ACTV ;A NO-OP ON THE -20
INTERN I$DFMR ;FILL IN SYSTEM DEPENDENT DATA IN MDR
SUBTTL I$EQQE - Move fields from EQ to QE
;ROUTINE TO MOVE OPERATING SYSTEM DEPENDENT FIELDS FROM THE EXTERNAL
; QUEUE REQUEST (EQ) TO THE INTERNAL QUEUE ENTRY (QE).
;
;CALL:
; MOVE S1,<ADDRESS OF EQ>
; MOVE AP,<ADDRESS OF QE>
; PUSHJ P,I$EQQE
; ALWAYS RETURN HERE
I$EQQE: PUSHJ P,.SAVE1 ;SAVE P1
MOVE P1,S1 ;SAVE THE EQ ADDRESS
MOVSI S2,.EQOWN(P1) ;SETUP TO BLT THE OWNER'S NAME
HRRI S2,.QEOWN(AP) ;FORM EQ TO QE
BLT S2,.QEOWN+7(AP) ;ZAP!!
MOVSI S2,.EQCON(P1) ;POINT TO CONNCECTED DIRECTORY
HRRI S2,.QECON(AP) ;PLACE TO BLT TO
BLT S2,.QECON+11(AP) ;AND BLT IT
$RETT ;RETURN
SUBTTL I$QESM - Move fields from the QE to CSM
I$QESM: $RETT ;THIS IS A NO-OP ON THE -20
SUBTTL I$SMEQ - ROUTINE TO MOVE FIELDS FROM THE CSM TO EQ
;CALL:
; MOVE S1,<ADDRESS OF CSM>
; MOVE AP,<ADDRESS OF EQ>
; PUSHJ P,I$SMEQ
; ALWAYS RETURN HERE
I$SMEQ: LOAD S2,CSM.OI(S1) ;GET THE OWNER ID
STORE S2,.EQOID(AP) ;SAVE IT IN THE EQ
HRROI S1,.EQOWN(AP) ;POINT TO EQ
DIRST ;CONVERT TO STRING
$STOP(ODE,OWNER DOESNT EXIST)
$RETT ;AND RETURN
SUBTTL I$RMCH -- Match a request and an RDB
;ROUTINE TO DETERMINE WHETHER OR NOT A PARTICULAR QUEUE ENTRY MATCHES
; THE REQUEST DESCRIPTION IN A PARTICULAR REQUEST DESCRIPTION
; BLOCK (RDB)
;
;CALL:
; MOVE S1,<ADDRESS OF RDB>
; MOVE AP,<ADDRESS OF QE>
; PUSHJ P,I$RMCH
; ALWAYS RETURN HERE
I$RMCH: SKIPN S2,.RDBRQ(S1) ;IS THERE A JOB ID NUMBER ???
JRST RMCH.0 ;NO,,THEN CONTINUE ON.
CAME S2,[-1] ;IS IT ALL JOBS ???
CAMN S2,.QERID(AP) ; OR DO WE MATCH ???
$RETT ;YES,,THEN RETURN OK
$RETF ;ELSE RETURN NO GOOD !!
RMCH.0: PUSHJ P,.SAVE1 ;SAVE P1
SKIPN P1,.RDBES(S1) ;LOAD EXTERNAL SEQ #
JRST RMCH.1 ;ZERO ASSUME A MATCH
LOAD S2,.QESEQ(AP),QE.SEQ ;GET SEQUENCE NUMBER FROM THE QE
CAME S2,P1 ;DO THEY MATCH?
$RETF ;NO, STOP NOW
RMCH.1: LOAD S2,.QEJOB(AP) ;GET JOBNAME FROM QE
XOR S2,.RDBJB(S1) ;FIND WHATS DIFFERENT
AND S2,.RDBJM(S1) ;MASK OUT INSIGNIFICANT PARTS
JUMPN S2,.RETF ;AND RETURN IF NO MATCH
MOVEI P1,.RDBOW(S1) ;GET THE USER NAME ADDRESS
SKIPE 0(P1) ;IS THERE A USER NAME ???
JRST RMCH.2 ;YES,,CONTINUE
SKIPE G$QOPR## ;NOT THERE,,IS THIS AN OPERATOR REQUEST
$RETT ;YES,,THEN WE MATCH.
HRRO S1,P1 ;NO,,CONVERT THE
MOVE S2,G$SID## ;SENDERS ID TO HIS
DIRST ;ASCIZ USER NAME
ERJMP .RETF ;IF AN ERROR,,NO MATCH !!
RMCH.2: MOVE S2,P1 ;GET THE ADDRESS
HRLI S2,(POINT 7,0) ;AND MAKE A BYTE POINTER
MOVX S1,<POINT 7,.QEOWN(AP)> ;POINT TO REQUEST OID
PJRST STGWLD ;MATCH AND PROPAGATE TRUE OR FALSE
SUBTTL I$DFEQ -- Default and check the EQ
;ROUTINE TO DEFAULT AND CHECK THE OPERATING SYSTEM DEPENDENT VALUES
; IN THE EXTERNAL QUEUE REQUEST (EQ).
;
;CALL:
; MOVE S1,<ADDRESS OF EQ>
; PUSHJ P,I$DFEQ
; ALWAYS RETURN HERE WITH T/F INDICATION
I$DFEQ: PUSHJ P,.SAVET ;SAVE T REGS
MOVE T2,S1 ;COPY EQ ADR INTO T2
SETZB T3,T4 ;CLEAR SOME FLAGS
MOVE S1,[POINT 7,G$LOCN##] ;GET THE REQUESTS LOCATION
PUSHJ P,S%SIXB ;CONVERT IT TO SIXBIT
SKIPN .EQROB+.ROBND(T2) ;IS THE NODE SPECIFIED ???
MOVEM S2,.EQROB+.ROBND(T2) ;NO,,SAVE THIS AS THE DESTINATION NODE
SKIPE .EQOWN(T2) ;IS OWNER SET?
JRST DFEQ.0 ;YES, CONTINUE
SETOM T3 ;FLAG DEFAULT ON .EQOWN
HRROI S1,.EQOWN(T2) ;NO, POINT TO LOCATION
LOAD S2,G$SID## ;GET DEFAULT
STORE S2,.EQOID(T2) ;SAVE THE USER ID IN THE EQ
DIRST ;AND GET DEFAULT ONWER STRING
ERJMP E$CDU## ;RETURN THROUGH CANT DEFAULT USER ERROR
DFEQ.0: SKIPE .EQCON(T2) ;IS CON DIR SET?
JRST DFEQ.1 ;YES, DONT DEFAULT IT
SETOM T4 ;FLAG DEFAULTED .EQCON
HRROI S1,.EQCON(T2) ;POINT TO BLOCK
LOAD S2,G$CDI## ;GET THE DEFAULT
DIRST ;GET THE CONNECTED DIRECTORY
ERJMP E$CDD## ;RETURN THROUGH CANT DEFAULT DIRECTORY
DFEQ.1: JUMPL T3,DFEQ.2 ;DON'T CHECK IF EQOWN WAS DEFAULT
MOVX S1,RC%EMO ;EXACT MATCH ONLY
HRROI S2,.EQOWN(T2) ;POINT TO THE OWNER BLOCK
RCUSR ;GET THE NUMBER
ERJMP .RETF ;IF IT FAILS,,TRASH THE REQUEST
TXNE S1,RC%NOM ;NO MATCH?
$RETF ;YES, NO MATCH
STORE T1,.EQOID(T2) ;SAVE THE USER ID IN THE EQ.
CAMN T1,G$SID## ;MATCH, IS IT OK?
JRST DFEQ.2 ;YES,,CONTINUE ON..
PUSHJ P,I$WHEEL ;NO, WIN ONLY IF HE'S A WHEEL
JUMPF .RETF ;NOT A WHEEL,,TOUGH BREAKEEE
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
DFEQ.2: JUMPL T4,DFEQ.3 ;IF CON DIR WAS DEFAULTED,,CHECK JOBNAME
MOVX S1,RC%EMO ;EXACT MATCH ONLY
HRROI S2,.EQCON(T2) ;NOW CHECK CONNECTED
RCDIR ;CHECK IT
ERJMP E$ICD## ;IF IT FAILS,,TRASH THE REQUEST
TXNE S1,RC%NOM ;MATCH?
PJRST E$ICD## ;NO, LOSE
CAMN T1,G$CDI## ;IS IT OK?
JRST DFEQ.3 ;YES,,CONTINUE ON..
PUSHJ P,I$WHEEL ;NO,,WIN ONLY IF HE IS A WHEEL
JUMPF E$ICD## ;NOT A WHEEL,,LETS LEAVE.
DFEQ.3: LDB S1,[POINT 7,.EQACT(T2),6] ;GET THE FIRST BYTE OF THE ACCT STRING
JUMPN S1,DFEQ.5 ;IF THERE IS ONE THERE,,VERIFY IT.
MOVE S1,G$ACCT## ;GET THE SENDERS ACCOUNT STR ADDRESS.
HRLI S1,(POINT 7,0) ;MAKE IT A BYTE POINTER.
MOVE S2,[POINT 7,.EQACT(T2)] ;THIS IS WHERE WE WANT IT TO GO.
DFEQ.4: ILDB T1,S1 ;COPY THE ACCOUNT STRING
IDPB T1,S2 ; TO THE EQ ENTRY.
JUMPN T1,DFEQ.4 ;END ON A NULL,,ELSE CONTINUE.
JRST DFEQ.6 ;SKIP OVER THE ACCOUNT VALIDATION
DFEQ.5: MOVE S1,T2 ;GET THE EQ ADDRESS
PUSHJ P,I$CACV ;GO VALIDATE THE ACCOUNT STRING
JUMPF E$IAS## ;NO GOOD,,RETURN WITH AN ERROR
DFEQ.6: SKIPE .EQJOB(T2) ;IS THERE A JOB NAME ???
$RETT ;YES,,DONT DEFAULT IT.
LOAD T1,.EQLEN(T2),EQ.LOH ;GET THE HEADER LENGTH
ADD T1,T2 ;POINT TO THE FIRST FP
LOAD S1,.FPLEN(T1),FP.LEN ;GET THE FP LENGTH
ADDI T1,.FDFIL(S1) ;POINT TO THE FIRST FILE-SPEC
HRLI T1,(POINT 7,0) ;MAKE IT A BYTE POINTER
MOVSI T3,76 ;STOP AT THE '>'
SETZ T4, ;DONT STORE ANY DATA
PUSHJ P,FBREAK ;STRIP THE FILE-SPEC UP TO THE FILENAME
SKIPN S1 ;ANYTHING THERE ???
PJRST E$IFS## ;MUST BE AN INVALID FILESPEC
MOVEI T4,6 ;COUNT 6 BYTES
MOVE S2,[POINT 6,.EQJOB(T2)] ;GET OUTPUT BYTE POINTER
SKIPA T3,[0] ;SKIP THE FIRST TIME THROUGH
DFEQ.7: SETOM T3 ;INDICATE A ^V WAS READ
DFEQ.8: ILDB S1,T1 ;GET A FILESPEC BYTE
CAIN S1,26 ;IS IT ^V ???
JRST DFEQ.7 ;YES,,IGNORE IT AND SET FLAG
CAILE S1," " ;LESS OR EQUAL TO A BLANK ???
CAILE S1,"z" ; OR GREATER THEN "z"
MOVEI S1,"?" ;YES,,MAKE IT A "?"
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
CAIL S1,"a" ;IF ITS LOWER CASE THEN
SUBI S1,40 ; MAKE IT UPPER CASE
SUBI S1,40 ;CONVERT IT TO SIXBIT
CAIN S1,'.' ;END ON A PERIOD (UNLESS ^V)
JUMPE T3,.RETT ;NO ^V,,THEN WE ARE DONE
CAIN S1,'-' ;ALSO CHECK FOR A '-' AS THE
CAIE T4,1 ; LAST CHARACTER IN THE JOB NAME
SKIPA ;HERE,,HE IS OK...
$RETT ;HERE,,DONT SAVE THE '-', JUST RETURN
IDPB S1,S2 ;SAVE IT
SETZM T3 ;CLEAR ^V FLAG
SOJG T4,DFEQ.8 ;CONTINUE FOR 6 BYTES
$RETT ;AND RETURN
SUBTTL I$LGFD - ROUTINE TO BUILD A LOG FILE FD.
;I$LGFD IS CALLED BY THE INPUT QUEUE DEFAULT FILLER TO GENERATE AN FD
; FOR A LOG FILE ON A JOB WHERE NO LOG FILE IS GIVEN.
;CALL: S1/ ADDRESS OF THE LOCATION TO START BUILDING THE FD.
; S2/ THE FP ADDRESS
; M/ THE EQ ADDRESS
;T RET: ALWAYS
I$LGFD: MOVE S2,.FPINF(S2) ;GET THE FP FLAG WORD FOR THIS FILE
TXNN S2,FP.SPL ;IS IT SUPPOSED TO BE 'SPOOLED' ???
JRST LGFD.1 ;NO,,CREATE A USER LOG FILESPEC
$TEXT (<-1,,.FDSTG(S1)>,<^T/SPOOL/^O/.EQITN(M)/.LOG>^0)
MOVEI S2,13 ;GET THE FD LENGTH.
STORE S2,.FDLEN(S1),FD.LEN ;AND SET IT
$RETT ;RETURN.
;HERE IF WE HAVE TO DEFAULT THE LOG FILE SPEC FOR THE USER
LGFD.1: PUSHJ P,.SAVET ;SAVE THE 'T' AC'S
MOVE T4,S1 ;SAVE THE FD ADDRESS FOR A MINUTE
HRROI S1,.FDSTG(S1) ;POINT TO WHERE WE WANT THE CONNECTED
MOVE S2,G$CDI## ; DIRECTORY PUT
DIRST ;GEN THE CONNECTED DIRECTORY
ERJMP E$IFS## ;ON AN ERROR,,'INVALID FILE SPEC'
PUSH P,S1 ;SAVE THE UPDATED BYTE POINTER
LOAD S1,.EQLEN(M),EQ.LOH ;GET THE HEADER LENGTH
ADD S1,M ;POINT TO THE FIRST FP
LOAD S2,.FPLEN(S1),FP.LEN ;GET THE FP LENGTH
ADD S1,S2 ;POINT TO THE FIRST FD
HRROI S2,.FDSTG(S1) ;POINT TO THE ACTUAL FILE-SPEC
MOVX S1,GJ%SHT+GJ%OFG ;SHORT + PARSE ONLY JFN
GTJFN ;GET A JFN
JRST E$IFS## ;ON AN ERROR,,'INVALID FILE SPEC'
MOVE S2,S1 ;GET THE JFN IN S2
POP P,S1 ;GET THE DESTINATION POINTER
MOVX T1,JS%NAM ;WANT FILE NAME ONLY
SETZM T2 ;NO ADDITION POINTERS
JFNS ;GET THE FILENAME
EXCH S1,S2 ;GET JFN IN S1,,UPDATED PTR IN S2
RLJFN ;RELEASE THE JFN
JFCL ;IGNORE THE ERROR
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
MOVE S1,[POINT 7,LOG] ;GET THE .LOG EXTENSION BYTE POINTER
LGFD.2: ILDB T1,S1 ;GET A BYTE
IDPB T1,S2 ;SAVE IT
SKIPE T1 ;END ON THE NULL
JRST LGFD.2 ;ELSE CONTINUE
HRRZS S2 ;GET END FILESPEC ADDRESS ONLY
SUBI S2,-1(T4) ;GET FD LENGTH
STORE S2,.FDLEN(T4),FD.LEN ;SAVE IT
$RETT ;AND RETURN
LOG: ASCIZ/.LOG/
SPOOL: ASCIZ/PS:<SPOOL>BATCH-/
SUBTTL I$MUSR - MOVE AN RDB OWNER ID TO AN RDB BLOCK.
;ROUTINE TO MOVE AN RDB OWNER ID INTO AN RDB BLOCK FOR A
; HOLD/RELEASE MESSAGE.
;CALL:
; MOVE S1,OWNER ID ADDRESS.
; MOVEI S2,OUTPUT RDB ADDRESS
; PUSHJ P,I$MUSR##
; ALWAYS RETURN HERE
;
I$MUSR: PUSHJ P,.SAVE1 ;SAVE P1 FOR A MINUTE
MOVE P1,S2 ;SAVE THE OUTPUT RDB ADDRESS
SKIPN S1 ;CHECK IF THERE IS ONE.
JRST MUSR.2 ;NONE THERE,,SET TO 0 AND RETURN.
MOVE S2,0(S1) ;GET THE 36 BIT USER ID.
HRROI S1,.RDBOW(P1) ;THIS IS WHERE WE WANT IT.
DIRST ;TRANSLATE IT.
ERJMP MUSR.1 ;ON ERROR,,TOUGH BREAKEEE
$RETT ;ELSE RETURN OK.
MUSR.1: SETOM .RDBOW(P1) ;MAKE IT SO IT NEVER WORKS.
$RETT ;AND RETURN.
MUSR.2: SETZM .RDBOW(P1) ;CLEAR THE FIRST WORD OF THE RDB OWNER
$RETT ;AND RETURN
SUBTTL I$ONOD - ROUTINE TO DEFAULT THE BATCH ONOD LIMIT WORD
;CALL: M/ The EQ address
;
;RET: TRUE ALWAYS
I$ONOD: MOVE S1,[POINT 7,G$LOCN##] ;GET THE USERS LOCATION
PUSHJ P,S%SIXB ;CONVERT IT TO SIXBIT
STOLIM S2,.EQLIM(M),ONOD ;DEFAULT THE OUTPUT NODE NAME
$RETT ;AND RETURN
SUBTTL I$CACV - ROUTINE TO VALIDATE THE ACCOUNT STRING FOR 'CREATE'
;CALL: S1/EQ ADDRESS
;
;RET: TRUE IF VALID
; FALSE IF NOT
I$CACV: SKIPN G$ACTV## ;ARE WE VALIDATING AT ALL ???
$RETT ;NO,,JUST RETURN
MOVE S2,S1 ;PUT EQ ADDRESS INTO S2
LOAD S1,.EQOID(S2) ;GET THE USER NUMBER.
HRROI S2,.EQACT(S2) ;POINT TO THE USERS ACCOUNT STRING
VACCT ;VERIFY THE ACCOUNT STRING FOR THE USER.
ERJMP .RETF ;NO GOOD,,RETURN NOW.
$RETT ;OK,,RETURN SAYING SO.
SUBTTL I$SACV - ROUTINE TO VALIDATE ACCT STRINGS FOR 'SCHEDULING'
;CALL: S1/ EQ ADDRESS
; AP/ QE ADDRESS
;
;RET: TRUE IF ACCT OK
; IF ACCT INVALID. IF THE ACCT IS INVALID,
; THE EQ.IAS BIT IS LIT SO THAT THE SPOOLER CAN KILL IT
I$SACV: PUSHJ P,I$CACV ;GO VALIDATE THE ACCOUNT STRING
MOVX S2,QE.IAS ;GET THE INVALID ACCOUNT STRING BIT
SKIPT ;IS THE ACCOUNT STRING VALID ??.
IORM S2,.QESEQ(AP) ;NO,,LIGHT IAS BIT.
$RETT ;AND RETURN
SUBTTL I$ACTV - A NO-OP ON THE -20
I$ACTV: $RETT ;JUST RETURN
SUBTTL I$DFMR - ROUTINE TO FILL IN SYSTEM DEPENDENT DATA INTO MDR
;CALL: S1/ The MDR Address
; M / The Mount Message Address
;
;RET: True Always
I$DFMR: PUSHJ P,.SAVE1 ;SAVE P1 FOR A MINUTE
MOVE P1,S1 ;GET THE MDR ADDRESS IN P1
HRROI S1,.MRNAM(P1) ;POINT TO THE DESTINATION AREA
MOVE S2,.MRUSR(P1) ;GET THE USERS NUMBER
DIRST ;CONVERT NUMBER TO NAME
JFCL ;IGNORE THE ERROR
MOVE S1,G$ACCT## ;GET THE ACCOUNT STRING ADDRESS
HRLI S1,(POINT 7,0) ;CONVERT TO A BYTE POINTER
MOVEI S2,.MRACT(P1) ;GET THE DESTINATION ADDRESS
HRLI S2,(POINT 7,0) ;CONVERT TO A BYTE POINTER
DFMR.1: ILDB P1,S1 ;GET A BYTE
IDPB P1,S2 ;SAVE IT
JUMPN P1,DFMR.1 ;CONTINUE TILL ASCIZ
$RETT ;AND RETURN
SUBTTL Batch Stream Unique Directory Routines
INTERN I$UQST ;SET DIRECTORY FOR A STREAM
INTERN I$UQCL ;CLEAR DIRECTORY FOR A STREAM
INTERN I$UQCH ;COMPARE STREAM FOR UNIQNESS
SUBTTL I$UQST -- Set Directory for a Stream
;ROUTINE TO SET THE DIRECTORY FOR A STREAM FROM THE BATCH QUEUE ENTRY
;
;CALL:
; MOVEI S1,<STREAM NUMBER>
; MOVE AP,<BATCH QUEUE ENTRY (QE)>
; PUSHJ P,I$UQST
; ALWAYS RETURN HERE
I$UQST: PUSH P,S1 ;SAVE STREAM NUMBER
MOVE S1,UNILST ;GET LIST NAME
MOVEI S2,^D12 ;AND ENTRY SIZE
PUSHJ P,L%CENT ;CREATE AN ENTRY
POP P,0(S2) ;PUT STREAM NUMBER IN 1ST WORD
GETLIM S1,.QELIM(AP),UNIQ ;GET UNIQUE SETTING
STORE S1,1(S2) ;SAVE IT
HRLI S1,.QECON(AP) ;GET SOURCE ADDRESS
HRRI S1,2(S2) ;AND DESTINATION
BLT S1,^D11(S2) ;STORE THE DIRECTORY
$RETT ;AND RETURN
SUBTTL I$UQCL -- Clear the directory for a stream
;ROUTINE TO CLEAR OUT THE DIRECTORY FOR A STREAM
;
;CALL:
; MOVEI S1,<STREAM NUMBER>
; PUSHJ P,I$UQCL
; ALWAYS RETURN HERE
I$UQCL: PUSHJ P,UNIFST ;FIND THE STREAM ENTRY
MOVE S2,S1 ;PUT IT INTO S2.
MOVE S1,UNILST ;GET THE LIST NUMBER.
PUSHJ P,L%DENT ;DESTROY ENTRY
$RETT ;AND RETURN
SUBTTL I$UQCH -- Check for directory match
;Routine to determine whether a job meets all necessary UNIQNESS criteria
; to be scheduled.
;
;CALL: AP/ BATCH QUEUE ENTRY
;
;T RET: IF JOB CAN BE SCHEDULED
;F RET: IF JOB CANNOT BE SCHEDULED
I$UQCH: PUSHJ P,.SAVE1 ;SAVE P1
MOVE S1,UNILST ;GET LIST NAME
PUSHJ P,L%FIRST ;POSITION TO THE BEGINNING
JUMPF .RETT ;EMPTY LIST WINS!!
UQCH.1: HRLI S2,-12 ;MAKE IT AN AOBJN POINTER ALSO
ADDI S2,2 ;AND POINT TO FIRST DIRECTORY WORD
MOVEI S1,.QECON(AP) ;POINT TO FIRST WORD IN QE
UQCH.2: MOVE P1,0(S2) ;GET A WORD
CAME P1,0(S1) ;COMPARE
JRST UQCH.3 ;NO MATCH, NEXT ENTRY
ADDI S1,1 ;BUMP S1
AOBJN S2,UQCH.2 ;LOOP
MOVE S1,UNILST ;GET LIST NAME
PUSHJ P,L%CURRENT ;GET ADDRESS OF CURRENT ENTRY AGAIN
MOVE S2,1(S2) ;GET UNIQNESS OF ENTRY
GETLIM S1,.QELIM(AP),UNIQ ;GET UNIQNESS OF NEW REQUEST
CAIE S1,%EQUYE ;IF EITHER ONE IS UNIQUE,
CAIN S2,%EQUYE ; THEN THE NEW ONE IS NO GOOD
$RETF ;GOTCHA!!
UQCH.3: MOVE S1,UNILST ;GET LIST NAME
PUSHJ P,L%NEXT ;POSITION TO NEXT
JUMPT UQCH.1 ;AND LOOP
$RETT ;NO MORE, RETURN SUCCESS
SUBTTL UNIFST - Find stream's unique entry
;UNIFST is called by the 'clear' and 'compare' routines to find the
; list entry associated with a particular stream number.
; Upon return the list entry is CURRENT.
;CALL: S1/ STREAM NUMBER
;
;T RET S1/ ADDRESS OF UNIQUE ENTRY FOR STREAM
UNIFST: PUSHJ P,.SAVE1 ;SAVE P1
MOVE P1,S1 ;COPY STREAM NUMBER OVER
MOVE S1,UNILST ;GET LIST NUMBER
PUSHJ P,L%FIRST ;POSITION IT
JUMPF S..USM ;LOSE BIG
UNIF.1: CAMN P1,0(S2) ;MATCH?
JRST [MOVE S1,S2
$RETT] ;YES, RETURN
PUSHJ P,L%NEXT ;POSITION TO NEXT
JUMPT UNIF.1 ;AND LOOP
$STOP(USM,Unique stream missing)
SUBTTL Failsoft System Interface
;ENTRY POINTS
INTERN I$WRIT ;WRITE SOMETHING INTO THE MASTER
INTERN I$READ ;READ SOMETHING FROM THE MASTER
INTERN I$CRIP ;CREATE AN INDEX PAGE
INTERN I$OQUE ;OPEN MASTER QUEUE FILES
SUBTTL I$WRIT -- Write something into master queue file
;ROUTINE TO WRITE SOMETHING INTO THE MASTER QUEUE FILES. CALL WITH S1
; CONTAINING THE BLOCK NUMBER TO WRITE, AND S2 CONTAINING AN
; IO-POINTER OF THE FORM:
;
; XWD LENGTH,ADDRESS
;
; WHERE 'LENGTH' IS THE NUMBER OF WORDS TO WRITE, AND 'ADDRESS'
; IS THE PLACE TO START WRITING FROM.
I$WRIT: PUSHJ P,.SAVET ;SAVE T1-T4
MOVE T1,S1 ;GET BLOCK NUMBER
IDIVI T1,FSSBPS ;DIVIDE BY BLOCKS/SECTION
CAIN T2,FSSFIB ;IS IT AN INDEX BLOCK?
JRST WRIT.1 ;YES, DO SOMETHING SPECIAL
DMOVEM S1,WRIT.A ;STORE INPUT ARGUMENTS
HRR T3,FSADDR ;ADDRESS OF SCRATCH PAGE
HRL T3,WRIT.A+1 ;GET SOURCE,,DEST IN T3
HLRZ T4,WRIT.A+1 ;GET LENGTH OF DATA
ADDI T4,-1(T3) ;ADD IN BASE ADR-1
BLT T3,(T4) ;AND BLT THE DATA
MOVE S1,FSPAGN ;GET 0,,SOURCE-PAGE
HRLI S1,.FHSLF ;<FORK-HANDLE>,,<SOURCE-PAGE>
MOVE S2,WRIT.A ;GET 0,,<DEST-PAGE>
HRL S2,FILJFN ;GET <JFN>,,<DEST-PAGE>
MOVX T1,PM%RD!PM%WT ;READ AND WRITE ACCESS
PMAP ;AND MAP THE PAGE OUT
HRL S1,FILJFN ;GET <JFN>,,0
HRR S1,WRIT.A ;GET <JFN>,,<FILE-PAGE>
MOVEI S2,1 ;AND A REPEAT COUNT
UFPGS ;UPDATE THE DISK
$STOP(CUF,CANT UPDATE FILE)
MOVE T1,WRIT.A ;GET FILE PAGE NUMBER
CAMG T1,G$NBW## ;HIGHEST PAGE YET
$RETT ;NO, RE-USING SAME SPACE
MOVEM T1,G$NBW## ;YES, SAVE NEW FILE SIZE
MOVSI S1,.FBUSW ;FILL IN USER-SPECIFIED-WORD
HRR S1,FILJFN ;FOR MASTER FILE
SETO S2, ;FILL ENTIRE WORD WITH T1
CHFDB ;CHANGE THE FILE BLOCK
$RETT ;AND RETURN
;HERE IF WRITING AN INDEX PAGE
WRIT.1: HRL S1,FILJFN ;GET <JFN>,,<PAGE-NUMBER>
MOVEI S2,1 ;AND A REPEAT COUNT
UFPGS ;AND UPDATE THE INDEX
$STOP(CUI,CANT UPDATE INDEX)
$RETT ;AND RETURN
WRIT.A: BLOCK 2 ;INPUT ARGUMENTS
SUBTTL I$READ -- Read something from master queue file
;ROUTINE TO READ SOMETHING FROM THE MASTER QUEUE FILE. CALL WITH S1
; CONTAINING A BLOCK TO START THE READ AT AND S2 CONTAINING AN
; IO-POINTER OF THE FORM:
;
; XWD LENGTH,ADDRESS
;
; WHERE 'LENGTH' IS THE NUMBER OF WORDS TO READ, AND 'ADDRESS'
; IS THE PLACE TO START READING THEM INTO.
I$READ: PUSHJ P,.SAVET ;SAVE T1-T4
MOVE T1,S1 ;GET BLOCK NUMBER
IDIVI T1,FSSBPS ;DIVIDE BY BLOCKS/SECTION
CAIN T2,FSSFIB ;IS IT AN INDEX BLOCK?
JRST READ.1 ;YES, GO MAP IT IN
DMOVE T1,S1 ;COPY ARGS FROM S TO T
MOVE S1,T1 ;GET 0,,<SOURCE-PAGE>
HRL S1,FILJFN ;GET <JFN>,,<SOURCE-PAGE>
MOVE S2,FSPAGN ;GET 0,,<DEST-PAGE>
HRLI S2,.FHSLF ;<FORK-HANDLE>,,<DEST-PAGE>
MOVX T1,PM%RD ;AND READ ACCESS
PMAP ;AND MAP IN THE PAGE
HRL T1,FSADDR ;GET <SOURCE-ADR>,,0
HRR T1,T2 ;GET <SOURCE-ADR>,,<DEST-ADR>
HLRZ T3,T2 ;GET LENGTH OF DATA
ADDI T3,-1(T2) ;ADD IN BASE ADR -1
BLT T1,(T3) ;AND BLT TO REQUESTORS PAGE
SETO S1, ;NOW SETUP TO RELEASE THE
HRRZ S2,FSPAGN ; MAPPED SCRATCH PAGE FROM
HRLI S2,.FHSLF ; OUR ADDRESS SPACE
SETZ T1, ;FLAGS ARE MEANINGLESS
PMAP ;DO IT!!
$RETT ;AND RETURN
;HERE TO MAP IN AN INDEX PAGE
READ.1: HRL S1,FILJFN ;GET JFN,,SOURCE-PAGE
TLZ S2,-1 ;GET 0,,<DEST-ADR>
ADR2PG S2 ;GET 0,,<DEST-PAGE>
HRLI S2,.FHSLF ;<FORK-HANDLE>,,<DEST-PAGE>
MOVX T1,PM%RWX ;READ/WRITE/EXECUTE
PMAP ;MAP IT!
$RETT ;AND RETURN
SUBTTL I$CRIP -- Create an index page in master file
;I$CRIP IS CALLED WHEN THE FAILSOFT SYSTEM DECIDES TO START A NEW FILE
; SECTION (INCLUDING THE VERY FIRST) TO WRITE OUT THE NEW INDEX
; PAGE INTO THE FILE. CALL WITH S1 CONTAINING THE BLOCK NUMBER OF
; THE PAGE, AND S2 CONTAINING THE ADDRESS OF THE PAGE.
I$CRIP: HRLI S2,FSSWPI ;NUMBER OF WORDS TO WRITE
PUSHJ P,.SAVET ;SAVE T REGS
DMOVE T3,S1 ;SAVE ARGS IN T3 AND T4
HRRZ S1,S2 ;GET 0,,<SOURCE-ADR>
ADR2PG S1 ;GET 0,,<SOURCE-PAGE>
HRLI S1,.FHSLF ;GET <FHANDLE>,,<SOURCE-PAGE>
HRRZ S2,T3 ;GET 0,,<DEST-PAGE>
HRL S2,FILJFN ;GET <JFN>,,<DEST-PAGE>
MOVX T1,PM%WR ;WRITE ACCESS REQUIRED
PMAP ;MAP THE PAGE OUT
DMOVE S1,T3 ;RECOVER THE ARGS
PUSHJ P,I$READ ;MAP THE PAGE IN
DMOVE S1,T3 ;RECOVER THE ARGS AGAIN
PJRST I$WRIT ;UPDATE THE WORLD AND RETURN
SUBTTL I$OQUE -- Open master queue files
;ROUTINE CALLED DURING FAILSOFT SYSTEM INITIALIZATION TO OPEN
; THE MASTER QUEUE FILE.
I$OQUE: ZERO OQUE.A ;FIRST TIME THRU
OQUE.1: MOVX S1,<GJ%SHT!GJ%OLD!GJ%NS> ;DO A SHORT GTJFN, OLD FILE ONLY,NO SEARCH
SKIPE DEBUGW ;ARE WE DEBUGGING?
SKIPA S2,[-1,,[DMQFNM]] ;YES, USE PRIVATE MASTER QUEUE FILE
HRROI S2,[MQFNAM] ;POINT TO MASTER QUEUE NAME
GTJFN ;GO GET IT
JRST OQUE.2 ;NOT THERE, CREATE IT
HRRZM S1,FILJFN ;SAVE THE JFN
HRRZS S1 ;AND ZERO THE LEFT HALF OUT
PUSH P,T1 ;SAVE T1
MOVX S2,<1,,.FBUSW> ;READ USER SUPPLIED ARGUMENT
MOVEI T1,OQUE.B ;INTO LOCAL STORAGE
GTFDB ;READ FILE BLOCK INFORMATION
MOVE T1,OQUE.B ;WE FILL IN HIGHEST PAGE NUMBER
MOVEM T1,G$NBW## ;SAVE THE FILE SIZE
POP P,T1 ;AND RESTORE T1
MOVE S1,FILJFN ;GET THE JFN
MOVX S2,<OF%RD+OF%WR+OF%NWT> ;GET OPENF BITS
OPENF ;OPEN THE FILE
PUSHJ P,OQUE.4 ;LOSE!!
PUSHJ P,M%ACQP ;GET A PAGE FOR I$READ/I$WRITE
MOVEM S1,FSPAGN ;FOR THEIR SCRATCH USE
PG2ADR S1 ;CONVERT TO ADDRESS ALSO
MOVEM S1,FSADDR ;FOR EASIER USE
$RETT ;AND RETURN
OQUE.2: SKIPE OQUE.A ;FIRST TIME THRU?
PUSHJ P,OQUE.3 ;NO, GIVE A STOPCD
MOVX S1,<GJ%NEW!GJ%SHT!GJ%FOU> ;NEW FILE, OUTPUT, SHORT GTJFN
SKIPE DEBUGW ;ARE WE DEBUGGING?
SKIPA S2,[-1,,[DMQFNM]] ;YES, USE PRIVATE MASTER QUEUE FILE
HRROI S2,[MQFNAM] ;POINT TO MASTER QUEUE NAME
GTJFN ;GET IT
PUSHJ P,OQUE.3 ;LOSE?
MOVX S2,OF%WR ;WRITE
HRRZS S1 ;CLEAR LH
PUSH P,S1 ;AND SAVE JFN
OPENF ;OPEN THE FILE
PUSHJ P,OQUE.3 ;CAN'T?
POP P,S1 ;RESTORE THE JFN
CLOSF ;CLOSE THE FILE
JFCL ;REALLY SHOULDN'T HAPPEN
SETOM OQUE.A ;WE'VE BEEN HERE ONCE ALREADY
JRST OQUE.1 ;AND TRY AGAIN
OQUE.3: $STOP(COP,Cannot Open Prime Queue)
OQUE.4: CAIE S1,OPNX9 ;IS IT ILLEGAL SIMUL ACCESS?
JRST OQUE.3 ;NO
$STOP(PQI,Prime Queue is Interlocked)
OQUE.A: BLOCK 1 ;LOCAL STORAGE
OQUE.B: BLOCK 1 ;LOCAL STORAGE
SUBTTL FBREAK -- Find a break character
;FBREAK IS USED TO SEPARATE PIECES OUT OF CHARACTER STRINGS. IT WILL
;ALSO DO A FIXED OFFSET CONVERSION OF THE CHARACTERS
;IT IS CALLED WITH:
; T1 = BYTE POINTER TO SOURCE STRING
; T2 = BYTE POINTER TO DESTINATION STRING
; T3 = CHARACTER TO STOP ON,,CONVERSION OFFSET (SUBTRACTED FROM SOURCE CHARACTER
; T4 = COUNT OF CHARACTERS TO STORE (OTHERS TO BREAK ARE SKIPPED)
;IT RETURNS:
; T1 = BYTE POINTER TO FIRST CHARACTER AFTER BREAK IN SOURCE
; S1 = TERMINATION CHARACTER (EITHER BREAK AS SPECIFIED IN T3 OR NULL
; S2,T2-T3 UNDEFINED
FBREAK: HLRZ S2,T3 ;GET CHARACTER TO STOP ON
HRRES T3 ;AND MAKE T3 CONVERSION OFFSET
FBRE.1: ILDB S1,T1 ;GET A CHARACTER FROM THE SOURCE
JUMPE S1,.RETT ;ALWAYS STOP ON NULL
CAMN S1,S2 ;IS IT THE BREAK CHARACTER
POPJ P, ;YES, RETURN
SUB S1,T3 ;DO THE CONVERSION
SOSL T4 ;DECREMENT NUMBER OF CHARACTERS TO STORE
IDPB S1,T2 ;STORE IT
JRST FBRE.1 ;AND LOOP BACK FOR MORE
SUBTTL STGWLD -- Match a "wild" string
;STGWLD IS CALLED WITH S1 CONTAINING A POINTER TO A "BASE" STRING
; LIKE A JOBNAME OR FILENAME AND S2 CONTAINING A POINTER TO
; A STRING WITH POSSIBLE WILDCARD CHARACTERS * AND % IN IT.
; IT THE BASE STRING MATCHES THE WILD STRING, TRUE IS RETURNED
; OTHERWISE FALSE.
STGWLD: PUSHJ P,.SAVET ;SAVE T REGS
STGW.1: ZERO T1 ;CLEAR * FLAG
STGW.2: ILDB T4,S2 ;GET A CHARACTER FROM "WILD"
STGW.3: CAIL T4,"A"+40 ;CHECK FOR LOWER CASE
CAILE T4,"Z"+40 ; "
SKIPA ;ITS NOT LC
SUBI T4,40 ;IT IS, MAKE IT UPPER CASE
STGW.4: ILDB T3,S1 ;GET A CHARACTER FROM "BASE"
CAIL T3,"A"+40 ;CHECK IT FOR LOWER CASE
CAILE T3,"Z"+40
SKIPA ;ITS NOT LOWER
SUBI T3,40 ;IT IS, MAKE IT UC
CAME T3,T4 ;MATCH?
JRST STGW.5 ;NO, THAT WOULD BE TOO SIMPLE
JUMPE T3,.RETT ;YES, RETURN IF END OF STRINGS
JRST STGW.1 ;ELSE JUST LOOP
STGW.5: CAIN T4,"*" ;IS "WILD" A *?
JUMPE T3,.RETT ;YES, WIN IF END OF STRING
JUMPN T1,STGW.4 ;IF LAST "WILD" WAS *, KEEP GOING
JUMPE T3,.RETF ;IF NOT END-OF-STRING DOES NOT MATCH
CAIN T4,"%" ;IS "WILD" A %
JRST STGW.7 ;YES, MATCH AND GO AROUND AGAIN
CAIE T4,"*" ;NO, IS IT A *
$RETF ;NO, LOSE
STGW.6: AOSA T1 ;YES, SET * FLAG
STGW.7: ZERO T1 ;CLEAR * FLAG
STGW.8: ILDB T4,S2 ;GET NEXT "WILD" CHARACTER
CAIN T4,"*" ;IS IT A *?
JRST STGW.6 ;YES, "**"="*"
CAIE T4,"%" ;NO, A % ?
JRST STGW.3 ;NO, PLAIN OLD ALPHANUMERIC
JRST STGW.8 ;YES, "*%" = "*"
SUBTTL I$MINI - ROUTINE TO INITIALIZE THE TAPE MOUNT PROCESSOR
INTERN I$MINI ;MAKE INITIALIZATION GLOBAL
MNTPDB: IP%CFV ;MSG PDB - PAGE MODE
0,,0 ; - SENDERS PID
0,,0 ; - RECEIVERS PID
1000,,0 ; - LENGTH,,PAGE #
I$MINI: MOVE S1,MDRQUE## ;GET THE MDR QUEUE LIST ID
PUSHJ P,L%FIRST ;GET THE FIRST MDR ENTRY
JUMPF MINI.0 ;NONE THERE,,JUST CONTINUE
MINI.A: MOVE AP,S2 ;SAVE THE MDR ADDRESS IN AP
PUSHJ P,D$DMDR## ;DELETE THE MDR ET AL
MOVE S1,MDRQUE## ;GET THE MDR QUEUE ID
PUSHJ P,L%NEXT ;GET THE NEXT MDR ENTRY
JUMPT MINI.A ;CONTINUE THROUGH ALL MDR'S
MINI.0: LOAD AP,HDRPSB##+.QHLNK,QH.PTF ;GET THE FIRST PSB
MOVEI H,HDRPSB## ;SETUP THE HEADER
SKIPA ;SKIP THE FIRST TIME THROUGH
MINI.1: LOAD AP,.QELNK(AP),QE.PTN ;GET THE NEXT PSB ADDRESS
MINI.2: JUMPE AP,.RETT ;NO MORE,,RETURN
LOAD S1,PSBOBJ(AP) ;GET THE FIRST OBJECT TYPE
CAIE S1,.OTMNT ;IS IT A MOUNT PSB ???
JRST MINI.1 ;NO,,TRY THE NEXT ONE
LOAD S1,.QELNK(AP),QE.PTN ;GET THE NEXT PSB ADDRESS NOW
PUSH P,S1 ; SINCE WE ARE DELETING THIS ENTRY
PUSHJ P,M$RFRE## ;DE-LINK/DELETE THIS PSB
POP P,AP ;RESTORE NEXT PSB ADDRESS
JRST MINI.2 ;AND CONTINUE
SUBTTL I$MNTR - ROUTINE TO PROCESS USER MOUNT REQUESTS
INTERN I$MNTR
;CALL: AP/ The MDR Entry Address
; M/ The Mount Message Address
;
;RET: TRUE RETURN or ERRORS:IMM, MPN, DRN
I$MNTR: PUSHJ P,.SAVE1 ;SAVE P1 FOR A MINUTE
PUSHJ P,FNDPSB ;GO FIND A MTCON PSB
JUMPF E$MPN## ;NOT THERE,,THATS AN ERROR
MOVE S1,PSBPID(S1) ;GET THE PROCESSORS PID
MOVEM S1,MNTPDB+.IPCFR ;SAVE IT IN THE PDB
PUSHJ P,M%ACQP ;GO GET A PAGE WE CAN USE FOR IPCF
HRRM S1,MNTPDB+.IPCFP ;SAVE THE PAGE NUMBER IN THE PDB
PG2ADR S1 ;CONVERT THE PAGE TO AN ADDRESS
MOVE P1,S1 ;SAVE THE ADDRESS
LOAD S1,.MRRID(AP),MR.RID ;GET THE REQUEST ID
MOVEM S1,.MMITN(P1) ;SAVE IT IN THE MESSAGE ALSO
MOVE S1,.MRUSR(AP) ;GET THE USER NUMBER
MOVEM S1,.MMUNO(P1) ;SAVE IT IN THE MESSAGE
MOVE S1,G$SND## ;GET THE SENDERS PID
MOVEM S1,.MMPID(P1) ;SAVE IT IN THE MESSAGE
MOVE S1,G$MCOD## ;GET THE SENDERS ACK CODE
MOVEM S1,.MMUCD(P1) ;SAVE IT IN THE MESSAGE
MOVE S1,.MRJOB(AP) ;GET THE USERS CAPABILITIES
MOVEM S1,.MMCAP(P1) ;SAVE IT IN THE MESSAGE
MOVE S1,[POINT 7,.MRACT(AP)] ;GET POINTER TO MDR ACCOUNT STRING
MOVE S2,[POINT 7,.MMACT(P1)] ;GET POINTER TO DESTINATION
MNT.0: ILDB TF,S1 ;COPY ACCOUNT
IDPB TF,S2 ; STRING FROM MDR
JUMPN TF,MNT.0 ; TO THE MESSAGE
LOAD S1,.MSTYP(M),MS.CNT ;GET THE SENDERS MESSAGE LENGTH
STORE S1,.MMUMS(P1) ;SAVE IT IN THE MESSAGE
ADD S1,P1 ;GET THE END ADDRESS (FOR BLT)
HRL S2,M ;GET THE SOURCE ADDRESS
HRR S2,P1 ;AND THE DESTINATION ADDRESS
BLT S2,0(S1) ;COPY IT OVER
MOVEI S1,1000 ;GET THE PAGE LENGTH
STORE S1,.MSTYP(P1),MS.CNT ;SAVE IT AS THE NEW MESSAGE LENGTH
PUSH P,AP ;SAVE AP FOR A MINUTE
MOVEI AP,MNTPDB ;POINT TO THE MESSAGE PDB
PUSHJ P,C$SEND## ;SEND THE MESSAGE OFF TO MOUNTR
POP P,AP ;RESTORE AP
$RETT ;AND RETURN
SUBTTL I$MTR - ROUTINE TO PROCESS MTCON RELEASE MESSAGES
;CALL: M/RELEASE MESSAGE ADDRESS (SAME AS .QOREL)
;
;RET: FALSE - ERROR MESSAGE (MTS, MTL, SNY)
; TRUE - REQUEST DELETED
INTERN I$MTR ;CREATE THE ENTRY POINT
I$MTR: PUSHJ P,.SAVE1 ;SAVE P1
LOAD S1,.MSTYP(M),MS.CNT ;GET THE MESSAGE LENGTH
CAIGE S1,REL.SZ ;IS IT LESS THEN RELEASE MSG SIZE ??
JRST E$MTS## ;YES,,THATS AN ERROR
CAIE S1,REL.SZ ;IS IT GREATER THEN RELSE MSG SIZE ???
JRST E$MTL## ;THAT TOO IS AN ERROR
MOVE S1,MDRQUE## ;GET THE MOUNT QUEUE ID
PUSHJ P,L%FIRST ;GET THE FIRST QUEUE ENTRY
JUMPF E$SNY## ;NONE THERE,,THATS AN ERROR
MTR.1: MOVE AP,S2 ;SAVE THE MDR ADDRESS IN AP
LOAD S1,.MRRID(AP),MR.RID ;GET THIS REQUESTS ID
CAMN S1,REL.IT(M) ;IS THIS THE ONE WE WANT ???
PJRST D$DMDR## ;YES,,DELETE IT AND RETURN
MOVE S1,MDRQUE## ;GET THE MOUNT QUEUE ID
PUSHJ P,L%NEXT ;GET THE NEXT QUEUE ENTRY
JUMPT MTR.1 ;FOUND,,GO CHECK IT
JRST E$SNY## ;NO MORE,,THATS AN ERROR
SUBTTL OPERATOR TAPE/DISK MOUNT MESSAGES
;CALL: M/MESSAGE ADDRESS
; T4/MESSAGE LENGTH
; P1/MESSAGE TYPE
;
;RET: TRUE ALWAYS
INTERN I$OMNT ;MAKE THE ROUTINE GLOBAL
I$OMNT: PUSHJ P,FNDPSB ;GET MTCON'S PSB
JUMPF OMNT.1 ;NOT THERE,,TELL OPERATOR
MOVE S1,PSBPID(S1) ;GET MTCONS PID
MOVEM S1,MNTPDB+.IPCFR ;SAVE IT IN THE PDB
PUSHJ P,M%ACQP ;GO GET A PAGE FOR IPCF
HRRM S1,MNTPDB+.IPCFP ;SAVE THE PAGE NUMBER IN THE PDB
PG2ADR S1 ;CONVERT IT TO AN ADDRESS
ADD T4,S1 ;CALC BLT END ADDRESS
HRL S1,M ;GET THE SOURCE ADDRESS
BLT S1,0(T4) ;COPY THE MESSAGE OVER
MOVEI AP,MNTPDB ;GET THE PDB ADDRESS
PUSHJ P,C$SEND## ;SEND THE MESSAGE OFF
$RETT ;AND RETURN
OMNT.1: $ACK (Mount Request Processor Not Running,,,.MSCOD(M))
$RETT ;RETURN
SUBTTL TAPE MOUNT CHECKPOINT ROUTINE
;CALL: M/ADDRESS OF CHECKPOINT MESSAGE
;
;RET: FALSE - ERROR MESSAGE (SNY, IPE)
; TRUE - REQUEST IS CHECKPOINTED
INTERN I$CHKP ;MAKE IT GLOBAL
I$CHKP: PUSHJ P,.SAVE2 ;SAVE P1 & P2
PUSHJ P,I$WHEEL ;MAKE SURE THE GUY HAS PRIVS.
JUMPF E$IPE## ;NO,,THE GUY IS A FRAUD
MOVE S1,MDRQUE## ;GET THE QUEUE LIST ID
PUSHJ P,L%FIRST ;GET THE FIRST ENTRY
JRST CHKP.2 ;SKIP THE FIRST TIME THROUGH
;Find the MDR in the Request queue
CHKP.1: MOVE S1,MDRQUE## ;GET THE MDR QUEUE ID
PUSHJ P,L%NEXT ;GET THE NEXT MDR ENTRY
CHKP.2: JUMPF E$SNY## ;NOT FOUND,,THATS AN ERROR
LOAD S1,.MRRID(S2),MR.RID ;GET THIS MDR'S RID IN S1
CAME S1,CHE.IT(M) ;HAVE WE FOUND THE MDR WE WANT ???
JRST CHKP.1 ;NO,,TRY THE NEXT MDR
MOVE AP,S2 ;SAVE THE MDR ADDRESS
MOVE S1,.MRVSL(AP) ;GET THE VSL ADDRESS
LOAD P2,.VSCVL(S1),VS.OFF ;GET THE OFFSET TO THE CURRENT VOLUME
ADDI P2,.VSVOL(S1) ;POINT TO THE CURRENT VOLUME ADDRESS
MOVE P2,0(P2) ;GET THE CURRENT VOLUME
MOVE S1,CHE.IN+.MTVOL(M) ;GET THE VOLUME (PERHAPS) IN S1
CAXE S1,%VOLBL ;IS THE VOLUME NAME BLANK ???
CAXN S1,%VOLSC ;OR IS IT A SCRATCH VOLUME ???
JRST [MOVX S1,VL.SCR ;YES,,GET THE SCRATCH VOLUME BIT
IORM S1,.VLFLG(P2) ;MAKE THE VOLUME A SCRATCH VOLUME
JRST CHK.2A ] ;AND CONTINUE
MOVEM S1,.VLNAM(P2) ;SAVE THE NEW VOLUME ID
ZERO .VLFLG(P2),VL.SCR ;CLEAR SCRATCH BIT
CHK.2A: ZERO .VLOWN(P2),VL.OFF ;MAKE THIS GUY THE CURRENT OWNER
MOVE S2,CHE.IN+.MTSTA(M) ;GET THE DEVICE NAME (POSSIBLY)
CAXE S2,%STAWT ;IS IT WAITING ???
CAXN S2,%STAAB ;OR IS IT 'ABORTED' ???
JRST [STORE S2,.VLFLG(P2),VL.STA ;YES,,SAVE THE NEW VOLUME STATUS
$RETT ] ;AND RETURN
HRROI S1,TMPBFR ;NO,,POINT TO ASCIZ DEVICE NAME BUFFER
DEVST ;TRY TO CONVERT TO ASCIZ DEVICE NAME
$RETT ;STILL NO GOOD,,JUST RETURN
HRROI S1,TMPBFR ;POINT TO THE ASCIZ DEVICE NAME
PUSHJ P,S%SIXB ;CONVERT IT TO SIXBIT
MOVE P1,S2 ;SAVE THE DEVICE NAME IN P1
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
;Find the UCB in the Device queue. If not there, create a UCB for the device
MOVE S1,UCBQUE## ;GET THE UCB QUEUE ID
PUSHJ P,L%FIRST ;GET THE FIRST UCB ENTRY
JRST CHKP.4 ;JUMP THE FIRST TIME THROUGH
CHKP.3: MOVE S1,UCBQUE## ;GET THE UCB QUEUE ID
PUSHJ P,L%NEXT ;GET THE NEXT UCB
CHKP.4: SKIPT ;THERE WAS ONE,,CHECK IT OUT
PUSHJ P,CHKP.6 ;NO MORE UCB'S,,CREATE ONE
CAME P1,.UCBNM(S2) ;HAVE WE FOUND THE UCB IN QUESTION ??
JRST CHKP.3 ;NO,,TRY THE NEXT ONE
MOVE P1,S2 ;SAVE THE UCB ADDRESS IN P1
SKIPE S1,.UCBVL(P1) ;ANY VOLUME POINTER ???
SETZM .VLUCB(S1) ;YES,,CLEAR THE VOL UCB POINTER
SETZM .UCBVL(P1) ;AND CLEAR THE UCB VOL POINTER
MOVEM P2,.UCBVL(P1) ;LINK THE VOL TO THE UCB
MOVEM P1,.VLUCB(P2) ;LINK THE UCB TO THE VOL
MOVX S1,%STAMN ;GET 'VOLUME' MOUNTED STATUS CODE
STORE S1,.VLFLG(P2),VL.STA ;SAVE THE NEW VOLUME STATUS
$RETT ;AND RETURN
;Subroutine to create a UCB entry for the device in the status message
CHKP.6: MOVE S1,UCBQUE## ;GET THE UCB QUEUE ID
MOVX S2,UCBLEN ;GET THE LENGTH OF A UCB
PUSHJ P,L%CENT ;CREATE A UCB FOR THE DEVICE IN P1
MOVEM P1,.UCBNM(S2) ;SAVE THE DEVICE NAME
MOVX S1,%TAPE ;WANT 'TAPE' DEVICE TYPE
STORE S1,.UCBST(S2),UC.DVT ;SAVE AS THE DEVICE TYPE
$RETT ;RETURN
SUBTTL I$MATR - ROUTINE TO SETUP AND PASS MNT ATTRIBUTE MSGS TO MTCON
;CALL: M/ MAT REQUEST ADDRESS
;
;RET: TRUE IF SENT OK
; FALSE IF MTCON NOT RUNNING
INTERN I$MATR ;MAKE IT GLOBAL
I$MATR: PUSHJ P,.SAVE1 ;SAVE P1
PUSHJ P,FNDPSB ;FIND MTCON'S PSB
JUMPF E$MPN## ;NOT THERE,,SEND ERROR MSG
MOVE S1,PSBPID(S1) ;GET THE PID
MOVEM S1,MNTPDB+.IPCFR ;SAVE IT IN THE PDB
PUSHJ P,M%ACQP ;GET A PAGE FOR IPCF
HRRM S1,MNTPDB+.IPCFP ;SAVE THE PAGE NUMBER
PG2ADR S1 ;MAKE IT AN ADDRESS
MOVE P1,S1 ;SAVE IT IN P1
HRL S1,M ;GET THE SOURCE ADDRESS (FOR BLT)
BLT S1,.MATQS-1(P1) ;COPY THE MESSAGE OVER
MOVX S1,.MATQS ;GET THE MESSAGE LENGTH
STORE S1,.MSTYP(P1),MS.CNT ;SAVE IT IN THE MESSAGE
LOAD S1,G$PRVS## ;GET PRVS,,JOB NUMBER
STORE S1,.MATCP(P1) ;SAVE IT IN THE MESSAGE
LOAD S1,G$SND## ;GET THE SENDERS PID
STORE S1,.MATPD(P1) ;SAVE IT IN THE MESSAGE
MOVEI AP,MNTPDB ;GET THE PDB ADDRESS
PUSHJ P,C$SEND## ;SEND THE MESSAGE OFF
$RETT ;AND RETURN
SUBTTL I$KMNT - ROUTINE TO PROCESS USER MOUNT KILL REQUESTS
;CALL: M/ Kill Message Address
;
;RET: TRUE ALWAYS
INTERN I$KMNT ;MAKE IT GLOBAL
I$KMNT: PUSHJ P,.SAVE3 ;SAVE P1, P2, AND P3
PUSHJ P,FNDPSB ;IS TAPE PROCESSOR RUNNING ???
JUMPF E$MPN## ;NO,,THATS AN ERROR
MOVE S1,PSBPID(S1) ;ELSE GET THE PROCESSOR'S PID
MOVEM S1,MNTPDB+.IPCFR ;SAVE IT AS THE RECIEVERS PID
MOVEI P1,KIL.RQ(M) ;GET THE RDB ADDRESS
SETZB P2,P3 ;ZERO P2 AND P3
MOVE S1,MDRQUE## ;GET THE MOUNT QUEUE ID
PUSHJ P,L%FIRST ;GET THE FIRST ENTRY
JUMPF E$SNY## ;NONE THERE,,THATS AN ERROR
KMNT.1: MOVE AP,S2 ;SAVE THE ENTRY ADDRESS
MOVE S1,.MRUSR(AP) ;GET THE USER ID
CAME S1,G$SID## ;IS IT THE SAME USER ???
JRST KMNT.4 ;NO,,TRY NEXT ENTRY
KMNT.2: SKIPN S1,.RDBRQ(P1) ;DID HE SPECIFY A REQUEST ID ???
JRST KMN.2A ;NO,,SKIP THIS
LOAD S2,.MRRID(AP),MR.RID ;GET THE REQUEST ID IN S2
CAIE S1,0(S2) ;DO THE REQUEST ID'S MATCH ???
JRST KMNT.4 ;NO,,TRY NEXT ENTRY
JRST KMN.2B ;YES,,CHECK JOB NUMBERS
KMN.2A: MOVE S1,.MRREQ(AP) ;GET THE REQUEST NAME
XOR S1,.RDBJB(P1) ;ZERO IDENTICAL BITS
AND S1,.RDBJM(P1) ;AND IT WITH THE MASK
JUMPN S1,KMNT.4 ;NOT ZERO, WE DONT MATCH, TRY NEXT ENTRY
KMN.2B: LOAD S1,G$PRVS##,MD.PJB ;GET THE USERS JOB NUMBER
LOAD S2,.MRJOB(AP),MD.PJB ;GET THE REQUESTS JOB NUMBER
CAME S1,S2 ;FROM THE SAME JOB ???
JRST KMNT.4 ;NO,,TRY THE NEXT ENTRY
SKIPE P2 ;HAVE WE SETUP THE IPCF MSG PAGE ???
JRST KMNT.3 ;YES,,CONTINUE ON
PUSHJ P,M%ACQP ;DONT DO THIS UNLESS WE HAVE TO !!
HRRM S1,MNTPDB+.IPCFP ;SAVE THE PAGE NUMBER IN THE PDB
PG2ADR S1 ;CONVERT IT TO AN ADDRESS
MOVE P2,S1 ;SAVE IT IN P2
MOVX S1,.QOMTA ;GET THE MESSAGE TYPE
STORE S1,.MSTYP(P2),MS.TYP ;SAVE IT
MOVEI S1,1000 ;GET THE MESSAGE LENGTH
STORE S1,.MSTYP(P2),MS.CNT ;SAVE IT
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
MOVE S1,.MSCOD(M) ;GET THE USERS ACK CODE
MOVEM S1,.MSCOD(P2) ;SAVE IT IN OUR MSG
MOVE S1,.MSFLG(M) ;GET THE USERS FLAG WORD
MOVEM S1,.MSFLG(P2) ;SAVE IT IN OUR MSG
MOVEI S1,2 ;GET THE BLOCK COUNT
STORE S1,.OARGC(P2) ;SAVE IT
MOVEI P2,.OHDRS(P2) ;POINT TO THE FIRST BLOCK
MOVX S1,.MTPID ;GET THE BLOCK TYPE
STORE S1,ARG.HD(P2),AR.TYP ;SAVE IT
MOVEI S1,2 ;GET THE BLOCK LENGTH
STORE S1,ARG.HD(P2),AR.LEN ;SAVE IT
MOVE S1,G$SND## ;GET THE SENDERS PID
STORE S1,ARG.DA(P2) ;SAVE IT
MOVEI P2,2(P2) ;POINT TO THE NEXT BLOCK
MOVX S1,.MTITN ;GET THE BLOCK TYPE
STORE S1,ARG.HD(P2),AR.TYP ;SAVE IT
PUSH P,P2 ;SAVE THIS BLOCK ADDRESS
MOVEI P2,ARG.DA(P2) ;POINT TO THE DATA AREA
KMNT.3: LOAD S1,.MRRID(AP),MR.RID ;GET THIS REQUESTS ITN
STORE S1,0(P2) ;SAVE IT IN THE MESSAGE
MOVEI P2,1(P2) ;GET THE NEXT ITN ADDRESS
AOS P3 ;BUMP THE ITN COUNT
KMNT.4: MOVE S1,MDRQUE## ;GET THE QUEUE LIST ID
PUSHJ P,L%NEXT ;GET THE NEXT ENTRY
JUMPT KMNT.1 ;FOUND ONE,,CONTINUE
JUMPE P2,E$SNY## ;FIND ANYTHING ???,,NO SEND AN ERROR
POP P,P2 ;RESTORE THE LAST BLOCK ADDRESS
AOS P3 ;ADD THE HEADER LENGTH
STORE P3,ARG.HD(P2),AR.LEN ;SAVE THE BLOCK LENGTH
MOVEI AP,MNTPDB ;POINT TO THE PDB
PUSHJ P,C$SEND ;SEND THE MESSAGE
SETZM G$ACK## ;DONT ACK USERS MSG (LET MTCON DO IT)
$RETT ;AND RETURN
SUBTTL TAPE MOUNT UTILITY ROUTINES
;FNDPSB - ROUTINE TO FIND THE MOUNT PROCESSOR'S PSB
;CALL: PUSHJ P,FNDPSB
; RETURN HERE ALWAYS
;RET: S1/ADDRESS OF MOUNT PSB
FNDPSB: MOVEI S1,HDRPSB## ;POINT TO THE PSB QUEUE
LOAD S1,.QHLNK(S1),QH.PTF ;GET THE FIRST PSB ENTRY
MOVEI S2,.OTMNT ;GET THE OBJECT TYPE
FNDP.1: JUMPE S1,.RETF ;NO MORE,,RETURN FALSE
CAMN S2,PSBOBJ(S1) ;DO WE MATCH ???
$RETT ;YES,,RETURN TRUE
LOAD S1,.QELNK(S1),QE.PTN ;POINT TO THE NEXT ENTRY
JRST FNDP.1 ;AND GO CHECK IT OUT
SUBTTL FILE ARCHIVING SCHEDULING ROUTINES
INTERN I$ARCHIVE ;PROCESS A MONITOR ARCHIVE MSG
INTERN I$RLNK ;LINK A RETREIVAL REQUEST INTO THE QUEUE
INTERN I$RSCH ;SCHEDULE A JOB FOR AN OBJECT
INTERN I$RDEF ;FILL IN DEFAULTS FOR A JOB
INTERN I$RFJB ;FIND A JOB FOR SCHEDULING
SUBTTL ARCHIVE -- IPCC Function .IPCSR (41)
; The ARCHIVE message is sent by the operating system whenever a
; retrieval request is made, and whenever the tape pointers
; of an archived file are destroyed.
;
; CALL: M/ Monitor Archive/Notification Msg Address
;
I$ARCHIVE:
PUSHJ P,M%GPAG ;GET A PAGE FOR THE EQ
MOVE P1,S1 ;SAVE ITS ADDRESS
MOVE S1,[EQHSIZ+FPMSIZ+FDXSIZ,,.QIRET] ;GET LENGTH,,TYPE
STORE S1,.MSTYP(P1) ;SAVE IT IN THE MESSAGE
MOVE S1,[%%.QSR,,EQHSIZ] ;GET QUASAR VERSION,,HEADER SIZE
STORE S1,.EQLEN(P1) ;SAVE IT IN THE MESSAGE
LOAD S1,ARC.FN(M),AR.FNC ;GET THE FUNCTION CODE
LOAD S1,[.OTRET ;USE AS AN OFFSET TO GET THE
.OTNOT](S1) ;CORRECT OBJECT TYPE
STORE S1,.EQROB+.ROBTY(P1) ;SAVE IT IN THE MESSAGE
MOVE S1,G$LNAM## ;GET THE LOCAL NODE NAME
MOVEM S1,.EQROB+.ROBND(P1) ;SAVE IN THE OBJECT BLOCK
LOAD S1,ARC.PR(M),AR.PRT ;GET THE PROTECTION BITS
STORE S1,.EQSPC(P1),EQ.PRO ;SAVE THEM IN THE MESSAGE
LOAD S1,ARC.FN(M),AR.MOD ;GET THE REASON VALUE
STORE S1,.EQSEQ(P1),EQ.PRI ;MAKE IT THE REQUESTS PRIORITY
MOVEI S1,1 ;GET A 1
STORE S1,.EQSPC(P1),EQ.NUM ;ONE FILE IN THIS EQ
HRLI S1,ARC.T1(M) ;SETUP SOURCE POINTER
HRRI S1,.EQLIM+1(P1) ;AND THE DESTINATION POINTER
BLT S1,.EQLIM+4(P1) ;COPY OVER THE TAPE 1 INFO
MOVX T1,EQHSIZ ;GET THE HEADER SIZE
ADD T1,P1 ;POINT TO THE FP AREA
MOVX S1,FPMSIZ ;GET THE FP LENGTH
STORE S1,.FPLEN(T1),FP.LEN ;SAVE IT IN THE FP
ADD T1,S1 ;POINT TO THE FP
MOVX S1,FDXSIZ ;GET THE FD SIZE
STORE S1,.FDLEN(T1),FD.LEN ;SAVE IT IN THE FD
HRLI S1,ARC.FL(M) ;POINT TO THE FILE-SPEC
HRRI S1,.FDFIL(T1) ;AND ITS DESTINATION
BLT S1,FDXSIZ-1(T1) ;COPY THE FILE-SPEC OVER TO THE EQ
PUSH P,M ;SAVE THE ARCHIVE MSG ADDRESS
MOVE M,P1 ;RESET M TO POINT TO THE EQ
PUSHJ P,Q$CREATE## ;CREATE THE QUEUE ENTRY
SKIPE G$ERR## ;ANY ERRORS ???
$STOP(CRA,CREATE REJECTED ARCHIVE DATA) ;YES,,SERIOUS ERROR !!!
POP P,M ;RESTORE THE ARCHIVE MESSAGE ADDRESS
LOAD S1,ARC.FN(M),AR.FNC ;GET THE FINCTION CODE
CAXN S1,.RETM ;IS IT A FILE RETRIEVAL REQUEST ???
$WTO (< Request From ^T/.EQOWN(P1)/ >,<File: ^T/ARC.FL(M)/>,.EQROB+.ROBTY(P1))
MOVE S1,P1 ;GET THE EQ ADDRESS
PJRST M%RPAG ;RELEASE IT AND RETURN
SUBTTL Retrieval Queue Subroutines
; Routine to link a retrieval request into the queue. Requests are ordered
; by their tape pointers.
I$RLNK: PUSHJ P,.SAVET ; Save T1-T4
MOVE S1,AP ; S1 points to new entry
MOVEI S2,RETL.A ; S2 points to tape info block
PUSHJ P,GETAPE ; Get the relevant tape numbers
LOAD E,.QHLNK(H),QH.PTF ; Get pointer to first in Q
RETL.1: JUMPE E,M$ELNK## ; If end of queue, tack on to end
MOVE S1,E ; S1 points to queued entry
MOVEI S2,T1 ; Tape info to T1 and T2
PUSHJ P,GETAPE ; Get tape info
CAMLE T1,RETL.A+0 ; Compare tape ID's
PJRST M$LINK## ; Link in here
CAME T1,RETL.A+0 ; Compare ID's again
JRST RETL.2 ; Move to next queued entry
CAMLE T2,RETL.A+1 ; Compare TSN,,TFN
PJRST M$LINK## ; Link in here
RETL.2: LOAD E,.QELNK(E),QE.PTN ; Get next entry in Q
JRST RETL.1 ; And continue
RETL.A: BLOCK 2 ; Tape info
;Routine to fill in tape information of a new retrieval request.
I$RDEF: SETZ S1,
STOLIM S1,.EQLIM(M),TDTD ;Clear timestamp
HRLI S1,.EQLIM(M) ; Make BLT pointer
HRRI S1,.EQCHK(M) ; Copy the tape info
BLT S1,.EQCHK+<EQLMSZ-1>(M) ; Into the limit words
AOS S1,RETSEQ ; Get new sequence #
STORE S1,.EQSEQ(M),EQ.SEQ ; Sequence the request
LOAD S1,.EQLEN(M),EQ.LOH ;GET THE MSG HEADER LENGTH
ADD S1,M ;POINT TO THE FP
LOAD S2,.FPLEN(S1),FP.LEN ;GET THE FP LENGTH
ADDI S1,.FDSTG(S2) ;POINT TO THE FILE NAME
HRL S1,S1 ;MOVE SOURCE TO LEFT HALF
HRRI S1,.EQCON(M) ;GET THE DESTINATION ADDRESS
BLT S1,.EQCON+11(M) ;PUT THE FILE NAME IN THE CONN DIR AREA
SETZM S1 ;GET A NULL BYTE
DPB S1,[POINT 7,.EQCON+11(M),34] ;MAKE SURE ITS ASCIZ
$RETT ; (A REAL HACK !!!) RETURN
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
I$RSCH: PUSHJ P,.SAVE1 ;SAVE P1 FOR A MINUTE
MOVE P1,S2 ;SAVE THE OBJECT ADDRESS
MOVEI S2,OBJPRM+.OBTAP(P1) ; Point to OBJ tape info
PUSHJ P,GETAPE ; Copy tape info into OBJ
MOVE S1,G$NOW## ;GET THE CURRENT UDT
EXCH S1,OBJPRM+.OBSTM(P1) ;SWAP THE CURRENT TIME WITH OBJECT TIME
CAIE S1,0 ;WAS OBJECT TIME 0
CAXN S1,<1B1> ;OR WAS IT 200000,,0
$RETT ;YES TO EITHER,,JUST RETURN
MOVEM S1,OBJPRM+.OBSTM(P1) ;NO,,RESTORE OLD OBJECT TIME
$RETT ;RETURN AND SEND NEXTJOB MSG
; Routine to find a retrieval request. If DUMPER is not already
; processing one, the next retrieval to be processed is found by skipping
; through the queue until a request which sorts after the most recently
; processed request. Starting with that request, the timestamps are
; checked. If a request is found which was not already processed (and
; rejected) by the current instance of DUMPER, that is the chosen request.
I$RFJB: PUSHJ P,.SAVE1 ; Save P1
SETZM RETS.A ; Clear flag
MOVE P1,S1 ; Save OBJ address
LOAD S1,HDRRET##+.QHLNK,QH.PTF ; Get first item in the QUEUE
JUMPE S1,RETS.5 ;NOTHING THERE,,JUST RETURN
RETS.0: MOVEI S2,T1 ; Point to T1-T2
PUSHJ P,GETAPE ; Get tape info
CAMGE T1,OBJPRM+.OBTAP(P1) ; Compare tape ID's
JRST RETS.1 ; Already been tried this pass
CAME T1,OBJPRM+.OBTAP(P1) ; Compare again
JRST RETS.3 ; Start with this one
CAMGE T2,OBJPRM+.OBSSN(P1) ; Compare TSN,,TFN
JRST RETS.1 ; Already tried this pass
CAME T2,OBJPRM+.OBSSN(P1) ; Compare again
JRST RETS.3 ; Start here
RETS.1: LOAD S1,.QELNK(S1),QE.PTN ; Get next in Q
JUMPN S1,RETS.0 ; Continue if anything there
PUSHJ P,RETS.9 ; Otherwise start new pass
; Now that we have found the place to start looking, start looking.
RETS.3: GETLIM T1,.QELIM(S1),TDAT ;Get date/time last tried
CAMLE T1,OBJPRM+.OBSTM(P1) ; In the past?
JRST RETS.4 ; No, keep looking
$RETT ; Schedule this one
;CONTINUED ON THE NEXT PAGE
;CONTINUED FROM THE PREVIOUS PAGE
RETS.4: LOAD S1,.QELNK(S1),QE.PTN ; Get next in Q
JUMPN S1,RETS.3 ; Continue if anything there
SKIPE RETS.A ; Just start a new pass?
JRST RETS.5 ; Yes, no more to do
PUSHJ P,RETS.9 ; No, start one
JRST RETS.3 ; Resume loop
; Here when there are no more suitable requests.
RETS.5: MOVX S1,OBSINT ;GET INTERNAL SHUTDOWN BIT
IORM S1,OBJSCH(P1) ;LITE IT
SETZM OBJPRM+.OBTAP(P1) ;CLEAR THE LAST TAPE ID
SETZM OBJPRM+.OBSSN(P1) ;CLEAR THE LAST SAVE SET NUMBER
MOVX S1,<1B1> ;CREATE A VERY LARGE TIME STAMP
MOVEM S1,OBJPRM+.OBSTM(P1) ;AND SET IT FOR LATER
$RETF ;AND RETURN
; Subroutine used by RETSCH to begin a new pass through the queue.
RETS.9: SETZM OBJPRM+.OBTAP(P1) ; Reset watermark
SETZM OBJPRM+.OBSSN(P1) ; Ditto
LOAD S1,HDRRET##+.QHLNK,QH.PTF ; Point to first in Q
SETOM RETS.A ; Flag the new pass
POPJ P,
RETS.A: BLOCK 1 ; -1 implies new pass started
SUBTTL GETAPE - ROUTINE TO EXTRACT TAPE NBRS FROM A RETREIVAL REQUEST
; The GETAPE routine is used by RETLNK and RETFJB to extract the tape
; numbers by which a retrieval request should be sorted.
; Call S1 = pointer to retrieval request (QE)
; S2 = pointer to 2 word block, as follows:
; 0: Tape ID
; 1: TSN,,TFN
; Returns +1 always.
GETAPE: PUSHJ P,.SAVE2 ; Save P1-P3
GETLIM P1,.QELIM(S1),TID2 ; Assume using 2nd set
GETLIM P2,.QELIM(S1),TTN2
DMOVEM P1,0(S2) ; Store it wherever
GETLIM P1,.QELIM(S1),TUFT ; Get 1st/2nd flag bit
JUMPE P1,.RETT ; If not set, assumption correct
GETLIM P1,.QELIM(S1),TID1 ; Was set, get 1st set
GETLIM P2,.QELIM(S1),TTN1
DMOVEM P1,0(S2) ; Return those instead
$RETT ; Done
SUBTTL FILE ARCHIVING NOTIFICATION SCHEDULING ROUTINES
INTERN I$NLNK ;LINK IN A JOB
INTERN I$NDEF ;FILL IN DEFAULTS FOR A JOB
INTERN I$NFJB ;FIND A JOB FOR SCHEDULING
; Routine to link entries in the notification queue. The entries are
; sorted first by the directory number, and second by the reason
; for notification (either the file was expunged or the archive
; pointers were explicitly discarded.)
I$NLNK: PUSHJ P,.SAVE3 ; Save P1-P3
LOAD E,.QHLNK(H),QH.PTF ; Get first in Q
GETLIM P1,.QELIM(AP),TDTD ; Get timestamp
LOAD P2,.QESEQ(AP),QE.PRI ; Get reason for notification
NOTL.1: JUMPE E,M$ELNK## ; If end, link there
CAMGE P1,.QELIM(E) ; Compare dir #s
PJRST M$LINK## ; Link in here
CAME P1,.QELIM(E) ; Compare again
JRST NOTL.2 ; Scan further
LOAD P3,.QESEQ(E),QE.PRI ; Get reason of Q'd entry
CAMG P2,P3 ; Compare
PJRST M$LINK## ; Link in here
NOTL.2: LOAD E,.QELNK(E),QE.PTN ; Get next in Q
JRST NOTL.1 ; And keep comparing
SUBTTL I$NDEF - ROUTINE TO FILL IN NOTIFICATION DEFAULTS
; Routine to fill in the tape pointers and directory number associated
; with the file in a NOTIFICATION queue entry.
I$NDEF: LOAD S1,.EQLEN(M),EQ.LOH ;GET THE HEADER LENGTH
ADD S1,M ;POINT TO THE FP
LOAD S2,.FPLEN(S1),FP.LEN ;GET THE FP LENGTH
ADDI S2,.FDFIL(S1) ;POINT TO THE FD FILENAME
HRLI S2,(POINT 7,0) ;MAKE IT A BYTE POINTER
MOVE S1,[POINT 7,DIRCTY] ;GET THE DESTINATION PTR
NDEF.1: ILDB T1,S2 ;GET A FILESPEC BYTE
IDPB T1,S1 ;SAVE IT
JUMPE T1,.RETF ;IF 0,,THATS A NO-NO
CAIE T1,76 ;WAS IT THE END OF THE DIRECTORY ???
JRST NDEF.1 ;NO,,KEEP ON GOING
SETZM T1 ;GET A NULL BYTE
IDPB T1,S1 ;MAKE IT ASCIZ
MOVX S1,RC%EMO ;WANT EXACT MATCH ONLY
HRROI S2,DIRCTY ;GET THE ASCIZ STRUCTURE ADDRESS
SETZM T1 ;CLEAR AC 3
RCDIR ;GET THE FILE'S DIRECTORY NUMBER
ERJMP .RETF ;NO GOOD,,END IT ALL
STOLIM T1,.EQLIM(M),TDTD ;SAVE THE CONNECTED DIR IN THE LIMIT WRD
$RETT
DIRCTY: BLOCK 10 ;TEMP DIRECTORY STORAGE
REASON==DIRCTY+1 ;REASON BLOCK USED IN I$NTFY
I$NFJB: LOAD S1,HDRNOT##+.QHLNK,QH.PTF ; Hand 'em first guy in queue
JUMPE S1,.RETF ; Return if nothing there
$RETT
SUBTTL I$NTFY - ROUTINE TO PERFORM FILE ARCHIVING NOTIFICATION
INTERN I$NTFY ;MAKE IT GLOBAL
I$NTFY: PUSHJ P,.SAVE2 ;SAVE P1 AND P2
SETZM G$NTFY## ;CLEAR THE NOTIFY FLAG
MOVEI H,HDRNOT## ;SET UP THE NOTIFICATION HEADER PTR
SETZM DIRCTY ;CLEAR THE DIRECTORY NUMBER
SETZM P1 ;CLEAR THE OUTPUT PAGE ADDRESS
NTFY.1: LOAD AP,.QHLNK(H),QH.PTF ;GET THE FIRST ENTRY
JUMPE AP,NTFY.2 ;NO MORE,,RETURN
GETLIM S1,.QELIM(AP),TDTD ;GET THE USERS DIRECTORY NUMBER
CAME S1,DIRCTY ;IF THE SAME,,THEN CONTINUE
PUSHJ P,NSETUP ;ELSE GO SETUP A PAGE FOR OUTPUT
LOAD S1,.QESEQ(AP),QE.PRI ;GET THE REASON CODE (SAVED IN PRIO FLD)
CAME S1,REASON ;IF THE SAME,,THEN CONTINUE
PUSHJ P,NHEADR ;ELSE GO SETUP THE HEADER
PUSHJ P,NXFILE ;OUTPUT THE FILE DATA
JRST NTFY.1 ;AND GO GET ANOTHER ENTRY
NTFY.2: SKIPE P1 ;NOTHING THERE,,JUST RETURN
PUSHJ P,NSNDIT ;ELSE SEND THE DATA OFF TO ORION
PUSHJ P,NTIMER ;GO RESET THE NOTIFICATION TIMER
$RETT ;RETURN
SUBTTL NSETUP - ROUTINE TO SETUP A PAGE FOR NOTIFICATION
;CALL: AP/.QE ADDRESS
;
;RET: P1/OUTPUT PAGE ADDRESS
NSETUP: PUSH P,S1 ;SAVE S1 FOR A MINUTE
SKIPE P1 ;DO WE ALREADY HAVE A PAGE SETUP ???
PUSHJ P,NSNDIT ;YES,,SEND IT OFF
POP P,S1 ;RESTORE THE DIRECTORY NUMBER
MOVEM S1,DIRCTY ;SAVE IT FOR LATER
PUSHJ P,M%ACQP ;GET A PAGE FOR THE DATA
MOVE P1,S1 ;GET THE PAGE NUMBER IN P1
PG2ADR P1 ;CONVERT IT TO AN ADDRESS
MOVEI S1,.OMNFY ;GET THE NOTIFY MSG TYPE
STORE S1,.MSTYP(P1),MS.TYP ;SAVE IT IN THE MESSAGE
MOVX S1,NT.MLU ;GET THE 'MAIL TO USER' FLAG BITS
MOVEM S1,.OFLAG(P1) ;SAVE IT IN THE FLAG WORD
MOVEI S1,3 ;GET THE ARGUMENT COUNT
MOVEM S1,.OARGC(P1) ;SAVE IT IN THE MESSAGE
MOVEI S1,.CMTXT ;GET THE DATA BLOCK TYPE
STORE S1,.OHDRS+ARG.HD(P1) ;SAVE IT IN THE MESSAGE
MOVEI S1,.OHDRS+ARG.DA(P1) ;POINT TO THE DATA BLOCK
HRLI S1,(POINT 7,0) ;MAKE IT A BYTE POINTER
MOVEM S1,BYTPTR ;SAVE IT FOR LATER
SETZM P2 ;CLEAR THE FLAG AC
SETOM REASON ;RESET THE REASON
$RETT ;AND RETURN
SUBTTL NHEADR - ROUTINE TO SETUP THE DATA HEADER LINE
;CALL: S1/THE REASON (MUST BE 0 OR 1)
;
;RET: P2/THE ENCODED REASON
NHEADR: MOVEM S1,REASON ;SAVE THE REASON
TRO P2,1(S1) ;LITE THE APPROPRIATE BITS
CAIN S1,0 ;IS THE REASON 'EXPUNGED' ???
$TEXT (OUTBYT,<The Following Archived File(s) have been Expunged:>)
CAIN S1,1 ;IS THE REASON 'DISCARDED' ???
$TEXT (OUTBYT,<The Archive Status of the Following File(s) has been Discarded:>)
$RETT ;RETURN
SUBTTL NXFILE - ROUTINE TO OUTPUT THE FILE DATA
;CALL: AP/.QE ADDRESS
;
;RET: TRUE ALWAYS
NXFILE: LOAD S1,.QESTN(AP),QE.DPA ;GET THE EXTERNAL QUEUE DISK ADDRESS
PUSHJ P,F$RDRQ## ;READ IT IN
PUSH P,S1 ;SAVE THE ADDRESS FOR A MINUTE
LOAD S2,.EQLEN(S1),EQ.LOH ;GET THE HEADER LENGTH
ADD S1,S2 ;POINT TO THE FP
LOAD S2,.FPLEN(S1),FP.LEN ;GET THE FP LENGTH
ADDI S1,.FDFIL(S2) ;POINT TO THE FD FILESPEC
GETLIM T1,.QELIM(AP),TTS1 ;FILE #1 SAVESET #
GETLIM T2,.QELIM(AP),TTF1 ;FILE #1 FILE #
GETLIM T3,.QELIM(AP),TTS2 ;FILE #2 SAVESET #
GETLIM T4,.QELIM(AP),TTF2 ;FILE #2 FILE #
LOAD S2,.QELIM+1(AP) ;GET THE TAPE VOLUME ID
TLNN S2,777777 ;IS IT DECIMAL ???
$TEXT (OUTBYT,< ^T/0(S1)/ Tape 1:^D/.QELIM+1(AP)/,^D/T1/,^D/T2/ Tape 2:^D/.QELIM+3(AP)/,^D/T3/,^D/T4/>)
TLNE S2,777777 ;IS IT SIXBIT ???
$TEXT (OUTBYT,< ^T/0(S1)/ Tape 1:^W/.QELIM+1(AP)/,^D/T1/,^D/T2/ Tape 2:^W/.QELIM+3(AP)/,^D/T3/,^D/T4/>)
LOAD S1,.QESTN(AP),QE.DPA ;GET THE DISK ADDRESS AGAIN
PUSHJ P,F$RLRQ## ;RELEASE THE REQUEST
POP P,S1 ;GET THE IN-CORE ADDRESS
PUSHJ P,M%RPAG ;RELEASE IT
PUSHJ P,M$RFRE## ;RELEASE THE QE ALSO
$RETT ;AND RETURN
OUTBYT: IDPB S1,BYTPTR ;OUTPUT THE BYTE
$RETT ;AND RETURN
BYTPTR: BLOCK 1 ;BYTE POINTER FOR NOTIFICATION
SUBTTL NSNDIT - ROUTINE TO SEND THE NOTIFICATION
;CALL: P1/THE DATA PAGE ADDRESS
;
;RET: TRUE ALWAYS
NSNDIT: $SAVE AP ;SAVE AP ACROSS THE SUBROUTINE CALL
HRRZ S1,BYTPTR ;GET THE END ADDRESS
SUBI S1,.OHDRS-1(P1) ;GET THE BLOCK LENGTH
STORE S1,.OHDRS+ARG.HD(P1),AR.LEN ;SAVE IT IN THE MESSAGE
ADDI S1,.OHDRS(P1) ;POINT TO THE NEXT BLOCK
MOVE S2,[2,,.CMDIR] ;SET UP THE DIRECTORY BLK HEADER
MOVEM S2,ARG.HD(S1) ;SAVE IT
MOVE S2,DIRCTY ;GET THE USERS DIRECTORE NUMBER
MOVEM S2,ARG.DA(S1) ;SAVE IT
ADDI S1,2 ;POINT TO THE NEXT BLOCK
PUSH P,S1 ;SAVE ITS ADDRESS FOR A MINUTE
MOVX S2,.NTSUB ;GET THE SUBJECT BLK TYPE
STORE S2,ARG.HD(S1) ;SAVE IT IN THE MESSAGE
MOVEI S1,ARG.DA(S1) ;POINT TO THE DATA BLOCK
HRLI S1,(POINT 7,0) ;MAKE IT A BYTE POINTER
MOVEM S1,BYTPTR ;SAVE IT
$TEXT (OUTBYT,<^T/@REATBL(P2)/>) ;OUTPUT THE SUBJECT STRING
HRRZ S1,BYTPTR ;GET THE END ADDRESS
POP P,S2 ;GET THE START ADDRESS
SUBI S1,-1(S2) ;GET THE BLOCK LENGTH
STORE S1,ARG.HD(S2),AR.LEN ;SAVE IT IN THE MESSAGE
HRRZ S1,BYTPTR ;GET THE END ADDRESS AGAIN
SUBI S1,-1(P1) ;GET THE MESSAGE LENGTH
STORE S1,.MSTYP(P1),MS.CNT ;SAVE IT
ADR2PG P1 ;CONVERT THE ADDRESS TO A PAGE NUMBER
HRRM P1,MNTPDB+.IPCFP ;SAVE THE PAGE NUMBER
MOVE S1,G$OPR## ;GET ORION'S PID
MOVEM S1,MNTPDB+.IPCFR ;SAVE AS RECIEVERS PID
MOVEI AP,MNTPDB ;GET THE PDB ADDRESS
PUSHJ P,C$SEND## ;SEND IT OFF
$RETT ;AND RETURN
REATBL: [0,,0] ;NOT USED
[ASCIZ/Expunged Archive File(s)/]
[ASCIZ/Discarded Archive Status/]
[ASCIZ\Expunged File(s)/Discarded Archive Status\]
SUBTTL NTIMER - ROUTINE TO SET/RESET THE NOTIFICATION TIMER
NTIMER: MOVEI S1,COMSTA##+.OHDRS+ARG.DA+OBJ.TY ;POINT TO THE OBJECT BLOCK
PUSHJ P,A$FOBJ## ;GO FIND IT
JUMPF .RETF ;NOT THERE,,JUST RETURN
MOVE P1,S1 ;SAVE THE OBJECT ADDRESS
MOVX S1,OBSIGN ;GET THE IGNORE BIT
IORM S1,OBJSCH(P1) ;SET IT
MOVEI S1,^D240 ;GET FOUR HOURS IN MINUTES
PUSHJ P,I$AFT ;GET CURRENT TIME+4 HOURS
STORE S1,OBJTIM(P1) ;SAVE IT
$RETT ;AND RETURN
END