.PSECT BYECHK .TITLE BYECHK LOG-OFF DISK ALLOCATION CHECKER .IDENT /V2.0.5/ .ENABL LC .NLIST BEX ;======================================================================== ; BYECHK.MAC ; ; Phil Hoffman ; Department of Chemistry ; Michigan State University ; East Lansing, MI 48824 ; 12-April-1983 ;------------------------------------------------------------------------ ; V2.0.2 - Modified to insure that any task running under the name TTn ; is aborted before the "real" BYE is run. All modifications flagged ; with the comment ; 2.0.2 . ; ; V2.0.3 - Eliminates complications due to tasks runs from VT0: in batch ; stream mode. V2.0.2 aborted "TTn" prior to running the real BYE. ; V2.0.3 is also capable of aborting "VTn". All modifications flagged with ; the comment ; 2.0.3 ; ; V2.0.4 - "Ignores" file open errors due to IE.WAC since that batch ; stream processor leaves the log file open in the user's directory, ; thereby preventing log-off once the user's entry in the queue has ; started execution. ; ; V2.0.5 - User device changed from DP2: to DP1:. Updated to reflect ; this change. ;======================================================================== .SBTTL Documentation -- General and Functional ;------------------------------------------------------------------------ ; BYECHK is a substitute for the BYE (log off) task, and inhibits log off ; attempts by a non-priviliged user if he/she has allocated more disk ; space than specifically allowed. Upon call, BYECHK first determines the ; identity of the user. All privileged users are immediately allowed to ; log off -- disk resources are not checked. For non-privileged users, ; BYECHK maintains an internal table (see the documentation for the USER ; macro in this code) of UICS. Each USER entry specifies the maximum ; number of blocks that may be allocated on a specific list of devices. ; Total allocation is defined as the SUM of the disk blocks allocated ; on ALL of the devices contained in the table entry for the current user. ; If the total allocation is less than or equal to the maximum specified ; in the table entry, then the "real" BYE task is spawned, and a normal ; log out procedure is performed. If the total allocation exceeds the ; the maximum, a warning message is printed, the log out is aborted, ; and the user is returned to monitor. Although BYECHK slaves the user's ; terminal upon invocation, the terminal is released if the total ; disk allocation is excessive and a return to monitor is called for. ; ; In order to determine total allocation, BYECHK must open all of the users ; files on the specified devices. If for any reason, BYECHK is unable to ; open a file because of an I/O or $DSW error, it is assumed that the ; disk allocation exceeds the maximum. The I/O or $DSW code is reported ; to the user, along with the name of the device on which it occurred. ; ; Because BYECHK deals with the login directory as opposed to the index ; file, any files not found in the directory will not be counted towards ; the total allocation. ; ; BYECHK may be aborted from any privileged terminal in the system (and ; hopefully not via a system crash executed manually by an enraged user). ;------------------------------------------------------------------------ .SBTTL Documentation -- Assembling BYECHK ;------------------------------------------------------------------------ ; BYECHK is assembled as follows: ; ; MAC BYECHK,BYECHK=MACROS/ML,LB:[1,1]EXEMC/ML,SY:[ugc,umc]BYECHK ; ; where MACROS/ML is a local macro library, distributed with BYECHK.MAC. ;------------------------------------------------------------------------ .SBTTL Documentation -- Task Building BYECHK ;------------------------------------------------------------------------ ; BYECHK is task built as follows: ; ; TKB BYECHK/PR,BYECHK=BYECHK,LB:[1,54]RSX11M.STB/SS ; / ; TASK=...BYE ; UNITS=2 ; ASG=SY0:1,TI0:2 ; LIBR=FCSRES:RO ; // ; ; Use of FCSRES is, of course, optional. ;------------------------------------------------------------------------ .SBTTL Documentation -- Installing BYECHK ;------------------------------------------------------------------------ ; REM BYE ; Remove the 'old' BYE ; INS BYECHK ; and install BYECHK in its place ; ; If the 'real' BYE.TSK is maintained in LB:[1,54], it may be necessary ; to edit the invocation string at address 'BYESTR' prior to assembling ; BYECHK. ;------------------------------------------------------------------------ ; .SBTTL MCALLs .MCALL UCBDF$,TCBDF$ .MCALL EXIT$S,FSRSZ$,FDBDF$,FDRC$A,FDOP$A,OPEN$R,CLOSE$ .MCALL DIR$,SPWN$ .MCALL CNCT$S,ABRT$S,WTSE$S,GLUN$ ; 2.0.2 .MCALL PUSH,POP,TEXT,QRWDEF ; (from MACROS.MLB) ; .SBTTL USER macro definition ;======================================================================== ; The USER macro generates an entry for a specified account, stating the ; maximum number of blocks of disc space which may be legally allocated upon ; log-off, and the system devices on which to search for those blocks. A ; trailing macro call to USER is required for account 0,0, which sets the ; default block limits for accounts not explicitly contained in the list. ; The format of the USER macro is as follows: ; ; USER UGC,UMC,BLKH,BLKL,DEVLST ; where ; UGC => is the user group account code ; UMC => is the user member account code ; BLKH => is the high-order word of the maximum number of ; allocated blocks to be allowed ; BLKL => is the low-order word of the maximum number of ; allocated blocks to be allowed ; DEVLST => is a list of devices to be checked. The user of ; physical device names is highly recommended, since ; local assignemnt tables have been cleared by BYE ; before BYECHK is invoked. ; NOTE: If a device list is omitted, no allocation ; limits are specified for the user. ; ; For example: ; ; USER 300,100 0.,1000. ; USER 300,200 0.,5000. DK0: ; USER 300,300 ; USER 0,0 0.,500. ; ; User [300,100] may allocate no more than 1000. blocks total on DP0: and ; DP1:. User [300,200] may allocate no more than 5000. blocks on DK0:. ; User [300,300] has no restriction placed upon his/her disk usage. All ; other users may allocate no more than 500. blocks (combined) on ; DK0:,DK1:,DK2:,DP0: and DP1: ;======================================================================== .MACRO USER UGC,UMC,BLKH,BLKL,DEVLST .BYTE UMC,UGC ; Store UIC USRLNK=. ; Linkage to next user entry .=.+2 ; Skip over linkage word .WORD BLKH,BLKL ; Store disk limits DEVCTR=. ; # of Devices to search .=.+2 ; Skip over # of devices word NDEVS=0 ; Init # of devs. to search .IF NB, ; If device list has been given .IRP DEV, ; Get next device from list NDEVS=NDEVS+1 ; Increment # of devices counter .NCHR DEVLEN,DEV ; Get length of this dev. name string .BYTE DEVLEN ; Store string length .ASCII \DEV\ ; and string .ENDM ; Loop until all devices stored .EVEN ; Force even address boundary .ENDC ENDUSR=. ; Save this loc. for next macro .=USRLNK ; Return to linkage pointer .WORD ENDUSR ; Specify forward linkage pointr .=DEVCTR ; Return to dev counter entry .WORD NDEVS ; Specify # of devices in this entry .=ENDUSR ; Return to the end of the macro .ENDM USER ;------------------------------------------------------------------------ .SBTTL Symbol Definitions and Working storage ;------------------------------------------------------------------------ LUNFDB=1 ; LUN for file access LUNTI0=2 ; LUN for the terminal ABOEFN=1 ; EFN for aborting task TT0 ; 2.0.2 ; BLOCKS: .BLKW 2 ; Running total of blocks allocated ASCBUF: .BLKB 20. ; Ascii working buffer ERRCNT: .BLKW 1 ; Error count during file access UCB: .BLKW 1 ; Storage for TI0: UCB address CW2SAV: .BLKW 1 ; Storage for 2nd UCB char word ; 2.0.2 TSKNAM: .BLKW 3 ; Task name storage for TTn (VTn) ; 2.0.3 R50NAM: .BLKW 2 ; Storage for RAD50 of TTn ; 2.0.2 ; TCBDF$ ; Define TCB offsets UCBDF$ ; Define UCB offsets FSRSZ$ 0,,BYECHK ; Allocate sufficient FSR space ; O.UIC=0 ; Offset to UIC in USER tables O.LNK=2 ; Offset to linkage in USER tables O.BLK=4 ; Offset to block limit in USER tables O.NUM=8. ; Offset to # of devs. in USER tables O.DEV=10. ; Offset to device list in USER tables ;------------------------------------------------------------------------ .SBTTL FDB's and Dataset Descriptors ;------------------------------------------------------------------------ DATDES: .BLKW 2 ; Reserved for name descriptor .WORD 0,0 ; Clear UIC field (use login default) .WORD WLDLEN,WLDADR ; File name descriptor ; WLDADR: .ASCII \*.*;*\ ; Wildcard filespec WLDLEN=.-WLDADR ; Filespec string length .EVEN ; FDB: FDBDF$ FDRC$A FD.RWM FDOP$A LUNFDB,DATDES,,FO.RD,FA.DLK ;------------------------------------------------------------------------ .SBTTL DPB'S ;------------------------------------------------------------------------ QRWDEF LUNTI0 ; Define the DPB for terminal I/O ; SPAWN: SPWN$ MCR...,,,,,,,,BYESTR,BYELEN ; Spawn real BYE task GETLUN: GLUN$ LUNTI0,LUNBUF ; Get Lun DPB ; 2.0.2 LUNBUF: .BLKW 6 ; Buffer for GLUN$ ; 2.0.2 ;------------------------------------------------------------------------ .SBTTL Ascii Messages ;------------------------------------------------------------------------ MSG1: TEXT ,MSG1L,2,0 MSG1A: TEXT ,MSG1AL,,0 MSG2: TEXT ,MSG2L MSG3: TEXT ,MSG3L MSG4: TEXT ,MSG4L MSG5: TEXT ,MSG5L MSG5A: TEXT ,MSG5AL ; ERRP: TEXT <.PARSE Failure>,ERRPL ERRF: TEXT <.FIND Failure>,ERRFL ERRO: TEXT ,ERROL ERRC: TEXT ,ERRCL ERRS: TEXT ,ERRSL ; BYESTR: .ASCII \RUN $BYE\ ; Invocation string for real BYE BYELEN=.-BYESTR ; and its length ; IOERR: TEXT ,IOERL,,0 DSWERR: TEXT <$DSW Error Code : >,DSWERL,,0 ; CRET: .BYTE 15 ; Ascii carriage return .EVEN SPACE: .BYTE 40,40 ; Ascii spaces ; 2.0.2 ;------------------------------------------------------------------------ .SBTTL USER Table ;------------------------------------------------------------------------ USERTB:: USER 1,20 USER 1,51 USER 1,254 USER 40,1 0.,500. USER 50,23 0.,2000. USER 50,24 0.,2000. USER 50,27 0.,2000. USER 50,30 0.,2000. USER 50,51 0.,2000. USER 50,54 0.,2000. USER 50,66 0.,2000. USER 50,73 0.,2000. USER 50,75 0.,2000. USER 50,76 0.,2000. USER 50,77 0.,2000. USER 50,111 0.,2000. USER 50,112 0.,2000. USER 50,150 0.,2000. USER 50,160 0.,2000. USER 50,170 0.,2000. USER 50,255 0.,2000. USER 50,366 0.,2000. USER 50,375 0.,500. USER 65,1 0.,2000. USER 65,47 0.,500. USER 65,57 0.,500. USER 100,100 0.,500. USER 200,300 0.,500. USER 300,1 0.,500. USER 300,300 0.,500. USER 301,21 0.,2000. USER 0,0 0.,500. ;======================================================================== .SBTTL ENTRY POINT ;======================================================================== BYECHK:: MOV $TKTCB,R0 ; Get TCB address for this task MOV T.UCB(R0),R0 ; and get UCB address for TI0: 2$: MOV U.RED(R0),R0 ; Chase the redirect pointer CMP R0,U.RED(R0) ; End of redirect chain reached? BNE 2$ ; NE => No - keep searching MOV R0,UCB ; EQ => Yes - save UCB address MOV U.CW2(R0),CW2SAV ; Save the characteristics word ; 2.0.2 BIS #U2.SLV,U.CW2(R0) ; and slave the terminal ; .SBTTL Identify the Current User ;------------------------------------------------------------------------ ; If the user is privileged, proceed directly to conventional log out. ; If not, check disk usage. ;------------------------------------------------------------------------ BIT #U2.PRV,U.CW2(R0) ; Is the user privileged? BEQ 4$ ; EQ => No - proceed with disk check JMP BYE ; NE => Yes - quit ;------------------------------------------------------------------------ ; Find an entry in the table of disk allocation limits for the ; current user. ;------------------------------------------------------------------------ 4$: MOV U.LUIC(R0),U.UIC(R0) ; Force current UIC to logon UIC MOV U.LUIC(R0),R0 ; Get logon UIC MOV R0,R1 ; Duplicate it in R1 CALL .WDFUI ; and set as default in $$FSR2 MOV #USERTB,R3 ; Point to user table 6$: TST (R3) ; End of user table (UIC 0,0)? BEQ 8$ ; Yes - handle the default entry CMP R0,(R3) ; Check logon UIC w/ table entry BEQ 8$ ; EQ => User entry found - continue MOV O.LNK(R3),R3 ; Get link to next user entry in table BR 6$ ; and continue ; 8$: MOV O.NUM(R3),R5 ; Get # of devices to search BNE 10$ ; NE => Search devices JMP BYE ; EQ => No alloc. limit - quit ; .SBTTL Determine Total Allocation By Current User ;------------------------------------------------------------------------ ; Determine the number of disk blocks allocated by this user on the devices ; specified in the table entry. ;------------------------------------------------------------------------ 10$: QWR #MSG1,#MSG1L ; Write 'checking' message CLR BLOCKS ; Clear current block allocation CLR BLOCKS+2 ; value CLR ERRCNT ; Clear error count MOV R3,R4 ; Point to the start of the device ADD #O.DEV,R4 ; list in the user entry ; MOV #FDB,R0 ; Point to the FDB MOV #FDB+F.FNB,R1 ; Point to its file name block MOV #DATDES,R2 ; Point to dataset descriptor ; 12$: CLR (R2) ; Clear dev name length in desciptor MOVB (R4)+,(R2) ; Set dev name length in descriptor MOV R4,2(R2) ; Point to dev name string QWR #SPACE,#1 ; Write leading space QWR 2(R2),(R2) ; and device name ADD (R2),R4 ; Move pointer to next dev. in table CALL .PARSE ; Parse filespec into the FNB BCC 16$ ; CC => No errors - continue CMPB F.ERR(R0),#IE.NSF ; NSF => No directory on this device BEQ 14$ ; NSF error ok - move on to next dev. QWR #CRET,#1 ; Send out leading QWR #ERRP,#ERRPL ; Write parse error message CALL ERROR ; Write out the error code INC ERRCNT ; Increment the error count 14$: BR 24$ ; Skip this device ; 16$: CALL .FIND ; Find first file to match *.*;* BCC 18$ ; CC => Found - continue CMPB F.ERR(R0),#IE.NSF ; All matches found? BEQ 24$ ; EQ => Yes - done w/ this device QWR #CRET,#1 ; Send out leading QWR #ERRF,#ERRFL ; Write find error message CALL ERROR ; Write out the error code INC ERRCNT ; Increment the error count BR 24$ ; Skip this device ; 18$: OPEN$R ; Open the file just found BCC 20$ ; CC => No errors - continue QWR #CRET,#1 ; Send out leading QWR #ERRO,#ERROL ; Write Error on Open message CALL ERROR ; Write out the error code CMPB F.ERR(R0),#IE.WAC ; Is error file accessed for write? ; 2.0.4 BEQ 16$ ; EQ => Yes - don't count this error ; 2.0.4 INC ERRCNT ; Increment the error count BR 22$ ; Ignore this file's block allocations 20$: ADD F.HIBK+2(R0),BLOCKS+2 ; Add blocks allocated for this ADC BLOCKS ; file to the running total ADD F.HIBK(R0),BLOCKS 22$: CLOSE$ ; Close the file BCC 16$ ; CC => No errors - get next file QWR #CRET,#1 ; Send out leading QWR #ERRC,#ERRCL ; Write Error on Close message CALL ERROR ; Write out the error code INC ERRCNT ; Increment the error count BR 16$ ; Move on to next file ; 24$: DEC R5 ; Dec. # of devs. to search BEQ 26$ ; EQ => All Done -- check results JMP 12$ ; NE => Loop until all devs searched ; 26$: QWR #CRET,#1 ; Send out leading QWR #MSG1A,#MSG1AL ; Write disk usage message MOV #ASCBUF,R0 ; Point to ascii buffer MOV #BLOCKS,R1 ; Point to # of blocks allocated CLR R2 ; Flag leading zero supression CALL $CDDMG ; Convert to decimal ascii MOVB #<'.>,(R0)+ ; Move in trailing period MOVB #<'/>,(R0)+ ; and slash MOV R3,R1 ; Point to user entry in table ADD #O.BLK,R1 ; and calc address of block limit CLR R2 ; Flag leading zero supression CALL $CDDMG ; Convert block limit to decimal ascii MOVB #<'.>,(R0)+ ; Put in a trailing period MOVB #15,(R0)+ ; and SUB #ASCBUF,R0 ; Determine length of the string QWR #ASCBUF,R0 ; Write disk usage figures ; .SBTTL Compare User Allocation With Specified Limits ;------------------------------------------------------------------------ ; Check total blocks allocated against specified limit ;------------------------------------------------------------------------ TST ERRCNT ; Were errors encountered? BEQ 28$ ; EQ => No - count the blocks QWR #MSG5,#MSG5L ; Write the warning QWR #MSG5A,#MSG5AL ; messages BR 32$ ; and assume overflow ; 28$: CMP BLOCKS,O.BLK(R3) ; Compare high-order words BGT 30$ ; GT => Too many blocks allocated CMP BLOCKS+2,O.BLK+2(R3) ; Compare low-order words BGT 30$ ; GT => Too many blocks allocated QWR #MSG3,#MSG3L ; LE => w/in limits - write 'ok' msg BR BYE ; and finish log out ; .SBTTL Handle Overallocation ;------------------------------------------------------------------------ ; Too many blocks allocated by the current user ;------------------------------------------------------------------------ 30$: QWR #MSG2,#MSG2L ; Write 'too many blocks' message 32$: QWR #MSG4,#MSG4L ; Write aborted log out message MOV UCB,R0 ; Get UCB for this terminal MOV CW2SAV,U.CW2(R0) ; Restore characteristics word ; 2.0.2 BR EXIT ; and quit ; .SBTTL Spawn the Real BYE task ;------------------------------------------------------------------------ ; Spawn the Real BYE task ;------------------------------------------------------------------------ BYE: MOV #TSKNAM,R0 ; Point to task name buffer ; 2.0.3 MOV SPACE,(R0) ; Clear task name buffer ; 2.0.3 MOV SPACE,2(R0) ; all 3 words ; 2.0.3 MOV SPACE,4(R0) ; 2.0.3 DIR$ #GETLUN ; Get LUN information for TI0: ; 2.0.2 BCS 10$ ; CS => Errors - just go for the bye ; 2.0.2 MOV G.LUNA+LUNBUF,(R0)+ ; Move in terminal name ; 2.0.3 MOVB G.LUNU+LUNBUF,R1 ; Get term. # from get LUN buffer ; 2.0.2 CLR R2 ; Flag leading zero supression ; 2.0.2 CALL $CBTMG ; Convert term # to ascii ; 2.0.2 MOV #TSKNAM,R0 ; Point to ascii task name ; 2.0.2 MOV #1,R1 ; Flag all characters ok ; 2.0.2 CALL $CAT5B ; Convert ascii to RAD50 ; 2.0.2 MOV R1,R50NAM ; Move result into R50 buffer ; 2.0.2 MOV #1,R1 ; Reset conversion flag ; 2.0.2 CALL $CAT5B ; Convert 2nd word to task name ; 2.0.2 MOV R1,R50NAM+2 ; and move it out ; 2.0.2 CNCT$S #R50NAM,#ABOEFN ; Connect to that task ; 2.0.2 BCS 10$ ; CS => Task probably not active ; 2.0.2 ABRT$S #R50NAM ; Task active - abort it ; 2.0.2 WTSE$S #ABOEFN ; Wait for abort to complete ; 2.0.2 ; 10$: MOV UCB,R0 ; Get UCB for this terminal BIS #U2.PRV,U.CW2(R0) ; and set prv for spawn DIR$ #SPAWN ; Spawn the task BCC EXIT ; CC => No errors QWR #ERRS,#ERRSL ; Write spawn error message ; .SBTTL EXIT POINT ;------------------------------------------------------------------------ ; Exit Point ;------------------------------------------------------------------------ EXIT: EXIT$S ; EXIT ; ; ; ; ;======================================================================== ; Subroutine ERROR ; ERROR reports file related errors to the terminal. Upon call, it is ; assumed that R0 contains the address of the FDB to which the error ; pertains. No registers are modified. ;======================================================================== ERROR: TST F.ERR(R0) ; I/O or $DSW error? BMI 2$ ; Branch to handle $DSW QWR #IOERR,#IOERL ; Write I/O error message BR 4$ ; Decode the error code 2$: QWR #DSWERR,#DSWERL ; Write $DSW error message ; 4$: CLR ASCBUF ; Clear the ascii conversion buffer CLR ASCBUF+2 CLR ASCBUF+4 PUSH ; Save some registers MOVB F.ERR(R0),R1 ; Get the error code MOV #ASCBUF,R0 ; Point to the buffer CLR R2 ; Flag leading zero suppression CALL $CBTMG ; Convert to ascii MOVB #CR,(R0)+ ; Put a trailing in the buffer MOVB #LF,(R0) ; as well as a QWR #ASCBUF,#6 ; Write the error code POP ; Restore the registers RETURN ; ; ; ; .END BYECHK