.TITLE SYSUSERS ; ; CONTINUOUS SHOW USERS ; ; .SBTTL MACRO DEFINITIONS $SYIDEF $JPIDEF $DVIDEF $PRVDEF $QIODEF $IODEF $SSDEF .SBTTL DATA DEFINITIONS .PSECT STATIC,NOEXE,LCL HDRSTR: .BYTE 0,0,0,0,0,0,0,0 ; NULL BYTES FOR REFRESH .ASCII %#6VMS % VERSION:.BLKB 4 .ASCII % users: % .ASCII %% .ASCII %Term Username PID Login Executing Image% .ASCII % % METER: .ASCII /CPU % idle / .ascii /(0x/ .ASCII /tqqqqnqqqqnqqqqnqqqqnqqqqn/ .ASCII /qqqqnqqqqnqqqqnqqqqnqqqqu(B/ .ASCII /0 10 20 30 40 50/ .ASCII / 60 70 80 90 100/ HDRLEN: .LONG HDRLEN-HDRSTR MTRLEN: .LONG HDRLEN-METER ; EXIPOS: .ASCII // EXILEN: .LONG EXILEN-EXIPOS CEOS: .ASCII /EEE/ .ASCII /EEE/ .ASCII /EEE/ .ASCII /EEE/ .ASCII /EEE/ .ASCII /EEE/ .ASCII /E/ ; ATIMENOW: .LONG 23 ; LONG WORD SIZE .ADDRESS TIMBUF ; ADDRESS OF TIME BUFFER MLEN: .LONG 1 TTYDSC: .LONG 5 .ADDRESS SYSTRM SYSTRM: .ASCII /_TTB4:/ ; COMPUTER ROOM TERMINAL MSGDSC: .LONG 80 .ADDRESS MSGBUF MSGBUF: .BLKB 80. SYIERR: .ASCII /ERROR IN $GETSYI/ SYIELN: .LONG SYIELN-SYIERR ; DVIERR: .ASCII /ERROR IN $GETDVI/ DVIELN: .LONG DVIELN-DVIERR ; PRVERR: .ASCII /YOU NEED GROUP & WORLD PRIVILEGES TO RUN THIS PROGRAM/ PRVELN: .LONG PRVELN-PRVERR ; JPIERR: .ASCII /ERROR IN $GETJPI/ JPIELN: .LONG JPIELN-JPIERR ; ASCERR: .ASCII /ERROR IN $ASCTIM/ ASCELN: .LONG ASCELN-ASCERR ; ALOERR: .ASCII /TTB4: IS NOT AVAILABLE FOR OUTPUT/ ALOLEN: .LONG ALOLEN-ALOERR ; QIOERR: .ASCII /ERROR IN $QIO/ QIOELN: .LONG QIOELN-QIOERR ; NULERR: .ASCII /ERROR IN FNDNUL/ NULLEN: .LONG NULLEN-NULERR ; OUTFMT: .ASCID "!/!AS !AS !XL !AS !AS" ; FMT FOR OUTPUT LINE USRFMT: .ASCID "!2" A01SEC: .ASCID /0 00:00:01.00/ ; 01 SEC TIMER (ASCII) A05SEC: .ASCID /0 00:00:05.00/ ; 05 SEC TIMER (ASCII) ; ; GRPWLD: .LONG <1@PRV$V_GROUP>!<1@PRV$V_WORLD> ; SET PROC/PRIV=(GROUP,WORLD) .LONG 0 ; NEEDED FOR $GETJPI ATTOFF: .ASCII // ATTLEN: .LONG ATTLEN-ATTOFF ;;;;; .PSECT LCLDTA,WRT,LCL,NOEXE TIMSTR: .ASCII // TIMBUF: .BLKB 20 ; TIME RETURNED HERE LOPOFF: .BLKB 4 ; LOPP OFF THE HUNDRETHS OD SECONDS DTAREA: .ASCII // BUFLEN: .LONG BUFLEN-TIMSTR ; TRMDSC: .LONG 5 .ADDRESS TERM TERM: .BLKW 1 DZ: .BLKB 1 UNIT: .BLKB 1 COLON: .BYTE ^A/:/ ; CURUSERS: .BLKB 1 ; NUMBER OF CURRENT USERS ; INIOSB: .BLKQ 1 ; TOTLEN: .BLKW 2 ; FAODESC: BLEN: .LONG 1920. BADR: .ADDRESS OUTLIN OUTLIN: .BLKB 1920. ; ASTPRM: .LONG 0 ; COUNT THE NUMBER OF TIMER AST'S NUDSC: .LONG 30 ; FAO DESC FOR NUMBER OF USERS .ADDRESS NUBUF NUBUF: .BLKB 30 ; B01SEC: .BLKQ 1 ; (BINARY) DELTA TIME 01 SEC B05SEC: .BLKQ 1 ; (BINARY) DELTA TIME 05 SECS INBUF: .BLKB 4 ERRCOD: .BLKL 1 ; ERRCOD FOR OUTPUT OLDPRI: .BLKL 1 ; OLD PRIORITY FOR RESTORE ON EXIT CEOSLN: .BLKL 1 ; LENGTH OF CLEAR SCREEN STRING FIRST: .BLKL 1 ; FIRST TIME THRU NULL_PID: .BLKL 1 ; PID OF NULL PROCESS FOR IDLMTR ; USRDSC: .LONG 12 .ADDRESS USERNAME USERNAME: .BLKB 12 ; LGIBIN: .BLKQ 1 LGIDSC: .LONG 11 ; LONG WORD SIZE .ADDRESS LGIBUF ; ADDRESS OF TIME BUFFER LGIBUF: .BLKB 11 LOGDSC: .LONG 5 ; LOPPED OFF SECS & 100THS OF SECS .ADDRESS LGIBUF ; IMGDSC: IMGLEN: .BLKL 1 .ADDRESS IMAGNAME IMAGNAME: .BLKB 128 TTYNAM: .BLKB 7 TTYLEN: .BLKL 1 .ADDRESS TTYNAM ; CIDSC: CILEN: .BLKW 2 ; DESCRIPTOR FOR CONVERTED CIADR: .BLKL 1 ; IMAGE NAME DCLDSC: .LONG 11 .ADDRESS DCLTXT DCLTXT: .ASCII /DCL or idle/ SUSTXT: .ASCII /SUSPENDED or MWAIT - no image info available/ SUSDSC: .LONG SUSDSC - SUSTXT .ADDRESS SUSTXT .PAGE .SBTTL SYSTEM SERVICE DATA STRUCTURES ; .PSECT SYILST,WRT,LCL,NOEXE ; $GETSYI ITEM LIST TO RETRIEVE THE VERSION NUMBER ; SYILST: .WORD 4 .WORD SYI$_VERSION .ADDRESS VERSION .LONG 0 .LONG 0 ; .PSECT DVILST,WRT,LCL,NOEXE ; $GETDVI ITEM LIST TO RETRIEVE THE PID ; DVILST: .WORD 4 .WORD DVI$_PID .ADDRESS PID .LONG 0 .LONG 0 PID: .BLKL 1 ; .PSECT JPILST,WRT,LCL,NOEXE ; $GETJPI ITEM LIST TO RETRIEVE USERNAME, LOGIN TIME, IMAGE NAME ; JPILST: .WORD 12 .WORD JPI$_USERNAME .ADDRESS USERNAME .LONG 0 ; DONT NEED RETURN LENGTH .WORD 8 .WORD JPI$_LOGINTIM .ADDRESS LGIBIN .LONG 0 ; DONT NEED RETURN LENGTH .WORD 128 .WORD JPI$_IMAGNAME .ADDRESS IMAGNAME .ADDRESS IMGLEN .WORD 7 ; TERMINAL NAME FOR VERIFICATION .WORD JPI$_TERMINAL .ADDRESS TTYNAM .ADDRESS TTYLEN .LONG 0 ; END OF LIST ; .SBTTL TERMINAL CHANNEL /COMMON/ .PSECT TTYOUT RD,WRT,GBL,OVR,NOEXE ; DATA NECCESSARY TO DO TTY OUTPUT TTCHAN: .BLKW 1 MSGLEN: .BLKW 1 ; MSGLEN FOR SUMMARY OUTPUT FAOLEN: .BLKW 1 IOSB: .BLKQ 1 OUTDSC: OUTLEN: .LONG 250. .ADDRESS OUTBUF OUTBUF: .BLKB 250. OUTPUT: .ASCID /SYS$OUTPUT/ .PAGE .SBTTL SET-UP AND INIT CODE .PSECT SYSUSERS,EXE,RD,NOWRT .ENTRY SYSUSERS,^M<> START: $ALLOC_S DEVNAM=TTYDSC CMPL #SS$_NORMAL,R0 BEQL GETSYI JMP ERRALO GETSYI: $GETSYI_S EFN=#1,ITMLST=SYILST,IOSB=IOSB ; GET VMS VERSION BLBS R0,WAITSY JMP ERRSYI WAITSY: $WAITFR_S EFN=#1 ; WAIT FOR COMPLETION SETQIO: $ASSIGN_S DEVNAM=TTYDSC,CHAN=TTCHAN ; ASSIGN SYS$OUTPUT $SETPRV_S ENBFLG=#1,PRVADR=GRPWLD ; SET PRIVILEGES NEEDED CMPL #SS$_NORMAL,R0 BEQL PRVSOK JMP ERRPRV PRVSOK: CVTTIM: $BINTIM_S TIMBUF=A01SEC,TIMADR=B01SEC ; CVT 1 SEC TIMER $BINTIM_S TIMBUF=A05SEC,TIMADR=B05SEC ; CVT 5 SEC TIMER PUSHAL NULL_PID CALLS #1,FNDNUL ; GET THE NULL PROCESS PID TSTL R0 ; SEE IF IT WAS SUCCESSFUL BGTR READ1 JMP ERRNUL ; set up read input ast's ; make sure one is pending ; READ1: CLRQ INIOSB CLRB INBUF $QIO_S CHAN=TTCHAN,- FUNC=#IO$_READVBLK!IO$M_CVTLOW!IO$M_PURGE!IO$M_NOECHO,- P1=INBUF,P2=#1,- ASTADR=CASE3,ASTPRM=#03,IOSB=INIOSB CMPL R0,#SS$_NORMAL BEQL READ1A JMP ERRQIO ; ; OUTPUT HEADER ; READ1A: $QIO_S CHAN=TTCHAN,- FUNC=#IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH,- P1=HDRSTR,P2=HDRLEN,P4=#0,IOSB=IOSB $ASCTIM_S TIMBUF=ATIMENOW,CVTFLG=#0 BLBS R0,TIMOK1 JMP ERRASC TIMOK1: MOVL #0,LOPOFF ; MOVE NULLS OVER HUNDRETHS OF SECS $QIO_S CHAN=TTCHAN,- FUNC=#IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH,- P1=TIMSTR,P2=BUFLEN,P4=#0,IOSB=IOSB ; FIRST TIME FALL THRU CASE STMT .PAGE .SBTTL MAIN LOOP .SBTTL - CASE STMT 1-2 AWAKE: CASEL ASTPRM,#1,#2 JMPTBL: .WORD DOIDLE-JMPTBL ; 1 = 1 SEC TIMER UPDATE CPU % IDLE .WORD REFRSH-JMPTBL ; 2 = 5 SEC TIMER REFRESH USERS ; .WORD ABORT-JMPTBL ; 3 = QIO INPUT AST .SBTTL ----- CASE2 - 5 SECOND REFRESH OF SCREEN REFRSH: $CANTIM_S REQIDT=#1 CLRL ASTPRM $ASCTIM_S TIMBUF=ATIMENOW,CVTFLG=#0 BLBS R0,OUTTIM JMP ERRASC outtim: MOVL #0,LOPOFF ; MOVE NULLS OVER HUNDRETHS OF SECS $QIO_S CHAN=TTCHAN,- FUNC=#IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH,- P1=TIMSTR,P2=BUFLEN,P4=#0,IOSB=IOSB .SBTTL SPECIAL HANDLING FOR OPA0: SETCNS: MOVW #^A/OP/,TERM ; DO THE CONSOLE (OPA0:) MOVB #^A/A/,DZ MOVB #^A/0/,UNIT CLRB CURUSERS ; CLEAR NUMBER OF USERS GETOPA0: ; CHECK THE CONSOLE $GETDVI_S EFN=#1,- DEVNAM=TRMDSC,- ITMLST=DVILST,- IOSB=IOSB ; GET THE PID FOR THIS TERM BLBS R0,WAIT0P1 JMP ERRDVI WAIT0P1: $WAITFR_S EFN=#1 ; WAIT FOR COMPLETION MOVL PID,R2 ; TEST TO SEE IF A PID WAS RETURNED BNEQ GETJPI ; YES FINISH GETTING INFO FOR CONSOLE JMP INIDZS ; NO INIT FO DZ'S .PAGE .SBTTL GET INFO FOR EACH TERMINAL GETDVI: $GETDVI_S EFN=#1,- DEVNAM=TRMDSC,- ITMLST=DVILST,- IOSB=IOSB ; GET THE PID FOR THIS TERM BLBS R0,WAIT01 JMP ERRDVI WAIT01: $WAITFR_S EFN=#1 ; WAIT FOR COMPLETION MOVL PID,R2 ; TEST TO SEE IF A PID WAS RETURNED BNEQ GETJPI ; IF NOT = 0 THEN PROCEED JMP CKUNIT ; IF = 0 THEN CHECK NEXT GETJPI: $GETJPI_S EFN=#2,- PIDADR=PID,- ITMLST=JPILST,- IOSB=IOSB CMPL R0,#SS$_NORMAL BEQL WAIT02 ; IF SUCCESS, WAIT FOR COMPLETION CMPL R0,#SS$_NOPRIV ; SEE IF NO PRIVILEGE BNEQ CKSUS ; EXIJPI: JMP ERRJPI ; NO PRIVILEGE OUTPUT ERROR MESSAGE CKSUS: CMPL R0,#SS$_SUSPENDED ; IS PROC SUSPENDED OR IN MWAIT BNEQ EXIJPI ; IF NOT THIS ASSUME SOME OTHER ERROR MOVQ SUSDSC,CIDSC ; COPY THE SUSPENDED MSG JMP FMTOUT WAIT02: $WAITFR_S EFN=#2 CMPC3 #4,TERM,TTYNAM ; SEE IF DETACHED PROCESS BEQL INCUSR ; USING THIS TERMINAL JMP CKUNIT ; YES - CHECK NEXT INCUSR: INCB CURUSERS ; BUMP UP COUNT FOR DISPLAY CVTIME: $ASCTIM_S TIMADR=LGIBIN,CVTFLG=#1,TIMBUF=LGIDSC ; CVT LOGIN TIME BLBS R0,CVTIMG JMP ERRASC CVTIMG: MOVQ IMGDSC,R0 ; SEE IF IMAG NAME RETURNED CMPL #0,R0 ; IMAGE NAME LENGTH = 0 ? BNEQ MOVMSG ; NO - LEAVE IMAGE NAME ALONE MOVQ DCLDSC,R0 ; YES - MOVE "DCL or idle" MSG MOVMSG: MOVQ R0,CIDSC FMTOUT: ; FMT THE OUTPUT LINE FOR THIS ENTRY $FAO_S CTRSTR=OUTFMT,OUTLEN=FAOLEN,OUTBUF=FAODESC,- P1=#TRMDSC,P2=#USRDSC,P3=PID,P4=#LOGDSC,P5=#CIDSC ADDW FAOLEN,BADR ; ADJUST BUFF ADDR TO NEXT FREE BYTE ADDW FAOLEN,TOTLEN ; KEEP TRACK OF TOTAL # OF BYTES .PAGE .SBTTL SET-UP FOR NEXT TERMINAL CKUNIT: CMPW #^A/OP/,TERM ; TEST TO SEE IF WERE DOING THE CONSOLE BNEQ MIDTTS ; NO - WE'RE IN THE MIDDLE OF TT'S JMP INIDZS ; YES INIT TO DZ MIDTTS: SOBGTR R4,INCUNIT ; CHECK IF ANY MORE TERMINALS ; ON THIS DZ CKDZ: SOBGTR R5,NEXTDZ ; CHECK IF ANY MORE DZ'S JMP FINIS NEXTDZ: MOVL #8,R4 ; LOAD # OF TERMINALS INCB DZ ; CHANGE DZ DESIGNATION MOVB #^A/0/,UNIT ; RESET UNIT TO "0" FOR FALL THRU JMP GETDVI ; DO THE NEXT TERMINAL INCUNIT: INCB UNIT ; BUMP UP THE ASCII UNIT NUMBER JMP GETDVI ; DO THE NEXT TERMINAL INIDZS: MOVW #^A/TT/,TERM ; DO THE CONSOLE (OPA0:) MOVB #^A/A/,DZ MOVB #^A/0/,UNIT MOVL #4,R5 ; NUMBER OF DZ'S (A-D) MOVL #8,R4 ; TERMINALS PER DZ JMP GETDVI .PAGE .SBTTL CLEAN-UP ALL TERMINALS DISPLAYED FINIS: OUTIT: $QIO_S CHAN=TTCHAN,- FUNC=#IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH,- P1=OUTLIN,P2=TOTLEN,P4=#0,IOSB=IOSB CLRW TOTLEN MOVAB OUTLIN,BADR MOVZBL CURUSERS,R6 ; CALCULATE HOW MANY LINES TO CLEAR SUBL3 R6,#19.,CEOSLN ; 19 - CURUSERS MULL2 #6.,CEOSLN ; 6 CHARS PER CLEAR LINE STRING $QIO_S CHAN=TTCHAN,- FUNC=#IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH,- P1=CEOS,P2=CEOSLN,P4=#0,IOSB=IOSB ;CLR LINES $FAO_S CTRSTR=USRFMT,OUTLEN=FAOLEN,- OUTBUF=NUDSC,P1=CURUSERS ; FMT # USERS $QIO_S CHAN=TTCHAN,- FUNC=#IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH,- P1=NUBUF,P2=FAOLEN,P4=#0,IOSB=IOSB ; OUTPUT # USERS IS1: TSTL FIRST BNEQ NOT1ST .SBTTL SYNCHRONIZE TO 5 SECOND INTERVALS MOVL #-1,FIRST PUSHL NULL_PID ; PUSH PID OF NULL PROCESS CALLS #1,IDLMTR $SETPRI_S PRI=#16.,PRVPRI=OLDPRI ; RAISE PRIORITY TO REAL TIME CALLS #0,SYNCH ; SYNCHRONIZE TO 5 SEC INTERVALS $SETPRI_S PRI=#5 ; LOWER PRIORITY TO 5 SO THAT ; WE RUN FIRST $SCHDWK_S DAYTIM=B05SEC,REPTIM=B05SEC ; WAKE UP EVERY 5 SECS BRW REFRSH NOT1ST: $SETIMR_S DAYTIM=B01SEC,ASTADR=DISPCH,REQIDT=#01 BRW SLEEP ; SET 1 SEC TIMER AND GOTO SLEEP ; NOTE REQIDT = 1 BECOMES ASTPRM = 1 .SBTTL ----- CASE 1 CALCULATE CPU % IDLE GRAPHIC (CALL IDLMTR) DOIDLE: PUSHL NULL_PID ; PUSH PID OF NULL PROCESS CALLS #1,IDLMTR .PAGE .SBTTL SLEEP UNTIL NEEDED SLEEP: MOVL #2,ASTPRM ; FAKE AN AST REQ ID = 2 (5 SEC TIMER) ; ---------------------------------------- ; IF PROCESS AWAKES FROM AST DELIVERY ; AND $WAKE FROM 1 SEC TIMER ; ASTPRM = 1 ; ---------------------------------------- $HIBER_S ; IF PROCESS AWAKES FROM SCEDULED WAKEUP JMP AWAKE ; ASTPRM = 2 ; THIS WAS TO FAKE AN AST FROM $SCHDWK ; WITH AN AST REQ ID OF 2 ; ---------------------------------------- ; IF PROCESS AWAKES FROM AST DELIVERY ; AND $WAKE FROM QIO (READVBLK) ; ASTPRM = 3 .PAGE .SBTTL AST DISPATCHER ENTRY POINT (DISPCH) .ENTRY DISPCH,^M<> SEC1: ; 1 SEC TIMER AND QIO AST ENTRY POINT $CANTIM_S REQIDT=#01 ; TURN OF IDLE AST'S ; OVER WRITE THE PHONY 5 SET BEFORE ; WE WENT TO SLEEP MOVL 4(AP),ASTPRM ; TEST TO SEE WHICH ON IT IS CHK1: $SETIMR_S DAYTIM=B01SEC,ASTADR=DISPCH,- REQIDT=#01 ; RESET THE TIMER WAKEUP: ; $WAKE_S ; WAKE MYSELF UP AND PASS PROCESS AST PARM RET ; RETURN FROM THE AST .SBTTL ----- CASE 3 - QIO INPUT PROCESSING .ENTRY CASE3,^M<> AST3: CMPB #^A/R/,INBUF ; SEE IF USERS TYPE "R" BNEQ SETNORM ; NO - SO EXIT NORMALLY JMP SETREF ; YES REPAINT SCREEN SETNORM: $CANTIM_S REQIDT=#01 ; TURN OF IDLE AST'S $CANCEL_S CHAN=TTCHAN ; CANCEL ANY PENDING I/O MOVL #SS$_NORMAL,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=EXIPOS,LENGTH=EXILEN EXIT: $SETPRI_S PRI=OLDPRI ; RESTORE ORIGINAL PRIORITY $EXIT_S CODE=ERRCOD ; FORCE AN EXIT RET SETREF: $CANTIM_S REQIDT=#01 ; TURN OF IDLE AST'S $QIO_S CHAN=TTCHAN,- FUNC=#IO$_READVBLK!IO$M_CVTLOW!IO$M_PURGE!IO$M_NOECHO,- P1=INBUF,P2=#1,- ASTADR=CASE3,ASTPRM=#03,IOSB=INIOSB ; 1ST RESET READ MOVL #2,ASTPRM ; FAKE A 5 SEC TIMER REPAINT: $QIO_S CHAN=TTCHAN,- FUNC=#IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH,- P1=HDRSTR,P2=HDRLEN,P4=#0,IOSB=IOSB ; REFRESH HEADER $WAKE_S ; WAKE UP RET .PAGE .SBTTL ERROR HANDLING CODE ERRALO: MOVL R0,ERRCOD $ASSIGN_S DEVNAM=OUTPUT,CHAN=TTCHAN $OUTPUT CHAN=TTCHAN,BUFFER=ALOERR,LENGTH=ALOLEN $EXIT_S CODE=ERRCOD ; FORCE AN EXIT RET ERRPRV: MOVL R0,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=PRVERR,LENGTH=PRVELN JMP DOMSG ERRSYI: MOVL R0,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=SYIERR,LENGTH=SYIELN JMP DOMSG ERRDVI: MOVL R0,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=DVIERR,LENGTH=DVIELN JMP DOMSG ERRJPI: MOVL R0,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=JPIERR,LENGTH=JPIELN JMP DOMSG ERRASC: MOVL R0,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=ASCERR,LENGTH=ASCELN JMP DOMSG ERRQIO: MOVL R0,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=QIOERR,LENGTH=QIOELN JMP DOMSG ERRNUL: MOVL R1,ERRCOD $OUTPUT CHAN=TTCHAN,BUFFER=NULERR,LENGTH=NULLEN JMP DOMSG DOMSG: $GETMSG_S MSGID=ERRCOD,MSGLEN=MLEN,BUFADR=MSGDSC $OUTPUT CHAN=TTCHAN,LENGTH=MLEN,BUFFER=MSGBUF JMP EXIT .END SYSUSERS