;======================================================================== ;= = ;= Programmer: Hunter Goatley = ;= Program: WATCH.MAR = ;= Language: VAX-11 MACRO32 = ;= Purpose: Watch processes by username (does DCL command = ;= SHOW PROC/CONT) = ;= System: VAX 11/785 VAX/VMS v4.2 = ;= Shop: WKU/ACRS Western Kentucky University = ;= Date: April 11, 1986 = ;= = ;======================================================================== ;= = ;= This program, when invoked by a DCL foreign command, accepts = ;= a username as a parameter and will show a process owned by = ;= that username (the program calls LIB$DO_COMMAND to execute = ;= SHOW PROC/CONT). If only one process is found matching the = ;= supplied username, it is displayed. If more than one process = ;= is found, the user is prompted for which process to show. = ;= The program supplies the process name, terminal name, and = ;= image name of each process that it must prompt for. If no = ;= process is found that matches the supplied username, a message = ;= stating so will be printed. = ;= = ;= The running user must have WORLD privilege to show processes = ;= other than his own. = ;= = ;= To assemble: $ MACRO WATCH = ;= To link: $ LINK WATCH = ;= = ;= Define symbol in appropriate account's LOGIN.COM: = ;= = ;= $ WATCH :== $dev:[directory]WATCH.EXE = ;= = ;= Usage: = ;= $ WATCH = ;= = ;======================================================================== ; .PSECT DATA,NOEXE,WRT,LONG ; ;======================================================================== ;= = ;= I T E M M A C R O ---- This macro is called to set up the = ;= itemlist requirements for the system = ;= service $GETJPI. = ;= = ;======================================================================== ; .MACRO ITEM BUF_LEN,ITEM_CODE,BUF_ADDR,RET_ADDR=0 .WORD BUF_LEN ; The length of the buffer .WORD ITEM_CODE ; Symbolic code specifying info item .ADDRESS BUF_ADDR ; Address of the buffer .LONG RET_ADDR ; The return length address .ENDM ITEM ; ; ;======================================================================== ;= = ;= D E S C M A C R O -> Macro to create a string descriptor = ;= = ;======================================================================== ; .MACRO DESC LEN,ADDR .WORD LEN ; The length of the string .BYTE DSC$K_DTYPE_T ; The type (character) .BYTE DSC$K_CLASS_S ; The class (string) .ADDRESS ADDR ; The address of the string .ENDM ; .LIBRARY /SYS$LIBRARY:LIB.MLB/ ; Needed for $PCBDEF ; $PCBDEF ; Process's status flags $IODEF ; Symbolic definitions for $QIO $SSDEF ; Symbolic definitions for status codes $JPIDEF ; Symbolic definitions for $GETJPI ; CR=13 LF=10 ; FOR_DESC: ; Descriptor for foreign buffer DESC 80,FOR_BUFF FOR_BUFF: ; Buffer area for foreign command .BLKB 80 FOR_LEN: ; Length of foreign command string .WORD 0 ; ... returned .ALIGN LONG JPIPID: .LONG -1 ; Wildcard search for $GETJPI ; NOT_FOUND_MSG: .ASCII /Username not found/ NOT_FOUND_LEN = .-NOT_FOUND_MSG .ALIGN LONG OUTBUF: .ASCII /Show / OPN_OFF=.-OUTBUF .BLKB 15 ; Process name will go here .BYTE ^A/ /[2] OTT_OFF=.-OUTBUF .BLKB 7 ; Terminal name will go here .BYTE ^A/ /[2] OIM_OFF=.-OUTBUF .BLKB 15 ; Image name will go here .ASCII \ (Y/N)? \ OUTBUF_LEN = .-OUTBUF .ALIGN LONG ; MAXPROC=50 ; Maximum number of processes SIM_LEN=15 ; Lengths of each USERSAVE info areas SPN_LEN=15 STT_LEN=8 SPID_LEN=4 SAVE_LEN=42 SPN_OFF=4 ; Offsets into USERSAVE for information STT_OFF=19 SIM_OFF=27 ; USERSAVE: ; Save room for Proc name, TT:, image, .BYTE ^A/ /[MAXPROC*SAVE_LEN] ; ... and PID ; .ALIGN LONG JPI_LIST: ; $GETJPI item list ITEM 139,JPI$_IMAGNAME,IMAGE ITEM 15,JPI$_PRCNAM,PROCNAME,PN_LEN ITEM 12,JPI$_USERNAME,USERNAME ITEM 8,JPI$_TERMINAL,TERMINAL,TT_LEN ITEM 4,JPI$_PID,PID ITEM 4,JPI$_MODE,MODE ITEM 4,JPI$_STS,PCBSTS .LONG 0 PCBSTS: ; Process's status flags .LONG 0 MODE: .LONG 0 PID: .LONG 0 ; Space for processes' PID USERNAME: ; Space for username of processes .BLKB 12 .ALIGN LONG PROCNAME: ; Space for the process names .BLKB 15 .ALIGN LONG PN_LEN: .BLKL 1 ; Length of process name returned IMAGE: .BLKB 139 ; Space for each image name ; ;=============== ;= Used to put terminal name in USERSAVE ; NET_TT: .BYTE 0 ; Holds * for network terminal .ALIGN LONG TERMINAL: ; The terminal name .BLKB 8 .ALIGN LONG TT_LEN: .BLKL 1 ; The length of terminal name TTDESC: DESC 8,TERMINAL TYPE_MODE: ; Displayed if process has no .ASCII /-NET--BAT--SUB--DET--SYS-/ ; ... terminal DVI_LIST: ; $GETDVI item list (modem chars) ITEM 4,DVI$_TT_MODEM,MODEM .LONG 0 MODEM: .LONG 0 ; Terminal modem characteristic ;========= ; ; .ALIGN LONG SH_PROC_CMD: .ASCID \SHOW PROCESS/CONTINUOUS/ID= \ ; DCL_CMD_PID = . - 8 ; DCL_CMD_PID points to 8 blanks for PID ; ... in SH_PROC_CMD buffer .ALIGN LONG USAGE_MSG: .ASCII /Usage: WATCH / USAGE_MSG_LEN = .-USAGE_MSG .ALIGN LONG BLANKS: .BYTE ^A/ /[80] ; Blanks used to clear out buffers TTNAME: .ASCID /TT:/ ; Device name TTCHAN: .BLKW 1 ; Channel # for TT: ; ; ;======================================================================= ; .PSECT WATCH_CONT,EXE,NOWRT .ENTRY WATCH_CONT,^M<> $ASSIGN_S - ; Assign an I/O channel to the device CHAN=TTCHAN, - DEVNAM=TTNAME ; ;*** Get the username entered on the foreign command line ; PUSHAW FOR_LEN ; Push address for return length CLRL -(SP) ; No prompt PUSHAQ FOR_DESC ; Push the descriptor for buffer CALLS #3,G^LIB$GET_FOREIGN ; Get the foreign command line MOVW FOR_LEN,R6 ; Move the length returned to a register TSTW R6 ; Was there a username specified? BNEQ 10$ ; ... (length^=0?) Yes -- continue $QIOW_S CHAN=TTCHAN, - ; Print usage message FUNC=#IO$_WRITEVBLK, - P1=USAGE_MSG, - P2=#USAGE_MSG_LEN BRW LEAVE ; ... No -- leave without doing anything 10$: MOVAB FOR_BUFF,R7 ; Move the addresses to registers for MOVAB USERNAME,R8 ; ... efficiency MOVAB USERSAVE,R10 ; ... CLRL R9 ; Clear the count of matching processes LOOP: $GETJPIW_S - ; Get process information PIDADR=JPIPID, - ; Address of -1 for wildcard search ITMLST=JPI_LIST ; The addr of JPI item list CMPL #SS$_NOMOREPROC,R0 ; Are we out of processes? BEQLU TRY_SHOWING ; Yes -- go try to show it. No-continue CMPC3 #12,(R7),(R8) ; Does username match specified name? TSTL R0 ; Yes -- continue BNEQU LOOP ; No -- go get info for next process ; ;*** Here if the process's username matched username specified on command line ; MOVL PID,(R10) ; Move the PID to the USERSAVE area MOVC3 PN_LEN,PROCNAME,SPN_OFF(R10) ; Move the Process name ; BSBW TERM_OUT ; Move the terminal name ; ;*** Move the image name ; LOCC #^A/]/,#80,IMAGE ; Find end of directory spec for image BNEQ 10$ ; Found? No -- no image Yes -- go move ; ... only the image name MOVL #^A/*DCL/,SIM_OFF(R10) ; Move "*DCL" to save area BRB 20$ ; Go bump up pointers 10$: INCL R1 ; Bump pointer => 1st char of image name MOVL R1,R5 ; Move addr to another register LOCC #^A/./,#39,(R5) ; Look for extension marker for name SUBL R5,R1 ; Subtract starting addr from addr of ; ... "." (length of name in R1) CMPL #SIM_LEN,R1 ; Is the length > 15? BGEQU 15$ ; Yes -- go around it MOVZBL #SIM_LEN,R1 ; Make it 15 15$: MOVC3 R1,(R5),SIM_OFF(R10) ; Move the image name to USERSAVE area ; 20$: ADDL2 #SAVE_LEN,R10 ; Bump USERSAVE pointer to point to next ; ... area in the "array" INCL R9 ; Increment matched username counter CMPL #MAXPROC,R9 ; Has the maximum number been reached? BNEQ LOOP ; No -- go get info for next process ; ;**** Here when ready to begin showing processes ; TRY_SHOWING: MOVAB USERSAVE,R10 ; Get the USERSAVE area address TSTL R9 ; Was a matching process found? BNEQU 10$ ; Yes -- show it No -- print msg & die $QIOW_S CHAN=TTCHAN, - ; Print message "Username not found" FUNC=#IO$_WRITEVBLK, - ; ... P1=NOT_FOUND_MSG, - ; ... P2=#NOT_FOUND_LEN ; ... BRW LEAVE ; Say good-night ; ;**** Here if at least one process matched supplied username ; 10$: CMPL #1,R9 ; Was there only one match? BEQL SHOW_IT ; Yes -- go show it and leave ; ;**** This loop traverses through USERSAVE, prompting for reply before showing ; LOOP2: MOVAB OUTBUF,R8 ; Get the addr of output buffer ; Move Information from USERSAVE MOVC3 #SPN_LEN,SPN_OFF(R10),OPN_OFF(R8) ; Move process name MOVC3 #STT_LEN,STT_OFF(R10),OTT_OFF(R8) ; Move terminal name MOVC3 #SIM_LEN,SIM_OFF(R10),OIM_OFF(R8) ; Move image name $QIOW_S CHAN=TTCHAN, - ; Ask if the displayed process FUNC=#IO$_READPROMPT!IO$M_CVTLOW, - ; ... is to be shown P1=FOR_BUFF, - ; ... re-use FOR_BUFF for input P2=#80, - ; ... The length of input buffer P5=#OUTBUF, - ; ... The prompt P6=#OUTBUF_LEN ; ... and its length CMPB #^A/Y/,FOR_BUFF ; Did the user enter "Y"? BEQLU SHOW_IT ; Yes -- go show it ; Prepare to traverse USERSAVE again ADDL2 #SAVE_LEN,R10 ; Bump up pointer to USERSAVE (-> next) SOBGTR R9,30$ ; Loop until all have been asked about BRW LEAVE ; Leave when matched process counter = 0 30$: BRW LOOP2 ; Branch back if counter > 0 ; ;**** SHOW the process whose PID is pointed to by R10 (current position in ;**** USERSAVE) ; SHOW_IT: $DASSGN_S - ; Deassign I/O channel to TT: CHAN=TTCHAN MOVL (R10),R0 ; Move the PID to R0 for subroutine MOVAB DCL_CMD_PID,R1 ; Move buffer address to R1 BSBW PID2ASC ; Convert the PID from HEX to ASCII ; ... for LIB$DO_COMMAND PUSHAQ SH_PROC_CMD ; Push the address of SHOW PROC/CONT CALLS #1,G^LIB$DO_COMMAND ; Start showing it ; ;**** Signal ERROR and exit ; ERROR: $EXIT_S CODE=R0 ; Return error status to VMS ; ;**** Here to EXIT quietly ; LEAVE: $DASSGN_S - ; Deassign I/O channel to TT: CHAN=TTCHAN $EXIT_S ; Return to VMS ; ;**** TERM_OUT puts the terminal name or process mode in the output buffer ; TERM_OUT: PUSHR #^M ; Save registers destroyed by MOVC3 MOVAB TERMINAL-1,R6 ; Move the terminal address - 1 to R6 MOVB #^A/ /,(R6) ; Move a blank in front of terminal MOVL TT_LEN,R5 ; The length of TERMINAL returned BNEQ 20$ ; Was no terminal returned? MOVL MODE,R3 ; Move the process mode to R3 CLRL R4 ; Clear the MODE buffer offset CMPL #JPI$K_NETWORK,R3 ; Is it a network process? BEQLU 15$ ; Yes - go move the TYPE of MODE INCL R4 ; Bump up pointer into TYPE_MODE CMPL #JPI$K_BATCH,R3 ; Is it a batch process? BEQLU 15$ ; Yes - go move the TYPE of MODE INCL R4 ; Bump up pointer into TYPE_MODE CMPL #JPI$K_INTERACTIVE,R3 ; Is it a subprocess? BEQLU 15$ ; Yes - go move the TYPE of MODE INCL R4 ; Bump up pointer into TYPE_MODE BBS #PCB$V_LOGIN,PCBSTS,15$ ; Is is detached (no SYSUAF login)? INCL R4 ; Bump up pointer into TYPE_MODE ; ... Just assume it is -SYS- 15$: MULL2 #5,R4 ; Get the offset into type buffer MOVAB TYPE_MODE[R4],R6 ; Get the correct address MOVZBL #5,R5 ; Move a length to R5 BRB 30$ ; Go print it 20$: $GETDVIW_S - ; Get the terminal characteristics DEVNAM=TTDESC, - ITMLST=DVI_LIST INCL R5 ; Add one to the # of bytes in tt name CMPL #1,MODEM ; Does the terminal have modem chars? BNEQ 30$ ; No -- don't add anything MOVB #^A"*",(R6) ; Move "*" to byte before TERMINAL 30$: MOVC3 R5,(R6),STT_OFF(R10) ; Move the terminal name to OUTBUF POPR #^M ; Restore registers RSB ; Return to calling routine ; ;**** PID2ASC expects a hexadecimal value in R0 and an 8-character buffer ;**** address in R1. ; PID2ASC: PUSHR #^M ; Save registers destroyed by MOVC3 MOVL R0,R5 ; Make a copy of the PID MOVZBL #8,R4 ; Set up the translation loop counter 10$: ROTL #4,R5,R5 ; Rotate the hex number to process next MOVL R5,R3 ; Make a copy to work with BICL2 #^XFFFFFFFF0,R3 ; Clear all but last 4 bits (1 digit) ADDB2 #^X30,R3 ; Add x'30' to make it ASCII SUBL3 #^X39,R3,R2 ; Subtract x'39' from digit (> ^A"9"?) BLEQ 20$ ; If ASCII ~> than 9, go put in OUTBUF ADDL3 #^X40,R2,R3 ; Make the digit (A-F) an ASCII "A-F" 20$: MOVB R3,(R1)+ ; Move the ASCII char to OUTBUF & bump SOBGTR R4,10$ ; Finished with longword value? no, 10$ POPR #^M ; Restore registers RSB ; Return to calling routine ; .END WATCH_CONT