.TITLE WHO - MCR WHO COMMAND .IDENT /02/ .ENABL LC .NLIST BEX ;+ ; MODULE: WHO ; VERSION: 02 ; BY: Greg Thompson (Informatics/PMI) ; DATE: 6/16/78 ; ; This command display a list of userids logged-in, their ; terminal numbers they are logged-in to and the tasks they ; have active. ; ; Example: ; >WHO ; TT0: [0,0] [200,200] RSX Operators console ; TT3: [6,6] [6,6] RKPGAT, Greg 19:40:44 16-JUN-78 ; ...MCR ...WHO TKBT3 ; VT0: [6,6] [6,6] RKPGAT, Greg 19:40:44 16-JUN-78 ; > ;- .MCALL QIOW$,DIR$,WTSE$S,OPEN$R,CLOSE$,READ$,MRKT$ .MCALL EXIT$S,FDOF$L,DEVDF$ FDOF$L DEVDF$ ; ; Constants ; LUNTI = 5 ; TI Logical Unit Number LUNSY = 2 ; SY Logical Unit Number EFTI = 1 ; TI Event Flag EFSY = 2 ; SY Event Flag EFMT = 3 ; Mark Time Event Flag OPNCNT = 5 ; Number of times to try to open HT = 011 ; ASCII tab character BUFL = 80. ; Length of terminal buffer ; MSG: .BLKB BUFL ; Message to terminal buffer ERR1: .ASCIZ <15>/WHO -- Not multi-user system./ ERR2: .ASCIZ <15>/WHO -- Account file open failure./ OPR: .ASCIZ /RSX Operators console/ UUN: .ASCIZ // .EVEN ; ODPB: QIOW$ IO.WVB,LUNTI,EFTI,,,, ; TI output dpb FDPB: QIOW$ IO.RVB,LUNSY,EFSY,,IOSB,,<$ACTBF,$BFLEN,,,1> IOSB: .BLKW 2 ; I/O status block FILOPN: .WORD 0 ; File open flag 0-no, 1-yes OPNERR: .WORD 0 ; Account file open error flag UCBCNT: .WORD 0 ; Number of TT UCBs GRP: .BLKB 3 ; Group code (ASCII) MEM: .BLKB 3 ; Member code (ASCII) PARAM: .BLKW 3 ; Parameter block for time conversion TSKL: .WORD 0 ; Used in FTASK MKT: MRKT$ EFMT,60.,1 ; Wait for one second ; ; WHO command code ; $WHOEP: CLR FILOPN ; Indicate file not open CLR OPNERR ; Init open error counter ; ; Attach TI: ; MOV #ODPB,R4 ; Get ptr to output DPB MOV #IO.ATT,Q.IOFN(R4) ; Set function to attach DIR$ R4 ; Do the attach MOV #IO.WVB,Q.IOFN(R4) ; Reset function to write BIT #FE.MUP,$FMASK ; Multi-User protection? BNE 10$ ; Branch if yes MOV #ERR1,R0 ; Not multi-user system error JMP ERROR ; Go issue error ; ; Open account file ; 10$: OPEN$R #$ACTFL,,,#FD.RWM ; Open account file for reading BCC 40$ ; Branch if file opened INC OPNERR ; Count number of times it failed CMP OPNERR,#OPNCNT ; Has it failed enough times? BLT 30$ ; Branch if not 20$: MOV #ERR2,R0 ; Get ptr to open error message JMP ERROR ; Issue error message ; 30$: DIR$ #MKT ; Set EF in a second BCS 20$ ; Exit now if error WTSE$S #EFMT ; Wait for it BR 10$ ; Try to open file again ; ; Start scanning the DCBs ; 40$: INC FILOPN ; Indicate account file open MOV $DEVHD,R5 ; R5 points to current DCB JMP 80$ ; Start checking DCBs ; ; Check a UCB out for being a logged-in tty device ; 50$: BIT #DV.TTY,U.CW1(R3) ; Is this device a tty? BEQ 70$ ; Try next one if not BIT #U2.LOG,U.CW2(R3) ; Is there anyone logged on? BNE 70$ ; Try next one if not MOV R3,-(SP) ; Save UCB pointer on stack MOV #MSG,R0 ; R0 points at line buffer CALL $FMTDV ; Output device name and number MOVB #HT,(R0)+ ; Output a tab MOVB #'[,(R0)+ ; and a bracket MOV PC,R2 ; Generate leading zeros MOV R0,-(SP) ; Save buffer pointer MOV #GRP,R0 ; Put group code (ASCII) in GRP MOVB U.LUIC+1(R3),R1 ; Get binary group code CALL $CBTMG ; Convert to octal MOV #MEM,R0 ; Put member code (ASCII) in MEM MOVB U.LUIC(R3),R1 ; Get binary group code CALL $CBTMG ; Convert to octal MOV (SP)+,R0 ; Restore terminal buffer pointer ; CALL LUIC ; CALL CURUIC ; CALL SEARCH ; Look for [GRP,MEM] in account file BCS 60$ ; "" if not there MOV R3,R1 ; Point at last name ADD #A.LNM,R1 ; MOV #14.,R2 ; Max length is 14. bytes CALL MOVEC ; Output the string MOVB #',,(R0)+ ; Output a comma MOVB #' ,(R0)+ ; Output a blank MOVB #' ,(R0)+ ; Output a blank MOV R3,R1 ; Point at first name ADD #A.FNM,R1 ; MOV #12.,R2 ; Max length is 12. bytes CALL MOVEC ; Output the string MOVB #HT,(R0)+ ; Output a tab MOVB #' ,(R0)+ ; Then a space MOV #PARAM,R1 ; Set ptr to parameter block CLR (R1)+ ; Clear it out CLR (R1)+ ; CLR (R1)+ ; DEC R1 ; Now insert time parameters MOVB A.LDAT+5(R3),-(R1) ; Insert seconds DEC R1 ; MOVB A.LDAT+4(R3),-(R1) ; Insert minutes DEC R1 ; MOVB A.LDAT+3(R3),-(R1) ; Insert hours MOV #3,R2 ; Output in HH:MM:SS format CALL $TIM ; Output time MOVB #' ,(R0)+ ; Space is next MOV #PARAM,R1 ; Point back at parameter block CLR (R1)+ ; Clear it out CLR (R1)+ ; CLR (R1)+ ; DEC R1 ; Now insert date parameters MOVB A.LDAT(R3),-(R1) ; Insert day DEC R1 ; MOVB A.LDAT+1(R3),-(R1) ; Insert month DEC R1 ; MOVB A.LDAT+2(R3),-(R1) ; Insert year CALL $DAT ; Output date BR 65$ ; Done ; 60$: MOV (SP),R3 ; Restore UCB pointer MOV #OPR,R1 ; Assume its the operator TST U.LUIC(R3) ; Is it the operator? BEQ 62$ ; Branch if it is MOV #UUN,R1 ; Output account unknown message 62$: CALL MOVE ; Move the string to the buffer 65$: CLRB (R0)+ ; Make sure there is zero at end MOV #MSG,R0 ; Retrieve addr of message CALL WRITE ; Write out message MOV (SP)+,R3 ; Restore UCB pointer CALL FTASK ; Display its active tasks 70$: ADD D.UCBL(R5),R3 ; Point at next UCB DEC UCBCNT ; Is there another UCB? BGT 90$ ; Branch if there is 75$: MOV D.LNK(R5),R5 ; Try next DCB BEQ EXIT ; If zero we are done 80$: MOV D.UCB(R5),R3 ; Get ptr to first UCB MOVB D.UNIT+1(R5),R1 ; Compute number MOVB D.UNIT(R5),R2 ; of units on SUB R2,R1 ; the TT DCB INC R1 ; MOV R1,UCBCNT ; Save number of UCBs BEQ 75$ ; If no UCBs - try next DCB 90$: JMP 50$ ; Check first UCB ; ; Exit and error processing ; ERROR: CALL WRITE ; Write out error message EXIT: MOV #ODPB,R4 ; Point R4 at output DPB MOV #IO.DET,Q.IOFN(R4) ; Set function to detach DIR$ R4 ; Detach from terminal MOV $TKTCB,R0 ; TCB addr -> R0 MOV T.UCB(R0),R0 ; UCB addr -> R0 BIC #U2.SLV,U.CW2(R0) ; Un-slave the terminal TST FILOPN ; Is the account file open? BEQ 10$ ; Branch if not CLOSE$ #$ACTFL ; Yes, close it 10$: EXIT$S ; And exit ; ; Write a message to the terminal ; ; Enter with: ; ; R0 -> message string terminated with a zero ; ; Returns with: ; ; R0,R1 - Modified ; R4 -> ODPB ; WRITE: MOV R0,R1 ; Copy buffer address 10$: TSTB (R1)+ ; End of message? BNE 10$ ; No, loop till end SUB R0,R1 ; Compute length MOV #ODPB,R4 ; Get output DPB address MOV R0,Q.IOPL(R4) ; Set buffer address MOV R1,Q.IOPL+2(R4) ; Set buffer length DIR$ R4 ; Write message out RETURN ; Return to caller ; ; Move a zero terminated string to the output buffer ; ; Enter with: ; ; R0 -> Output buffer ; R1 -> String to move terminated with a zero ; MOVE: MOVB (R1)+,(R0)+ ; Move a byte BNE MOVE ; Keep moveing till zero reached DEC R0 ; Dont move the zero RETURN ; Return ; ; Move a string (max length given) to output buffer ; ; Enter with: ; ; R0 -> Output buffer ; R1 -> String to move ; R2 = Number of bytes to move ; MOVEC: MOVB (R1)+,(R0) ; Move a byte BITB #137,(R0) ; Is it end of string BEQ 10$ ; Done if end of string INC R0 ; Point at next output byte DEC R2 ; Is that all? BNE MOVEC ; Do more if not 10$: RETURN ; Return ; ; Search file for account ; ; Output: ; R2, R4 modified ; R3 - Address of account entry ; Carry clear - account found ; Carry set - account not found ; SEARCH: MOV R3,-(SP) ; Save R3 MOV #FDPB,R4 ; Get file DPB address MOV #1,Q.IOPL+10(R4) ; Set to start at VBN 1 CLR Q.IOPL+6(R4) ; 10$: DIR$ R4 ; Read next block MOV IOSB+2,R2 ; Get count of words read BEQ 40$ ; Zero, no words read MOV #$ACTBF,R3 ; Get buffer address 20$: CMP GRP,A.GRP(R3) ; Do group codes match? BNE 30$ ; Branch if not CMP GRP+2,A.GRP+2(R3) ; Check next word too BNE 30$ ; Branch if no match CMP GRP+4,A.GRP+4(R3) ; Check member codes also BNE 30$ ; Branch if no match TST (SP)+ ; Restore R3 CLC ; Indicate entry found RETURN ; Return successful ; 30$: ADD #A.LEN,R3 ; Point to next entry SUB #A.LEN,R2 ; Compute words left in buffer BHI 20$ ; Loop, if more left 40$: CMPB #IE.EOF,IOSB ; End of file? BEQ 50$ ; Branch if yes TSTB IOSB ; Any errors? BMI 50$ ; Branch if yes ADD #$BFLEN/512.,Q.IOPL+10(R4) ; Point to next VBN ADC Q.IOPL+6(R4) ; BR 10$ ; Read next block in ; 50$: MOV (SP)+,R3 ; Restore R3 SEC ; Entry not found RETURN ; Return unsuccessful ; ; Display all tasks active on a given UCB ; ; Enter with: R3 -> UCB ; FTASK: MOV #MSG,R0 ; Init buffer pointer CALL $SWSTK,50$ ; Switch to system stack MOV $TSKHD,R4 ; Get ptr to first task name 10$: BIT #TS.EXE,T.STAT(R4) ; Is the task active? BEQ 20$ ; Yes, check its UCB BIT #TS.OUT,T.STAT(R4) ; Not active but still in memory? BNE 30$ ; No, try next task 20$: CMP T.UCB(R4),R3 ; Is its TI: our UCB? BNE 30$ ; No, try next one MOVB #HT,(R0)+ ; Yes, output a tab MOV T.NAM(R4),R1 ; and then the task name CALL $C5TA ; MOV T.NAM+2(R4),R1 ; Both halves of it CALL $C5TA ; 30$: MOV T.TCBL(R4),R4 ; Get link to next TCB TST T.TCBL(R4) ; Null task? BNE 10$ ; No, check it MOV R0,TSKL ; Yes, return buf ptr to user state RETURN ; Return to users state ; 50$: MOV TSKL,R0 ; Get buffer pointer CMP #MSG,R0 ; Did it find any tasks? BEQ 60$ ; No CLRB (R0)+ ; Yes, terminate string MOV #MSG,R0 ; and write task names to TI: CALL WRITE ; 60$: RETURN ; ; ; OUTPUT LOGIN UIC ; LUIC: CLR R2 ; Now suppress leading zeros MOVB U.LUIC+1(R3),R1 ; Get group code again CALL $CBTMG ; Output group number MOVB #',,(R0)+ ; Comma in-between CLR R2 ; Suppress leading zeros MOVB U.LUIC(R3),R1 ; Get member code again CALL $CBTMG ; Output member number MOVB #'],(R0)+ ; Put in trailing bracket MOVB #HT,(R0)+ ; Tab is next RETURN ; ; Output current UIC for terminal ; CURUIC: MOVB #'[,(R0)+ ; Put in leading bracket CLR R2 ; Now suppress leading zeros MOVB U.UIC+1(R3),R1 ; Get group code for current uic CALL $CBTMG ; Output group number MOVB #',,(R0)+ ; Comma in-between CLR R2 ; Suppress leading zeros MOVB U.UIC(R3),R1 ; Get member code for current uic CALL $CBTMG ; Output member number MOVB #'],(R0)+ ; Put in trailing bracket MOVB #HT,(R0)+ ; Tab is next RETURN ; .END $WHOEP ; End of program