;WHERE.MAR displays information about processes and devices .TITLE WHERE .IDENT 'V04-007' ; ;******************************************************************************* ;* * ;* THIS SOFTWARE IS MAINTAINED AT THE CALIFORNIA INSTITUTE OF TECHNOLOGY * ;* ASTRONOMY DATA PROCESSING FACILITY. IT MAY BE COPIED AND DISTRIBUTED * ;* WITHOUT RESTRICTION. * ;* * ;* CALTECH ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF THIS * ;* SOFTWARE. * ;* * ;******************************************************************************* ; ; ; DESCRIPTION: ; ; WHERE displays information about processes and devices. ; ; WHERE searches the I/O data base for all terminals that are in use, ; and displays selected information about the owners' processes, along ; with terminal locations retrieved from file WHERE_PORTS. ; Options include listing subprocesses and batch jobs, sorting output ; by username, selecting or discarding output by search string, and ; listing users of allocated devices (other than terminals). ; ; ; General qualifiers: ; ; /INTERACTIVE - Include interactive users ; /SORT - Sort by username ; /BATCH - Include batch jobs ; /SUBPROCESSES - Include sub-processes ; /FULL - Same as /INTER/SORT/BATCH/SUBPROC ; /ALL_PROCESSES - Include all processes on system ; /ALLOCATED_DEVICES - Include list of allocated devices ; /DCL - Exclude processes not at DCL level ; /LONG - Use long output formats ; ; Qualifiers which select the information to be listed about each process: ; ; /PID - PID ; /USERNAME - username ; /PROCESS_NAME - process name (if different from ; username and terminal ID) ; /UIC - UIC (octal format) ; /TERMINAL - terminal ID ; /TYPE - terminal type ; /IMAGE - name of currently executing image ; /STATE - process state ; /PRIORITY - current and base priorities ; /DIRECT_IO - direct I/O count ; /BUFFERED_IO - buffered I/O count ; /PAGE_FAULTS - number of page faults ; /WORKING_SET - working set size ; /PHYSICAL_MEMORY - number of pages the process has ; in physical memory. ; /CPU_TIME - CPU time ; /ELAPSED_TIME - elapsed time ; /LOCATION - location ; ; ; SITE SPECIFIC MODIFICATIONS: ; ; The BADDEV list contains device types that should be ignored. ; The BADUSRNAM and BADPRCNAM lists contain usernames and process names ; which should be ignored unless the /ALL_PROCESSES qualifier is ; specified. ; ; ; BUILDING: ; ; Assemble with SYS$LIBRARY:LIB/LIB ; Link with SYS$SYSTEM:SYS.STB/SEL (/NOTRACE) ; Install with privileges: CMKRNL - to get device info ; WORLD - to get process info ; OPER - to get queue info ; ; ; AUTHORS: ; ; Kimo B. Yap ; Jon L. Vavrus ; ; ; MODIFICATIONS: ; ; V04-007 17-OCT-1985 PCP ; VMS V4.2. Add QUI$_SEARCH_FLAGS. ; ; V04-006 24-SEP-1985 PCP ; Fix bad R6 reference in QUI_HANDLER. ; ; V04-005 25-JUL-1985 PCP ; Remove duplicate /FULL from command definition. Increase ; maximum device count from 128 to 256. ; ; V04-004 7-MAY-1985 PCP ; Interface with command definition utility. ; Enhance search string capability to immitate DCL SEARCH command ; (multiple strings; /EXACT; /MATCH=) ; Corrections for virtual terminal names with more than 3 digits. ; ; V04-003 6-APR-1985 PCP ; Batch processing restored. The code can be greatly simplified ; if the new (yet undocumented) system service $GETQUI eventually ; acquires an argument or item code for PID. ; ; V04-002 28-FEB-1985 PCP ; TTYTYP macro modified to reference TT$_ symbols ($TTDEF) ; rather than DT$_ ($DCDEF). Additional entries made in TRMTAB ; for new terminal types. Code added to output routine ; for terminal type to prevent out-of-bounds references in TRMTAB. ; ; V04-001 19-FEB-1985 PCP ; Batch processing has been eliminated, since it was dependent ; on the format of the queue data base under previous versions ; of VMS. ; ; Internal format PIDs taken from the I/O data base are ; converted to extended format for use with $GETJPI. ; ; Virtual terminal names are converted to physical device ; names for the ports file search. ; ; The executive mode routine to search the I/O data base ; has been replaced by a user mode routine having the same call ; interface. The first time the new routine is entered, it calls a ; kernel mode routine that locks the data base and runs through the ; device list, copying the desired data to a buffer allocated from ; process virtual memory. VMS system routines are used as much as ; possible. Information on these routines was obtained from the VMS ; source code for the SHOW DEV command and associated routines from ; module IOSUBNPAG of facility SYS. ; ; .PAGE .SBTTL COMMAND DEFINITION ; ; DEFINE VERB WHERE ; IMAGE sys:[sysprog]where ; PARAMETER P1, LABEL=SEARCH_STRING, VALUE (LIST) ; QUALIFIER INTERACTIVE, DEFAULT ; QUALIFIER SORT ; QUALIFIER BATCH ; QUALIFIER SUBPROCESSES ; QUALIFIER FULL ; QUALIFIER ALL_PROCESSES ; QUALIFIER ALLOCATED_DEVICES, DEFAULT ; QUALIFIER DCL, DEFAULT ; QUALIFIER LONG ; QUALIFIER PID ; QUALIFIER USERNAME, DEFAULT ; QUALIFIER PROCESS_NAME, DEFAULT ; QUALIFIER UIC ; QUALIFIER TERMINAL, DEFAULT ; QUALIFIER TYPE, DEFAULT ; QUALIFIER IMAGE, DEFAULT ; QUALIFIER STATE ; QUALIFIER PRIORITY ; QUALIFIER DIRECT_IO ; QUALIFIER BUFFERED_IO ; QUALIFIER PAGE_FAULTS ; QUALIFIER WORKING_SET ; QUALIFIER PHYSICAL_MEMORY ; QUALIFIER CPU_TIME, DEFAULT ; QUALIFIER ELAPSED_TIME ; QUALIFIER LOCATION, DEFAULT ; ; QUALIFIER EVERY_FIELD ; ; QUALIFIER EXACT ; QUALIFIER MATCH, NONNEGATABLE, DEFAULT, VALUE (TYPE=MATCH) ; ; DEFINE TYPE MATCH ; KEYWORD OR, DEFAULT ; KEYWORD AND ; KEYWORD NOR ; KEYWORD NAND ; .PAGE .SBTTL DECLARATIONS $TPADEF $JPIDEF $UCBDEF $DCDEF DC$_UNKNOWN= 0 ; Add this one for AP $TTDEF $DDBDEF $DEVDEF $STATEDEF $SECDEF $UCBDEF $CHFDEF $SSDEF BLANK= ^A\ \ ; ASCII blank TAB= 9 ; ASCII tab V_LINE= ^A\|\ ; ASCII | D_QUOTE= ^A\"\ ; ASCII " TILDA= ^A\~\ ; ASCII ~ SLASH= ^A\/\ ; ASCII / PORT_COMMENT= ^A\!\ ; Comment delimiter in port file IMAG_BUF_LEN= 64 ; Length of image name buffer PRC_BUF_LEN= 15 ; Length of process name buffer TERM_BUF_LEN= 16 ; Length of terminal buffer USR_BUF_LEN= 12 ; Length of username buffer KEY_LEN= USR_BUF_LEN+PRC_BUF_LEN+TERM_BUF_LEN+4 .PAGE .SBTTL PSECT DEFINITIONS .PSECT CODE,BYTE,NOWRT,EXE,SHR,GBL,RD .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL .PSECT DATA_WRT,LONG,NOEXE,RD,WRT,NOSHR,GBL .PSECT DATA_RD,BYTE,RD,NOWRT,NOEXE,SHR,GBL .PAGE .SBTTL MACROS ; ; .ADDR ; .MACRO .ADDR ADDRESS .ADDRESS 'ADDRESS' .ENDM .ADDR ; ; ASCII_TAB ; ; This macro constructs a table of equivalent characters for the ASCII ; character set (256 bytes). OLD is the string of ASCII values to be ; substituted for ( specifies a range). It should be seperated by ; commas and enclosed in angle brackets (<>). FILL is a string of ; characters to be used as replacements. ; .MACRO ASCII_TAB CHRVAL,FILLCHR=<.>,?L1 A_TAB.= 0 L1: .REPEAT 256 ; Create table .BYTE A_TAB. A_TAB.= A_TAB.+1 .ENDR .FILLCHR= 0 ..FILLCHR= %LENGTH(FILLCHR) - 1 .IRP A_TAB.,<'CHRVAL'> .A_TAB= %LOCATE(<->,A_TAB.) ..A_TAB= %LENGTH(A_TAB.) - .A_TAB - 1 .IF EQUAL ..A_TAB+1 .= L1+'A_TAB.' .ASCII \%EXTRACT(.FILLCHR,1,<'FILLCHR'>)\ .IF_FALSE ...A_TAB= .A_TAB+1 .A_TAB= %EXTRACT(0,.A_TAB,A_TAB.) .= L1+.A_TAB ....A_TAB= %EXTRACT(...A_TAB,..A_TAB,A_TAB.) .A_TAB = ....A_TAB-.A_TAB .REPEAT .A_TAB .ASCII \%EXTRACT(.FILLCHR,1,<'FILLCHR'>)\ .ENDR .ENDC .IIF NOT_EQUAL ..FILLCHR-.FILLCHR,.FILLCHR=.FILLCHR+1 .ENDR .= L1+256 .ENDM ; ; FLAGDEF ; ; Creates a symbol ITM_V_name and ITM_M_name for a unique ; bit position in FLAGS2. ITM_V_name is the bit number and ITM_M_name ; is the mask. ; .MACRO FLAGDEF NAME .IF NOT_DEFINED NEXT_2_BIT NEXT_2_BIT=0 .ENDC ITM_V_'NAME'=NEXT_2_BIT ITM_M_'NAME'=1@NEXT_2_BIT NEXT_2_BIT=NEXT_2_BIT+1 .ENDM FLAGDEF ; ; $GETJPI ; ; This macro calls SYS$GETJPI in the proper way, including the wait for ; the event flag and seting and clearing a timer request so that there ; is no "infinite" wait. ; .MACRO $GET_JPI PIDADR=0,PRCNAM=0,ITMLST,IOSB=0,ASTADR=0,- ASTPRM=#0,GEF=0,WEF=31,WAITIM,ERR,?LAB1 .GLOBL SYS$GETJPI $QIOPUSH ASTPRM,ASTADR $PUSHADR IOSB,CONTEXT=Q $PUSHADR ITMLST,CONTEXT=L $PUSHADR PRCNAM,CONTEXT=Q $PUSHADR PIDADR,CONTEXT=L PUSHL #GEF CALLS #7,G^SYS$GETJPI .IF BLANK ERR BLBC R0,LAB1 .IF_FALSE BLBC R0,ERR .ENDC .IF BLANK WAITIM .IF NOT_DEFINED $$GJP$TEMP .SAVE_PSECT .PSECT DATA_RD,BYTE,RD,NOWRT,NOEXE,SHR,GBL $$GJP$TEMP: .LONG -20000000,-1 .RESTORE_PSECT .ENDC $SETIMR_S EFN=#WEF,DAYTIM=$$GJP$TEMP .IF_FALSE $SETIMR_S EFN=#WEF,DAYTIM=WAITIM .ENDC $WFLOR_S EFN=#GEF,MASK=#^B1@GEF+<1@WEF> .IF NOT_DEFINED $$GJP$TEMP2 .SAVE_PSECT .PSECT DATA_WRT,LONG,RD,WRT,NOEXE,NOSHR,GBL $$GJP$TEMP2: .LONG .RESTORE_PSECT .ENDC $READEF_S EFN=#GEF,STATE=$$GJP$TEMP2 CMPL #SS$_WASSET,R0 BNEQ LAB1 $CANTIM_S MOVL #SS$_WASSET,R0 LAB1: .ENDM ; ; OUTTAB ; ; Output field definitions. ; .MACRO OUTTAB TYPE,JPI= ,JPISIZ=4,JPIBUF,JPILEN=0,HEAD= ,- HEAD_LONG= ,JPI2= ,JPISIZ2=4,JPIBUF2,JPILEN2=0,- SWITCH= ,?L1,?L2,?L3 .SAVE_PSECT LOCAL_BLOCK .PSECT DATA_WRT,LONG,NOEXE,RD,WRT,NOSHR,GBL .IIF NOT_DEFINED OUTTAB_V,OUTTAB_V=0 .IF NOT_DEFINED RTN_TAB RTN_TAB: .BLKL 32 ; Define routine address table .ENDC .IIF NOT_DEFINED OUTTAB_ENT_LEN,OUTTAB_ENT_LEN=12 .IF NOT_DEFINED OUT_TAB OUT_TAB: .BLKB OUTTAB_ENT_LEN*32 ; Define header/getjpi table .ENDC ITM_V_'TYPE'=OUTTAB_V ; Define symbols ITM_M_'TYPE'=1@OUTTAB_V .IF BLANK <'HEAD'> ; Check for end of outputs .IIF DEFINED FIRST_OUT_V,LAST_OUT_V=OUTTAB_V-1 .IF_FALSE ; Check for start of outputs .IF NOT_DEFINED FIRST_OUT_V FIRST_OUT_V=OUTTAB_V ALL_OUT_FIELDS=1@OUTTAB_V .IF_FALSE ALL_OUT_FIELDS=ALL_OUT_FIELDS!<1@OUTTAB_V> .ENDC .SAVE_PSECT ; Define GETJPI stuff .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL .IF NOT_BLANK <'JPI'> L1: .WORD JPISIZ,JPI$_'JPI' .ADDR JPIBUF .ADDR JPILEN .IF NOT_BLANK <'JPI2'> .WORD JPISIZ2,JPI$_'JPI2' .ADDR JPIBUF2 .ADDR JPILEN2 .ENDC .LONG 0 .ENDC L2: .ASCIC \'HEAD'\ .IF BLANK <'HEAD_LONG'> ; No "long" format L3: .ASCIC \'HEAD'\ .IF_FALSE ; "Long" formats L3: .ASCIC \'HEAD_LONG'\ .ENDC .RESTORE_PSECT .TEMP=. .=OUT_TAB+ .IF BLANK ; Store addresses in table .LONG 0 .IF_FALSE .ADDR L1 .ENDC .ADDR L2 .ADDR L3 .=.TEMP .ENDC OUTTAB_V=OUTTAB_V+1 .IIF GE, OUTTAB_V-32, .ERROR ; OUTTAB overflow .IF NOT_BLANK <'SWITCH'> MULTI_SWITCH SWITCH,ITM_M_'TYPE' .ENDC .RESTORE_PSECT .ENDM OUTTAB ; ; MULTI_SWITCH ; .MACRO MULTI_SWITCH SWITCH,FLAGS,?L1 .SAVE_PSECT LOCAL_BLOCK .PSECT DATA_WRT .IF NOT_DEFINED SWITCH_TAB SWITCH_TAB_MAX = 48 SWITCH_TAB_COUNT = 0 SWITCH_TAB: .BLKL 2*SWITCH_TAB_MAX +1 ; +1 for end-of-list (zero longword) .ENDC .SAVE_PSECT .PSECT STRINGS L1: .ASCIC \'SWITCH'\ .RESTORE_PSECT .=SWITCH_TAB + .ADDR L1 ; address of switch name counted string .LONG FLAGS ; flag mask .LONG 0 ; assume end-of-list SWITCH_TAB_COUNT = SWITCH_TAB_COUNT + 1 .IIF GE, SWITCH_TAB_COUNT-SWITCH_TAB_MAX, .ERROR ; SWITCH_TAB overflow .RESTORE_PSECT .ENDM MULTI_SWITCH ; ; OUTRTN ; .MACRO OUTRTN TYPE ; This macro defines an output formatting routine .SAVE_PSECT LOCAL_BLOCK .PSECT CODE,BYTE,RD,NOWRT,EXE,SHR,GBL 'TYPE'_ROUTINE: .ENDM .MACRO ENDRTN TYPE ; This macro ends an output formatting routine RSB .PSECT DATA_WRT,LONG,NOEXE,RD,WRT,NOSHR,GBL ..=. .=RTN_TAB+<4*ITM_V_'TYPE'> .ADDR 'TYPE'_ROUTINE .=.. .RESTORE_PSECT .ENDM ; ; INSERT_BLANK ; .MACRO INSERT_BLANK ?L1 ; Inserts a leading blank in output field if ; not the first one. BBS #ITM_V_FIRST,FLAGS2,L1 MOVB #BLANK,(AP)+ L1: .ENDM ; ; ALLOCATED ; .MACRO ALLOCATED LABEL,NOT= ,?L1 ; This macro branches to LABEL if the ; terminal is not marked as allocated ; OR there is no login terminal. If ; NOT is given then the opposite ; occurs .IF BLANK <'NOT'> BBC #ITM_V_ALLOTRM,FLAGS2,'LABEL' TSTW LGNTRML BEQL 'LABEL' .IF_FALSE BBC #ITM_V_ALLOTRM,FLAGS2,L1 TSTW LGNTRML BNEQ 'LABEL' L1: .ENDC .ENDM ; ; RMS_FNM ; ; This macro defines the filenames FNM and DNM for the given FAB. ; .MACRO RMS_FNM FAB,FNM= ,DNM= ,?L1,?L2 .SAVE_PSECT .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL .IF NOT_BLANK <'FNM'> ; If there is a filename L1: .ASCII /'FNM'/ ; Define string .RESTORE_PSECT .RMS_TMP=. .='FAB'+FAB$B_FNS ; Insert length .BYTE %LENGTH(FNM) .='FAB'+FAB$L_FNA .ADDR L1 ; Insert address .=.RMS_TMP .SAVE_PSECT .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL .ENDC .IF NOT_BLANK <'DNM'> ; If there is a default name L2: .ASCII \'DNM'\ ; Define string .RESTORE_PSECT .RMS_TMP=. .='FAB'+FAB$B_DNS ; Insert length .BYTE %LENGTH(DNM) .='FAB'+FAB$L_DNA ; Insert address .ADDR L2 .=.RMS_TMP .IF_FALSE .RESTORE_PSECT .ENDC .ENDM RMS_FNM ; ; STATETYP ; ; This macro defines all the different types of states. ; .MACRO STATETYP TYPE= ,NAME= ,?L1 .IIF NOT_DEFINED .STATETYP,.STATETYP=0 .IF BLANK <'TYPE'> .=STATE_TAB ; This is unknown state .SAVE_PSECT .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL L1: .ASCIC \'NAME'\ .IF_FALSE .=STATE_TAB+<4*SCH$C_'TYPE'> ; Go to right place .SAVE_PSECT ; Define string .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL L1: .IF BLANK <'NAME'> .ASCIC /'TYPE'/ .IF_FALSE .ASCIC /'NAME'/ .ENDC .ENDC .RESTORE_PSECT .ADDR L1 ; Load address .IIF GREATER <.-.STATETYP>,.STATETYP=. ; Set at end .=.STATETYP .ENDM ; ; TTYTYP ; ; This macro is used to define the various ASCII terminal type strings. ; .MACRO TTYTYP TYPE,NAME,?L1 .IIF NOT_DEFINED .TTYTYP,.TTYTYP=0 .IF BLANK <'TYPE'> .=TRMTAB .SAVE_PSECT ; Define string .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL L1: .ASCIC \'NAME'\ .IF_FALSE .=TRMTAB+<4*TT$_'TYPE'> ; Go to right place .SAVE_PSECT ; Define string .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL L1: .IF BLANK <'NAME'> .ASCIC /'TYPE'/ .IF_FALSE .ASCIC /'NAME'/ .ENDC .ENDC .RESTORE_PSECT .ADDR L1 ; Load address .IIF GREATER <.-.TTYTYP>,.TTYTYP=. ; Set at end .=.TTYTYP .ENDM .PAGE .SBTTL MAIN PROGRAM .PSECT CODE .ENTRY WHERE,^M $CREATE FAB=SYSOUT ; Open listing file (SYS$OUTPUT) $CONNECT RAB=OUTRAB MOVAB SWITCH_TAB,R11 ; get addr of table of qual names/flags CLRL FLAGS ; assume no qualifiers 5$: MOVL (R11)+,R1 ; get addr of next qual name counted str BEQL 15$ ; branch if none MOVZBL (R1)+,R0 ; peel off byte count to make desc MOVQ R0,-(SP) ; put desc on stack for pass by ref PUSHL SP ; pass addr of desc CALLS #1,G^CLI$PRESENT ; qualifier present on command line? MOVL (R11)+,R1 ; get the flag mask BLBC R0,5$ ; loop if qual not present BISL R1,FLAGS ; present, set flags according to mask BRB 5$ ; loop for another qual 15$: CALLS #0,GET_SEARCH_LIST BLBS R0,20$ CMPL R0,#CLI$_ABSENT BEQL 20$ PUSHL R0 CALLS #1,G^LIB$STOP 20$: ; 40$: BICL3 #^C,FLAGS,R11 ; R11 = output flags MOVAL GETJPI_END,R8 ; R10 = GETJPI list position MOVAB HDRBUF,R7 ; R7 = title string position BISL2 #ITM_M_FIRST,FLAGS2 ; Loop to get all outputs 50$: FFS #0,#32,R11,R0 BNEQ 55$ BRW 100$ 55$: ASHL R0,#1,R1 BICL2 R1,R11 MULL3 #OUTTAB_ENT_LEN,R0,R6 ; Get table location ADDL2 #OUT_TAB,R6 MOVL (R6)+,R1 ; Get GETJPI stuff BEQL 60$ MOVQ (R1)+,(R8)+ MOVL (R1)+,(R8)+ TSTL (R1) BEQL 60$ MOVQ (R1)+,(R8)+ MOVL (R1)+,(R8)+ 60$: BBC #ITM_V_LONG,FLAGS,70$ ; Correct for /LONG ADDL2 #4,R6 70$: MOVL (R6),R6 MOVZBL (R6)+,R0 CMPB #BLANK_FILL,(R6) ; Remove any leading blank if BNEQ 90$ ; this is first field BBS #ITM_V_FIRST,FLAGS2,80$ MOVB #BLANK,(R7)+ 80$: DECL R0 INCL R6 90$: BICL2 #ITM_M_FIRST,FLAGS2 MOVC3 R0,(R6),(R7) ; Move header MOVL R3,R7 BRW 50$ 100$: SUBL2 #HDRBUF,R7 MOVW R7, BBC #ITM_V_LONG,FLAGS,110$ ; Long output? MOVL #11,TIMEDSC ; Yes, fix time descriptors MOVL #11,CPUDSC 110$: MOVC3 #VALUE_BUF_LEN,VALUE_BUF,MASTER_BUF $OPEN FAB=PORTFAB ; Open port file $CONNECT RAB=PORTRAB $PUT RAB=OUTRAB ; Output header MOVAB RECBUF,OUTRAB+RAB$L_RBF ; Set RAB pointer to right ; buffer BBC #ITM_V_SORT,FLAGS,LOOP BSBW INIT_SORT ; Set up sort .ENABLE LOCAL_BLOCK LOOP: BICL2 #ITM_M_SUB1!ITM_M_HASTTY!ITM_M_ALLOTRM,FLAGS2 PUSHR #^M MOVC5 #0,TRMBUF,#BLANK,#TERM_BUF_LEN,TRMBUF POPR #^M BBS #ITM_V_SUB2,FLAGS2,GETSB BBS #ITM_V_BAT1,FLAGS2,GETBAT BBS #ITM_V_ALL1,FLAGS2,GETALL BRW GETTRM GETALL: BSBW GET_REST ; Get any non-terminal BLBS R0,15$ ; proc's BISL2 #ITM_M_SUB2,FLAGS2 ; No more, revert to sub's BICL2 #ITM_M_ALL1,FLAGS2 GETSB: REMQUE @PIDQUE,R0 ; Get next sub-process PID BVC 10$ 5$: BRW DONE 10$: MOVL 8(R0),PID CLRL 8(R0) PUSHR #^M MATCHC #4,PID,#DONEPIDS_LEN,DONEPIDS POPR #^M BNEQ 15$ BRW LOOP 15$: BRW GETINF GETBAT: BSBW GET_BATCH ; Get a batch job BLBS R0,15$ BICL2 #ITM_M_BAT1,FLAGS2 20$: BBS #ITM_V_ALL,FLAGS,30$ ; No more, see about ALL/SUB BBC #ITM_V_SUB,FLAGS,5$ BISL2 #ITM_M_SUB2,FLAGS2 BRB GETSB 30$: BISL2 #ITM_M_ALL1,FLAGS2 BRW GETALL ; If not doing a sub-process or batch job, get a terminal owner GETTRM: CALLG GETDEVARG,GETDEV BISL2 #ITM_M_HASTTY,FLAGS2 BLBS R0,GETINF BICL2 #ITM_M_HASTTY,FLAGS2 CMPL #SS$_NOSUCHDEV,R0 BNEQ 70$ BBC #ITM_V_BAT,FLAGS,20$ ; No more, see about BAT/SUB BBC #ITM_V_ALL,FLAGS,40$ BISL2 #ITM_M_ALL1,FLAGS2 BRW GETALL 40$: BRW GETBAT 70$: $EXIT_S CODE=R0 ; Exit if strange error ; Get information on obtained PID GETINF: MOVL PID,@LSTPID ; Mark PID as "processed" ADDL2 #4,LSTPID ; Clear fields MOVC3 #VALUE_BUF_LEN,MASTER_BUF,VALUE_BUF BICL2 #ITM_M_ALLOTRM,FLAGS2 ; Get info. $GET_JPI PIDADR=PID,ITMLST=JPILST,ERR=90$ CMPL #SS$_WASSET,R0 ; All OK? BNEQ 90$ BBS #ITM_V_SUB,FLAGS,80$ BBC #ITM_V_ALL,FLAGS,90$ 80$: BSBW GET_SUB_PIDS ; Get PIDs of sub proc's ; See if we don't want this process listed. ; /Unlisted process names begin at BADPRCNAM (as counted strings)\ ; \Unlisted usernames begin at BADUSRNAM (as counted strings) / ; Checks for interactiveness and DCL-ness are included here. 90$: BBC #ITM_V_HASTTY,FLAGS2,95$ ; Interactiveness BBS #ITM_V_INT,FLAGS,95$ BRW 130$ 95$: BBS #ITM_V_DCL,FLAGS,97$ ; DCL-ness TSTW IMGLEN BEQL 130$ CMPC5 IMGLEN,IMGNAM,#BLANK,#0,(AP) BEQL 130$ 97$: BBS #ITM_V_ALL,FLAGS,PORTS TSTW PRCLEN BEQL 110$ MOVAB BADPRCNAM,R0 ; Process names 100$: MOVZBL (R0),R1 ; Check for end BEQL 110$ INCL R0 CMPC5 R1,(R0),#BLANK,PRCLEN,PRCNAM BEQL 130$ ; If match then ; end itteration ADDL2 R1,R0 ; Move to next name BRB 100$ 110$: TSTW USRLEN BEQL PORTS MOVAB BADUSRNAM,R0 ; Usernames 120$: MOVZBL (R0),R1 ; Check for end BEQL PORTS ; If so, all OK INCL R0 CMPC5 R1,(R0),#BLANK,USRLEN,USRNAM BEQL 130$ ; If match then ; end itteration ADDL2 R1,R0 ; Move to next name BRB 120$ 130$: BRW LOOP ; Not wanted, loop again .DISABLE LOCAL_BLOCK PORTS: TSTW LGNTRML BNEQ 5$ CMPL #^A\ \,TRMBUF BEQL 10$ BRB 7$ 5$: CMPC5 TRMLEN,TRMBUF,#^A/:/,LGNTRML,LGNTRM BEQL 10$ ; Login terminal? 7$: BISL2 #ITM_M_ALLOTRM,FLAGS2 ; No, assume allocated 10$: TSTL OWNER_PID BEQL 12$ BISL2 #ITM_M_SUB1,FLAGS2 12$: BICL3 #^C,FLAGS,R11 BISL2 #ITM_M_FIRST,FLAGS2 PUSHL AP MOVAB RECBUF,AP 20$: FFS #0,#32,R11,R0 ; Find an output type BEQL 40$ ASHL R0,#1,R1 BICL2 R1,R11 MULL2 #4,R0 ADDL2 #RTN_TAB,R0 PUSHL R11 ; Save registers JSB @0(R0) ; Execute routine POPL R11 ; Recover registers BICL2 #ITM_M_FIRST,FLAGS2 BRB 20$ ; Check for search string match 40$: SUBL3 #RECBUF,AP,RECLEN ; Get final length POPL AP ; PUSHAQ RECLEN ; pass addr of desc CALLS #1,SEARCH ; search BLBS R0,50$ ; system err? no, branch PUSHL R0 ; yes, signal it CALLS #1,G^LIB$STOP ; 50$: TSTL R0 ; match? BLSS NOUSR1 ; no, branch 70$: INCL FNDNUM ; Otherwise inc. "found" count 80$: CALLG TRIM_LIST_2,G^STR$TRIM ; Trim string ; Convert non-printing char.s MOVTC RECLEN,RECBUF,#FILL_CHAR,MOVTC_TAB,RECLEN,RECBUF BBC #ITM_V_SORT,FLAGS,90$ BSBW RELEASE_REC ; Output to sort or.... BRW LOOP ; Start new itteration ; Output to SYS$OUTPUT 90$: MOVW RECLEN, $PUT RAB=OUTRAB NOUSR1: BRW LOOP ; Start new itteration ; DONE code (done with looping) DONE: BBC #ITM_V_SORT,FLAGS,30$ BSBW SORT_MERGE ; Sort and output if necessary 30$: CLRL R6 ; assume SYS$NODE not defined 50$: $TRNLOG_S LOGNAM=SYSNODE,RSLBUF=NODE,RSLLEN=NODE CMPW #SS$_NORMAL,R0 BNEQ 100$ 60$: CMPB @,#^A\_\ ; Clear leading underscores BNEQ 70$ INCL DECW NODE BRB 60$ 70$: MOVZWL NODE,R0 ; Clear trailing colons ADDL2 ,R0 DECL R0 80$: CMPB (R0),#^A\:\ BNEQ 90$ DECL R0 DECW NODE BRB 80$ 90$: MOVL #1,R6 ; remember that NODE is valid 100$: TSTL SEARCH_LIST ; search parameter specified BNEQ 105$ ; yes, branch MOVAQ SUMCTR,R0 ; assume NODE invalid BLBC R6,107$ ; NODE valid? no, branch MOVAQ SUMCTR_NODE,R0 ; BRB 107$ ; 105$: MOVAQ SUMCTR_MATCH,R0 ; BLBC R6,107$ ; MOVAQ SUMCTR_MATCH_NODE,R0 ; 107$: $FAO_S CTRSTR=(R0),- ; Format summary line OUTLEN=OUTRAB+RAB$W_RSZ,- OUTBUF=RECDSC,- P1=FNDNUM,- P2=TRMNOU,- P3=TRMNO,- P4=#NODE,- P5=#0 $PUT RAB=OUTRAB ; Output summary line CLRW OUTRAB+RAB$W_RSZ ; Output a blank line $PUT RAB=OUTRAB ; Look for allocated devices BBC #ITM_V_ALLO,FLAGS,110$ MOVL #DC$_TAPE,CLASS_ARG ; Tapes BSBW GET_DEVICES MOVL #DC$_SCOM,CLASS_ARG ; SCOM BSBW GET_DEVICES MOVL #DC$_REALTIME,CLASS_ARG ; Real time BSBW GET_DEVICES MOVL #DC$_DISK,CLASS_ARG ; Disks (floppies) BSBW GET_DEVICES MOVL #DC$_UNKNOWN,CLASS_ARG ; Unknown (AP) BSBW GET_DEVICES 110$: $EXIT_S .PAGE .SBTTL SEARCH .PSECT DATA_WRT DYNSTR: .WORD 0 .BYTE DSC$K_DTYPE_T .BYTE DSC$K_CLASS_D .LONG 0 SEARCH_LIST: .BLKL 1 SEARCH_LIST_UPCASE: .BLKL 1 SEARCH_LIST_PARAM: .ASCID /SEARCH_STRING/ .PSECT CODE ; ; SEARCH ; .ENTRY SEARCH,^M MOVL 4(AP),R6 ; get addr of src string desc MOVL SEARCH_LIST,R1 ; get addr of search list BNEQ 5$ ; if not empty, branch to continue BRW 95$ ; empty search list, return MATCH 5$: BBS #ITM_V_EXACT,FLAGS,10$ ; exact compare? yes, brnch, skip upcase PUSHL R6 ; pass addr of src string desc MOVAQ DYNSTR,R6 ; get addr of dyn str desc for return PUSHL R6 ; pass desc addr CALLS #2,G^STR$UPCASE ; convert to upper case MOVL SEARCH_LIST_UPCASE,R1 ; use already upcased search list BLBS R0,10$ ; upcase successful? yes, branch RET ; no, return the err code 10$: MOVQ (R6),R6 ; get desc MOVL FLAGS,R9 ; keep flags handy MOVZBL (R1)+,R0 ; get byte count of first item in list BGTRU 60$ ; list empty? no, branch BITL #ITM_M_MATCH.AND!- ; AND or OR? (null string matches always ITM_M_MATCH.OR,R9 ; if AND or OR, never if NAND or NOR) BEQL 90$ ; no, branch, return NOMATCH BRB 95$ ; yes, return MATCH ; Compare loop 60$: MATCHC R0,(R1),R6,(R7) ; match? BEQL 80$ ; yes, branch ; No match 70$: BITL #ITM_M_MATCH.OR!- ; OR or NAND? ITM_M_MATCH.NAND,R9 ; BEQL 75$ ; no, branch MOVAB (R1)[R0],R1 ; point to next string MOVZBL (R1)+,R0 ; get byte count BGTRU 60$ ; end-of-list? no, branch, compare next BBS #ITM_V_MATCH.OR,- ; if OR then return NOMATCH R9,90$ BRB 95$ ; else return MATCH 75$: BBS #ITM_V_MATCH.AND- ; if AND then return NOMATCH ,R9,90$ ; BRB 95$ ; else return MATCH ; Match 80$: BITL #ITM_M_MATCH.AND!- ; AND or NOR? ITM_M_MATCH.NOR,R9 ; BEQL 85$ ; no, branch MOVZBL (R1)+,R0 ; get byte count of next string BGTRU 60$ ; end-of-list? no, branch, compare next BBS #ITM_V_MATCH.AND,- ; if AND then return MATCH R9,95$ BRB 90$ ; else return NOMATCH 85$: BBS #ITM_V_MATCH.OR,R9,95$ ; if OR then return MATCH ; Return values 90$: MNEGL #1,R0 ; return NOMATCH RET 95$: MOVL #1,R0 ; return MATCH RET ; ; GET_SEARCH_LIST ; .ENTRY GET_SEARCH_LIST,^M CLRL SEARCH_LIST ; assume no list present on command CLRL SEARCH_LIST_UPCASE ; assume no list ; Read the command parameter (which may be a list). CLI$GET_VALUE success code ; is CLI$_CONCAT or CLI$_COMMA if returned item is not last in a list, or ; SS$_NORMAL if it is last. MOVL SP,R11 ; create temporary stack pointer MOVL SP,R10 ; save addr of first byte beyond list MOVAQ DYNSTR,R9 ; keep desc addr handy 10$: ; BEGIN LOOP PUSHL R9 ; pass addr of desc for returned string PUSHAQ SEARCH_LIST_PARAM ; pass addr of parameter label desc CALLS #2,G^CLI$GET_VALUE ; get next list item BLBC R0,15$ ; if err, branch, return code MOVL R0,R7 ; save status code MOVL R9,R0 ; pass desc addr JSB G^STR$ANALYZE_SDESC_R1 ; parse desc SUBL R0,R11 ; allocate stack space for string CVTWB R0,-(R11) ; store count at head of str BICL3 #3,R11,SP ; realign stack MOVC3 R0,(R1),1(R11) ; copy string to stack CMPL R7,#SS$_NORMAL ; last item in list? BNEQ 10$ ; no, branch, get another BRB 20$ ; yes, EXIT LOOP 15$: RET ; err exit ; Allocate dynamic buffers for lists and copy list from stack. 20$: SUBL3 R11,R10,R2 ; find size of list INCL R2 ; allow for end-of-list flag MULL3 #2,R2,R1 ; get space for second list (upcase) PUSHL R1 ; store byte count for pass by ref PUSHAL SEARCH_LIST ; addr to return addr of VM alloc PUSHAL 4(SP) ; addr of byte count CALLS #2,G^LIB$GET_VM ; BLBC R0,50$ ; if err, branch, return code MOVL SEARCH_LIST,R3 ; retrieve addr of alloc ADDL3 R2,R3,SEARCH_LIST_UPCASE; save addr of second list DECL R2 ; no end-of-list flag on stack MOVC3 R2,(R11),(R3) ; move list to newly allocated VM CLRB (R3) ; end-of-list flag ; Read strings from first list buffer and upcase to second buffer 30$: INSV #DSC$K_DTYPE_T,#16,#8,R7; prepare fixed string desc INSV #DSC$K_CLASS_S,#24,#8,R7; MOVL SEARCH_LIST,R6 ; get addr of original list MOVL SEARCH_LIST_UPCASE,R8 ; get addr of upcase list to be 35$: ; BEGIN LOOP MOVZBL (R6)+,R5 ; get byte count, point to string BEQL 40$ ; end-of-list? yes, EXIT LOOP MOVW R5,R7 ; transfer byte count to dst desc MOVB R7,(R8)+ ; store dst byte count MOVQ R5,-(SP) ; put src desc on stack MOVQ R7,-(SP) ; put dst desc on stack PUSHAQ 8(SP) ; pass addr of src desc PUSHAQ 4(SP) ; pass addr of dst desc CALLS #2,G^STR$UPCASE ; convert to uppercase BLBC R0,50$ ; if err, branch, return code ADDL #8*2,SP ; clean off descriptors MOVAB (R6)[R5],R6 ; point to next src counted string MOVAB (R8)[R5],R8 ; point to next dst loc BRB 35$ ; END LOOP 40$: CLRB (R8) ; end-of-list flag for upcase MOVL #1,R0 50$: RET .PAGE .SBTTL GETDEV $CHFDEF $DEVDEF $SSDEF $UCBDEF $DEFINI DEV $DEF DEV_L_EPID .BLKL 1 $DEF DEV_B_CLASS .BLKB 1 $DEF DEV_B_TYPE .BLKB 1 $DEF DEV_W_NAMELEN .BLKW 1 $DEF DEV_T_NAME .BLKB 16 DEV_S_NAME = .-DEV_T_NAME DEV_K_SIZE = . $DEFEND DEV .PSECT DATA_WRT NDEV: .LONG 0 DEVLST: .LONG DEV_K_SIZE*256 .LONG 0 ; addr obtained by LIB$GET_VM ; ; GETDEV ; ; Get info on next device of specified class. ; ; Arguments: ; ; index - device buffer index ; ptr - device buffer pointer ; pid - returned PID ; namelen - returned length of device name ; name - returned device name ; type - returned device type ; class - device class ; DEV_INDEX = 4 DEV_PTR = 8 DEV_PID = 12 DEV_NAMELEN = 16 DEV_NAME = 20 DEV_TYPE = 24 DEV_CLASS = 28 .PSECT CODE .ENTRY GETDEV,^M MOVL NDEV,R8 ; get device count BNEQ 30$ ; if zero, haven't yet generated list PUSHAL DEVLST+4 ; arg2: addr for ret addr PUSHAL DEVLST ; arg1: addr of byte count CALLS #2,G^LIB$GET_VM ; allocate virtual memory for list BLBS R0,10$ ; ok? PUSHL R0 ; no, signal the error CALLS #1,G^LIB$STOP 10$: $CMKRNL_S - ROUTIN=GETDEVLST,- ARGLST=DEVLST CMPL R0,#SS$_ACCVIO ; kernel mode access violation? BNEQ 15$ ; no, branch MOVO ACCVIO,-(SP) ; stack signal args PUSHL R0 ; condition code PUSHL #5 ; arg list header MOVL SP,R0 ; get addr of arg list $PUTMSG_S MSGVEC=(R0) ; write the message $EXIT_S ; exit the image 15$: CMPL R0,#SS$_NORMAL ; kernel mode routine exit ok BEQL 20$ ; yes, branch PUSHL R0 ; no, signal it CALLS #1,G^LIB$STOP ; fatal 20$: MOVL NDEV,R8 30$: MOVL DEV_CLASS(AP),R2 ; get device class for which to search MOVL DEV_INDEX(AP),R6 ; get dev buf index MOVL DEV_PTR(AP),R7 ; get dev buf pointer BNEQ 50$ ; if zero, must init both SUBL3 #DEV_K_SIZE,DEVLST+4,R7 ; init addr one dummy block ahead of buf CLRL R6 ; init index BRB 50$ 40$: MOVAB DEV_K_SIZE(R7),R7 ; get addr of next block CMPB DEV_B_CLASS(R7),R2 ; right class? BNEQ 50$ ; no, go to end of loop INCL TRMNO ; yes, keep count of this class MOVL DEV_L_EPID(R7),R3 ; is the device being used? BNEQ 60$ ; yes, exit loop, go copy out data 50$: AOBLEQ R8,R6,40$ ; no, loop for another block MOVL #SS$_NOSUCHDEV,R0 ; fall through, no dev of this class CLRQ DEV_INDEX(AP) ; clear index and pointer RET 60$: INCL TRMNOU ; keep count of dev in use of this class MOVL R6,DEV_INDEX(AP) ; ret index MOVL R7,DEV_PTR(AP) ; ret pointer MOVL R3,@DEV_PID(AP) ; ret EPID MOVZBL DEV_B_TYPE(R7),- ; ret type DEV_TYPE(AP) MOVQ @DEV_NAME(AP),R2 ; get output desc for device name MOVZWL DEV_W_NAMELEN(R7),R0 ; get input str len MOVAB DEV_T_NAME(R7),R1 ; get input str addr CMPB (R1),#^A/_/ ; leading underscore? BNEQ 70$ ; no, branch INCL R1 ; yes, adjust addr to skip over DECL R0 ; adjust count 70$: MOVZWL R0,@DEV_NAMELEN(AP) ; ret name len MOVC5 R0,(R1),#^A/ /,R2,(R3) ; copy device name MOVL #SS$_NORMAL,R0 RET ; ; GETDEVLST ; ; Kernel mode routine to get a list of devices. The I/O database ; is locked by mutex so IPL is at AST level and page faults are allowed. ; ; AP - address of buffer descriptor ; .ENTRY GETDEVLST,^M MOVAB KRNLCH,(FP) ; establish cond hand to trap access vio JSB G^SCH$IOLOCKR ; lock the I/O data base, IPL to AST lev MOVQ (AP),R6 ; get buffer descriptor CLRL R8 ; initialize device counter CLRQ R10 ; init UCB, DDB ptrs for IOC$SCAN_IODB PUSHL #SS$_NORMAL ; return code 10$: JSB G^IOC$SCAN_IODB ; get UCB address BLBC R0,30$ ; if zero, then no more devices BBC #UCB$V_ONLINE,- ; skip offline device UCB$L_STS(R10),10$ MOVL UCB$L_DEVCHAR(R10),R0 BBC #DEV$V_AVL,R0,10$ ; skip unavailable dev (redirected term) BBS #DEV$V_MBX,R0,10$ ; skip mailbox device MOVL #SS$_BUFFEROVF,R0 ; assume no room to copy data from UCB SUBL #DEV_K_SIZE,R6 ; find actual buffer space available BLSS 20$ ; if not enough, return with err code MOVL UCB$L_PID(R10),R0 ; get internal PID of device owner JSB G^EXE$IPID_TO_EPID ; translate to extended PID MOVL R0,DEV_L_EPID(R7) ; save it (zero for nonexistent proc) MOVB UCB$B_DEVCLASS(R10),- ; save device class DEV_B_CLASS(R7) MOVB UCB$B_DEVTYPE(R10),- ; save device type DEV_B_TYPE(R7) MOVL R10,R5 ; arg: UCB address MOVL #2,R4 ; arg: op code MOVAB DEV_T_NAME(R7),R1 ; arg: name buffer addr MOVL #DEV_S_NAME,R0 ; arg: name buffer size JSB G^IOC$CVT_DEVNAM ; get device name string CMPL R0,#SS$_NORMAL ; did buffer overflow? BNEQ 20$ ; yes, return with code MOVW R1,DEV_W_NAMELEN(R7) ; no, store string count MOVAB DEV_K_SIZE(R7),R7 ; point to next empty output data block INCL R8 ; keep device count BRB 10$ ; loop to get another device 20$: MOVL R0,(SP) ; err, overwrite default return code 30$: MOVL R8,NDEV ; save number of devices MOVL G^SCH$GL_CURPCB,R4 ; get addr of PCB for unlock routine JSB G^SCH$IOUNLOCK ; unlock I/O data base via mutex POPL R0 ; get return code RET ; ; KRNLCH ; ; Kernel mode condition handler. ; .PSECT CODE,EXE,NOWRT,RD,BYTE,SHR,GBL .ENTRY KRNLCH,^M MOVL G^SCH$GL_CURPCB,R4 ; yes, get PCB addr for unlock JSB G^SCH$IOUNLOCK ; unlock I/O mutex SETIPL #0 ; reduce IPL from AST lev MOVL CHF$L_SIGARGLST(AP),R6 ; get addr of signal arg list CMPL CHF$L_SIG_NAME(R6),#SS$_ACCVIO ; is it access violation? BNEQ 10$ ; no, branch MOVO CHF$L_SIG_ARG1(R6),ACCVIO ; yes, save 4 args 10$: PUSHL CHF$L_MCHARGLST(AP) ; addr of mech arg list PUSHL R6 ; addr of sig arg list CALLS #2,G^LIB$SIG_TO_RET ; return the condition code RET .PAGE .SUBTITLE SUBROUTINES ;****************************************************************************** ;****************************** GET_SUB_PIDS ****************************** ;****************************************************************************** ; This routine gets and queues up any PIDs of the "current" process's ; sub-processes. It also marks the "current" PID as "done". GET_SUB_PIDS: TSTL SUBNUM ; Any sub-procs? BEQL 70$ MOVL #-1,WILDPID ; Yes, find it 10$: $GETJPI_S PIDADR=WILDPID,ITMLST=GETSUB ; Get owners of all processes ; (can use "normal" GETJPI ; since all info in PCB.) CMPL #SS$_NORMAL,R0 BNEQ 70$ ; No more subs CMPL OWNPID,PID ; Is it sub-process? BNEQ 10$ ; No, get a new PID 30$: ADDL3 #16,#PIDQUE,R0 ; Insert in queue 40$: TSTL (R0) ; Find empty spot BEQL 50$ ADDL2 #12,R0 BRB 40$ 50$: MOVL RETPID,(R0) ; Fill it INSQUE -8(R0),@PIDQUE+4 ; Queue it 60$: DECL SUBNUM BNEQ 10$ ; Get more sub-proc's 70$: RSB ;****************************************************************************** ;******************************** GET_BATCH ******************************* ;****************************************************************************** GET_BATCH: CALLS #0,QUI RSB ; ; VMS V4.0 implementation ; ; This would be simple if the new system service $GETQUI had an argument ; or item list code to get the PID if a queue entry is executing. ; As it is, info is returned either for the requesting process, or for a named ; queue entry (which can be a wild card). (That is, it's easy to get the ; name of batch job's queue from inside the batch job, and it's easy to get ; a list of entry numbers and queue names for all executing batch jobs, but ; it's still a bit of a problem to get an entry number and queue name from a ; PID of an executing batch job.) ; ; The technique is to use $GETJPI in search mode to find the next ; executing batch job. Then a message is formatted and sent to JOB_CONTROL ; in the same manner as $GETQUI, except that the message includes the PID ; returned by $GETJPI for the batch job, instead of the current process's PID. ; This works because this message field (ACM$L_PID) is not used by JOB_CONTROL ; to determine who sent the message, but only to get queue info. The sender ; is determined from the PID returned in second longword of the IOSB on ; JOB_CONTROL's mailbox QIO. ; $ACMDEF $CHFDEF $PCBDEF $PHDDEF $PSLDEF $QUIDEF ; $ACM extensions $DEFINI QUIACM .=ACM$S_ACMDEF1+ACM$W_MSGSTS $DEF ACM$L_IMAGCNT .BLKL 1 ; avoid IMGCNT, used in $ACMDEF $DEF ACM$L_EFN .BLKL 1 $DEF ACM$A_IOSB .BLKL 1 $DEF ACM$L_ASTADR .BLKL 1 $DEF ACM$L_ASTPRM .BLKL 1 $DEF ACM$W_QUIFUNC .BLKW 1 $DEF ACM$L_QUILST $DEFEND QUIACM ; Offsets in dynamically allocated storage $DEFINI QUIBLK $DEF QUI_L_EFN .BLKL 1 ; for pseudo-$GETQUI $DEF QUI_Q_IOSB .BLKQ 1 ; for pseudo-$GETQUI $DEF QUI_L_PID .BLKL 1 ; $GETJPI return item $DEF QUI_L_STS .BLKL 1 ; $GETJPI return item $DEF QUI_L_JPIPID .BLKL 1 ; $GETJPI search context $DEF QUI_W_QUEUE_NAME_LEN .BLKW 1 ; pseudo-$GETQUI return item $DEF QUI_T_QUEUE_NAME .BLKB 16 ; pseudo-$GETQUI return item QUI_S_QUEUE_NAME = .-QUI_T_QUEUE_NAME $DEF QUI_L_ENTRY_NUMBER .BLKL 1 ; pseudo-$GETQUI return item $DEF QUI_W_MSG_LEN .BLKW 1 ; message sent to JOB_CONTROL $DEF QUI_T_MSG .BLKB 255 ; requesting queue info QUI_S_MSG = .-QUI_T_MSG QUI_K_BLKSIZ = . $DEFEND QUIBLK .PSECT DATA_WRT,NOEXE,RD,WRT,LONG,NOSHR,GBL QUI_A_BLK: ; address of dynamic storage .BLKL 1 .PSECT CODE,EXE,NOWRT,RD,BYTE,SHR,GBL .ENTRY QUI,^M BBSS #ITM_V_BAT1,FLAGS2,10$ ; first time? no, branch BSBW QUI_INIT ; alloc and init info blk BLBS R0,5$ ; err? no, branch BRW 40$ ; yes, return 5$: MOVL #-1,QUI_L_JPIPID(R8) ; init $GETJPI search context 10$: MOVL QUI_A_BLK,R8 ; get info blk addr 20$: CLRQ -(SP) ; set up $GETJPI item list PUSHAL QUI_L_PID(R8) PUSHL #<!4> ; need PID CLRL -(SP) PUSHAL QUI_L_STS(R8) PUSHL #<!4> ; need status to test for batch MOVL SP,R7 ; save address of item list 30$: $GETJPIW_S - ; get next process PIDADR=QUI_L_JPIPID(R8),- ITMLST=(R7) BLBC R0,40$ ; branch if err BBC #PCB$V_BATCH,QUI_L_STS(R8),30$ ; batch job? no, get another prc MOVAB QUI_T_MSG(R8),R0 ; get msg addr MOVL QUI_L_PID(R8),ACM$L_PID(R0) ; replace PID BSBW QUI_SEND ; request info from job contrlr BLBC R0,30$ ; err? yes, get another process MOVL QUI_L_PID(R8),PID ; old WHERE code... MOVL #255,LOCLEN MOVAB LOCBUF,LOCLEN+4 MOVZWL QUI_W_QUEUE_NAME_LEN(R8),R0 MOVAB QUI_T_QUEUE_NAME(R8),R1 $FAO_S CTRSTR=BATCTR,- OUTLEN=LOCLEN,- OUTBUF=LOCLEN,- P1=R0,P2=R1,- P3=QUI_L_ENTRY_NUMBER(R8) 40$: RET ; ; QUI_INIT ; ; Allocate and initialize queue info block (with the help of QUI_EXEC). ; ; Outputs: ; ; R0 - status ; R8 - addr of info block ; (R1 modified, all others restored) ; ; QUI_A_BLK - addr of info block ; ; Info block fields initialized. ; QUI_INIT: PUSHL #QUI_K_BLKSIZ ; number of bytes to alloc PUSHAL QUI_A_BLK ; addr to receive addr of alloc PUSHAL 4(SP) ; addr of byte count CALLS #2,G^LIB$GET_VM ; allocate the buffer SUBL3 #1,(SP)+,R1 ; pop len-1 (offset to end) BLBC R0,20$ ; if error, branch MOVL QUI_A_BLK,R8 ; get buf addr ADDL3 R1,R8,-(SP) ; last addr in buf PUSHL R8 ; first addr in buf MOVL SP,R0 ; get addr of quadword arg $LKWSET_S INADR=(R0) ; lock the page(s) CLRQ (SP)+ ; clean arg from stack BLBC R0,20$ ; if error, branch PUSHAL QUI_L_EFN(R8) ; addr for returned EFN CALLS #1,G^LIB$GET_EF ; alloc event flag BLBC R0,20$ ; if error, branch PUSHL R8 ; put addr of info block in arg list MOVL SP,R0 ; save addr of arg list $CMEXEC_S ROUTIN=QUI_EXEC,- ; initialize msg buf ARGLST=(R0) TSTL (SP)+ ; clean arg list from stack BSBW QUI_TEST_ACCVIO ; handle access violation BLBC R0,20$ ; branch if other err MOVW R1,QUI_W_MSG_LEN(R8) ; save msg len MOVL #SS$_NORMAL,R0 ; 20$: RSB ; ; ; QUI_SEND ; ; Send message to job controller (with help of QUI_KERNEL) and wait for reply. ; ; Inputs: ; ; R8 - addr of info block ; ; Outputs: ; ; R0 - status ; (R1 modified, all others restored) ; ; Info block fields filled by job controller. ; QUI_SEND: CLRQ QUI_Q_IOSB(R8) ; initialize IOSB $CLREF_S EFN=QUI_L_EFN(R8) ; clear event flag BLBC R0,20$ PUSHAL QUI_T_MSG(R8) ; put msg addr in arg list MOVZWL QUI_W_MSG_LEN(R8),-(SP) ; put msg len in arg list MOVL SP,R0 ; get addr of arg lis $CMKRNL_S - ; send it ROUTIN=QUI_KERNEL,- ARGLST=(R0) BSBW QUI_TEST_ACCVIO ; handle access violation BLBC R0,10$ ; branch if other err $SYNCH_S - ; wait for completion EFN=QUI_L_EFN(R8),- IOSB=QUI_Q_IOSB(R8) MOVZWL QUI_Q_IOSB(R8),R0 ; get status 10$: CLRQ (SP)+ ; clean arg list from stack 20$: RSB ; return with status ; ; QUI_EXEC ; ; Immitate the $GETQUI system service. ; ; The following code has been taken from EXE$GETQUI (module SYSSNDJBC of ; facility SYS). This was done to allow for an arbitrary value in field ; ACM$L_PID of the message which is sent the job controller. The job ; controller's QUI routines use this field to determine which process ; is making the request. ; ; Changing ACM$L_PID does not affect the interprocess communication because ; another value, ACM$L_PROCID, (the PID received by the job contrller in the ; second longword of the IOSB on its mailbox read QIO) is used to identify the ; process to which the completion AST should be queued. (ACM$L_PROCID is an ; offset of -4 from the message buffer, which is valid if the buffer is ; appended to the IOSB.) ; ; The message fields are filled below using auto-increment addressing, but ; they can also be referenced by ACM$ offsets (with the extensions specified ; above). The arguments for the $GETQUI service are appended after the ; standard fields. ; ; Inputs: ; ; (AP) addr of buffer ; ; Outputs: ; ; R0 status code ; R1 number of bytes written to the buffer ; .ENTRY QUI_EXEC,^M MOVAB QUI_HANDLER,(FP) ; prevent process termination ; on err MOVL @#CTL$GL_PCB,R6 ; get this process's PCB addr MOVL @#CTL$GL_PHD,R7 ; get P1 region addr of PHD map MOVL (AP),R8 ; get addr of data block MOVAB QUI_T_MSG(R8),R3 ; get msg addr MOVZWL #MSG$_GETQUI,(R3)+ ; ACM$W_TYPE, ACM$W_MAILBOX MOVQ PHD$Q_PRIVMSK(R7),(R3)+ ; ACM$Q_PRVMSK MOVL PCB$L_UIC(R6),(R3)+ ; ACM$L_UIC MOVC3 #20,@#CTL$T_USERNAME,(R3) ; ACM$T_USERNAME, ACM$T_ACCOUNT SUBB3 PCB$B_PRIB(R6),#31,(R3)+ ; ACM$B_PROCPRI MOVPSL R0 ; get PSL EXTZV #PSL$V_PRVMOD,- ; get previous mode #PSL$S_PRVMOD,R0,R0 MOVB R0,(R3)+ ; insert in buf CLRW (R3)+ ; unused MOVL PCB$L_EPID(R6),(R3)+ ; ACM$L_PID MOVL PCB$L_STS(R6),(R3)+ ; ACM$L_STS MOVL PCB$L_EOWNER(R6),(R3)+ ; ACM$L_OWNER MOVQ PCB$T_TERMINAL(R6),(R3)+ ; ACM$T_TERMINAL 10$: MOVQ G^EXE$GQ_SYSTIME,(R3) ; ACM$Q_SYSTIME CMPL G^EXE$GQ_SYSTIME,(R3) ; validate system time BNEQ 10$ CMPL G^EXE$GQ_SYSTIME+4,4(R3) BNEQ 10$ ADDL #8,R3 ; size of system time ; The following ACM$ extension comprises the $GETQUI arguments ; (with the exception of image count, which is used by the return kernel mode ; AST to determine whether the same image is executing as that which initiated ; the request). ; ; Note that the order of item code and size are reversed from the standard ; system service item list format. The input item is passed by value. MOVL PHD$L_IMGCNT(R7),(R3)+ ; image count MOVZBL QUI_L_EFN(R8),(R3)+ ; event flag MOVAQ QUI_Q_IOSB(R8),(R3)+ ; I/O status block CLRQ (R3)+ ; astadr, astprm MOVW #QUI$_DISPLAY_JOB,(R3)+ ; function code MOVW #QUI$_SEARCH_FLAGS,(R3)+ ; input item code MOVW #4,(R3)+ ; input item size MOVL #QUI$M_SEARCH_THIS_JOB,(R3)+ ; input item value MOVW #QUI$_ENTRY_NUMBER,(R3)+ ; item code MOVW #4,(R3)+ ; item size MOVAL QUI_L_ENTRY_NUMBER(R8),(R3)+ ; item return address CLRL (R3)+ ; item return size address MOVW #QUI$_QUEUE_NAME,(R3)+ ; item code MOVW #16,(R3)+ ; item size MOVAB QUI_T_QUEUE_NAME(R8),(R3)+ ; item return address MOVAW QUI_W_QUEUE_NAME_LEN(R8),(R3)+ ; iterm return size address MOVAB QUI_T_MSG(R8),R1 ; get msg starting addr SUBL3 R1,R3,R1 ; compute and return len MOVL #SS$_NORMAL,R0 RET ; ; QUI_KERNEL ; ; Invoke system routine to send message to job controller's mailbox. ; .ENTRY QUI_KERNEL,^M MOVAB QUI_HANDLER,(FP) ; prevent fatal machine check ; while IPL is ASTDEL or less MOVQ (AP),R3 ; R3 = msg len, R4 = addr of msg buf MOVAB G^SYS$GL_JOBCTLMB,R5 ; addr of UCB for job contrlr's mailbox JSB G^EXE$SENDMSG RET ; ; QUI_HANDLER ; ; Handle executive and kernel mode conditions by returning a status code ; to the user mode routine that called the establisher. If access violation, ; save the four signal args (mask, virt addr, PC, PSL) so a complete message ; can be issued by the user mode routine. ; .ENTRY QUI_HANDLER,0 MOVL CHF$L_SIGARGLST(AP),R0 ; get addr of signal arg list CMPL CHF$L_SIG_NAME(R0),#SS$_ACCVIO ; access violation? BNEQ 10$ ; no, branch MOVO CHF$L_SIG_ARG1(R0),ACCVIO ; yes, save 4 args 10$: PUSHL CHF$L_MCHARGLST(AP) ; pass addr of mech arg list PUSHL R0 ; pass addr of sig arg list CALLS #2,G^LIB$SIG_TO_RET ; return to caller of establishr RET ; ; QUI_TEST_ACCVIO ; ; Tests for access violations. If R0 contains SS$_ACCVIO, the four signal args ; are copied from ACCVIO, a message is generated, and the image is terminated. ; Any other value in R0 causes immediate return with no registers modified. ; ; Intended to be called in user mode following return from inner mode routine ; that establishes QUI_HANDLER as its condition handler. ; QUI_TEST_ACCVIO: CMPL R0,#SS$_ACCVIO ; access violation? BNEQ 10$ ; no, other err, branch MOVO ACCVIO,-(SP) ; push four signal args PUSHL R0 ; condition code PUSHL #5 ; arg list header MOVL SP,R0 ; get addr of arg list $PUTMSG_S MSGVEC=(R0) ; write the message $EXIT_S ; terminate the image 10$: RSB ;****************************************************************************** ;********************************* GET_REST ******************************* ;****************************************************************************** ; This routine gets non-terminal connected jobs GET_REST: 10$: $GETJPI_S PIDADR=RESTPID,ITMLST=GETPID ; Get owners of all processes ; (can use "normal" GETJPI ; since all info in PCB.) BLBC R0,40$ ; No more PIDS MOVAL DONEPIDS,R0 ; Check to see if we've done 20$: TSTL (R0) ; this one BEQL 30$ CMPL PID,(R0)+ BEQL 10$ ; Yes, get another BRB 20$ 30$: MOVL #1,R0 ; No, do it 40$: RSB ;****************************************************************************** ;******************************* GET_DEVICES ****************************** ;****************************************************************************** ; This routine gets allocated devices of the type pushed on the stack ; prior to the call. GET_DEVICES: MOVL #1,DDB_ARG ; First DDB CLRL UCB_ARG 10$: CALLG GETDEVARG,GETDEV BLBS R0,20$ ; Get an allocated device RSB 20$: MOVAW BADDEV,R0 ; Check for unwanted devices 30$: TSTW (R0) BEQL 40$ CMPW (R0)+,TRMBUF BEQL 10$ BRB 30$ 40$: MOVC5 #0,USRNAM,#BLANK,#12,USRNAM ; Clear username $GETJPI_S PIDADR=PID,ITMLST=GETUSR ; Get Username (regular ; GETJPI since in PCB/JIB) $FAO_S CTRSTR=MTACTR,- ; Format string OUTLEN=OUTRAB+RAB$W_RSZ,OUTBUF=RECDSC,- P1=TRMLEN,P2=#TRMBUF,P3=#12,P4=#USRNAM $PUT RAB=OUTRAB ; Output string BRW 10$ ; Loop ;****************************************************************************** ;******************************** INIT_SORT ******************************* ;****************************************************************************** ; This routine initializes the area used to sort records. INIT_SORT: PUSHL #64*KEY_LEN ; Room for 64 keys PUSHAL SORT_DATA ; Get a bunch of memory PUSHAL 4(SP) CALLS #2,G^LIB$GET_VM MOVL SORT_DATA,NEXT_SKEY ; Spot for first key ADDL2 #4,SP RSB ;****************************************************************************** ;******************************* RELEASE_REC ****************************** ;****************************************************************************** ; This routine stores away a record to be sorted. It also constructs ; its key. Sorting will be by username->terminal->process name RELEASE_REC: PUSHR #^M MOVC5 USRLEN,USRNAM,#BLANK,- ; Move in username #USR_BUF_LEN,@NEXT_SKEY ADDL2 #USR_BUF_LEN,NEXT_SKEY MOVC5 TRMLEN,TRMBUF,#BLANK,- ; Move in terminal #TERM_BUF_LEN,@NEXT_SKEY ADDL2 #TERM_BUF_LEN,NEXT_SKEY MOVC5 PRCLEN,PRCNAM,#BLANK,- ; Move process name #PRC_BUF_LEN,@NEXT_SKEY ADDL2 #PRC_BUF_LEN,NEXT_SKEY MOVZWL RECLEN,-(SP) ; Get room for record ADDL2 #2,(SP) PUSHAL @NEXT_SKEY PUSHAL 4(SP) CALLS #2,G^LIB$GET_VM ADDL2 #4,SP MOVL @NEXT_SKEY,R0 ADDL2 #4,NEXT_SKEY MOVW RECLEN,(R0)+ ; Store record length MOVC3 RECLEN,RECBUF,(R0) ; Store record POPR #^M RSB ;****************************************************************************** ;******************************** SORT_MERGE ****************************** ;****************************************************************************** ; This routine sorts the records and outputs them in order. ; ; The routine used is a modified QUICKSORT using detached key records. ; The modifications are: ; 1.) The lower valued partition (partition which is below ; (by order) the pivot) is chosen for a next phase (the ; higher is stacked) of processing, rather than smaller ; (size). This allows completed partitions to be ; directly output. ; 2.) The pivot is included in the lower valued partition ; (so it can be output). ; Pivot selection is done using Singleton's method (median of first, ; last, and middle keys). Partitions of 7 or less elements are ; considered sorted and are passed to a final SIFT phase from which ; they are output. SORT_MERGE: PUSHR #^M CMPL SORT_DATA,NEXT_SKEY ; Check for no records BNEQ 5$ BRW 65$ 5$: MOVL SORT_DATA,R6 ; R6 = first pointer SUBL3 #KEY_LEN,NEXT_SKEY,R7 ; R7 = end pointer PUSHL #0 ; Mark end of partition stack PUSHL #0 10$: MOVQ R6,R8 ; Save ends SUBL3 R6,R7,R0 ; Check for partition size BEQL 60$ ; One item partition CMPL #7*KEY_LEN,R0 BGEQU 15$ BRW 70$ ; SIFT sort for partitions of less than 8 items 15$: ADDL3 #KEY_LEN,R6,R7 20$: CMPC3 #KEY_LEN-4,(R6),(R7) ; Compare keys BLSSU 50$ ; Sift MOVC3 #KEY_LEN,(R7),KEYBUF MOVC3 #KEY_LEN,(R6),(R7) 30$: CMPL R6,R8 ; Hit top BEQL 40$ CMPC3 #KEY_LEN-4,-KEY_LEN(R6),KEYBUF BLSSU 40$ MOVC3 #KEY_LEN,-KEY_LEN(R6),(R6) SUBL2 #KEY_LEN,R6 BRB 30$ 40$: MOVC3 #KEY_LEN,KEYBUF,(R6) ; Found key position 50$: MOVL R7,R6 ; Get new keys ADDL2 #KEY_LEN,R7 CMPL R6,R9 BNEQ 20$ ; Output sift results 60$: MOVL KEY_LEN-4(R8),R6 ; Get a record address MOVW (R6)+, MOVL R6, $PUT RAB=OUTRAB ; Output it ADDL2 #KEY_LEN,R8 CMPL R8,R9 BLEQU 60$ POPL R7 ; Get a new partition POPL R6 BEQL 65$ BRW 10$ 65$: POPR #^M MOVAL RECBUF, RSB ; None, then we are done ; QUICKSORT 70$: SUBL3 R6,R7,R6 ; Get middle key location DIVL2 #2*KEY_LEN,R6 MULL2 #KEY_LEN,R6 ADDL2 R8,R6 CMPC3 #KEY_LEN-4,(R8),(R6) ; Sift first, middle, and last BLSSU 80$ MOVC3 #KEY_LEN,(R8),KEYBUF MOVC3 #KEY_LEN,(R6),(R8) MOVC3 #KEY_LEN,KEYBUF,(R6) 80$: CMPC3 #KEY_LEN-4,(R6),(R7) BLSSU 90$ MOVC3 #KEY_LEN,(R7),KEYBUF MOVC3 #KEY_LEN,(R6),(R7) CMPC3 #KEY_LEN-4,(R8),KEYBUF BLSSU 100$ MOVC3 #KEY_LEN,(R8),(R6) MOVC3 #KEY_LEN,KEYBUF,(R8) 90$: MOVC3 #KEY_LEN,(R6),KEYBUF ; Take middle as pivot 100$: MOVC3 #KEY_LEN,KEY_LEN(R8),(R6) ADDL3 #KEY_LEN,R8,R6 ; R6 is low empty 105$: SUBL2 #KEY_LEN,R7 ; R7 will be high 110$: CMPC3 #KEY_LEN-4,KEYBUF,(R7) ; Find high empty BGTRU 120$ SUBL2 #KEY_LEN,R7 BRB 110$ 120$: CMPL R6,R7 ; Make sure we aren't done BGTRU 160$ MOVC3 #KEY_LEN,(R7),(R6) ; Fill low empty ADDL2 #KEY_LEN,R6 ; and find a new one 130$: CMPC3 #KEY_LEN-4,KEYBUF,(R6) BLSSU 140$ ADDL2 #KEY_LEN,R6 BRB 130$ 140$: CMPL R6,R7 ; Make sure we aren't done BGTRU 150$ MOVC3 #KEY_LEN,(R6),(R7) ; Fill high empty BRB 105$ ; and continue 150$: MOVL R7,R6 160$: MOVC3 #KEY_LEN,KEYBUF,(R6) ; Done! Move pivot in PUSHAL KEY_LEN(R6) ; Push high partition on stack PUSHL R9 MOVL R6,R7 MOVL R8,R6 BRW 10$ .PAGE .SBTTL DATA .PSECT DATA_WRT,LONG,NOEXE,RD,WRT,NOSHR,GBL ; RMS data structures .ALIGN LONG PORTFAB: $FAB FAC=GET RMS_FNM FAB=PORTFAB,FNM= PORTRAB: $RAB FAB=PORTFAB,UBF=LOCBUF,USZ=255 SYSOUT: $FAB FAC=PUT,RAT=CR RMS_FNM FAB=SYSOUT,FNM= OUTRAB: $RAB FAB=SYSOUT,RBF=HDRBUF .PSECT DATA_RD,BYTE,RD,NOWRT,NOEXE,SHR,GBL ; Read only structures ALLOC: .ASCII \(Alloc)\ ; Allocated message ALLOCL=.-ALLOC AMBIG_CTR: ; FAO string for ambiguous switch msg. .ASCID \Ambiguous keyword !AD encountered, !AC assumed\ BAD_SYNTAX_CTR: ; FAO string for bad search string .ASCID \!AS is invalid syntax.\ BADDEV: ; List of device types not to include ; in allocation list .WORD ^A\XM\ ; DECNET .WORD ^A\DR\ ; Standard disk .WORD ^A\DB\ ; Standard disk .WORD ^A\NE\ ; More DECNET .WORD ^A\XE\ ; Yet more DECNET .WORD ^A\PT\ ; MODEL Windows .WORD ^A\XG\ ; Some CERN-DD garbage .WORD ^A\LN\ ; LN03's .WORD 0 BADPRCNAM: ; List of process names not to be ; output ; .ASCIC \NETACP\ .BYTE 0 BADUSRNAM: ; List of usernames not to be output .ASCIC \JOB_CONTROL\ ; Job controller .BYTE 0 BATCTR: .ASCID \queue !AF, entry !UL\ ; Batch queue location FAO control str GETPID: ; GETJPI list to get non-term. PIDs .WORD 4,JPI$_PID .ADDR PID .LONG 0,0 GETSUB: ; GETJPI list to get owner PID .WORD 4,JPI$_PID ; PID .ADDR RETPID .LONG 0 .WORD 4,JPI$_OWNER ; OWNER PID .ADDR OWNPID .LONG 0,0 GETUSR: ; GETJPI list to get username .WORD 12,JPI$_USERNAME .ADDR USRNAM .ADDR USRLEN .LONG 0 LONG_CPU_FAO: ; FAO call list for long CPU time $FAOL CTRSTR=LONG_TIME_CTR,OUTBUF=CPUDSC,PRMLST=TIME_PLIST LONG_ELAP_FAO: ; FAO call list for long elapsed time $FAOL CTRSTR=LONG_TIME_CTR,OUTBUF=TIMEDSC,PRMLST=TIME_PLIST LONG_TIME_CTR: ; Long Time FAO control string .ASCID \!3UL:!2ZL:!2ZL.!1ZL\ MOVTC_TAB: ; Table for MOVTC ASCII_TAB <<0-31>,<127-255>>,<.> FILL_CHAR=^A\.\ MTACTR: .ASCID \!AD is in use by !AD\ ; Device allocation FAO control string NO_SWIT_CTR: ; String for no match message .ASCID \!AS not a valid switch.\ NO_USR: .ASCII \No info \ ; No username message NO_USR_LEN=.-NO_USR NOCPU: .ASCII \ NO INFO\ ; No CPU info. message NO_NUMBER: ; No info. message .ASCII \ NO INF\ PHMEM_LIST: ; Arg. list for OTS$CVT_L_TI .LONG 3 .ADDR PHYS_MEM .ADDR TMPDSC .LONG 1 PHMEM_NO: ; No info. message .ASCII \NONE\ PID_LIST: ; Argument list for OTS$CVT_L_TZ call .LONG 3 ; by PID output routine .ADDR PID .ADDR TMPDSC .LONG 8 PRIO_CTR: ; Priority FAO control string .ASCID \!2UL/!2\ PRIO_NO: ; No info message .ASCII @ ?/? @ RECDSC: .LONG 256 ; Output record descriptor .ADDR RECBUF RT_LOC: .ASCII \Remote node\ ; RTxn type locations RT_LOC_LEN=.-RT_LOC RT_TYPE=^A\RT\ SHORT_CPU_CTR: ; Short CPU time FAO control string .ASCID \!3UL:!2ZL.!1ZL\ SHORT_CPU_FAO: ; FAO call list for short CPU $FAOL CTRSTR=SHORT_CPU_CTR,OUTBUF=CPUDSC,PRMLST=TIME_PLIST SHORT_ELAP_CTR: ; Short elapsed time FAO control string .ASCID \!4UL:!2ZL\ SHORT_ELAP_FAO: ; FAO call list for short elapsed time $FAOL CTRSTR=SHORT_ELAP_CTR,OUTBUF=TIMEDSC,PRMLST=TIME_PLIST STATE_TAB: ; State types STATETYP , STATETYP CEF STATETYP COLPG STATETYP COM STATETYP COMO STATETYP CUR STATETYP FPG STATETYP HIB STATETYP HIBO STATETYP LEF STATETYP LEFO STATETYP MWAIT STATETYP PFW STATETYP SUSP STATETYP SUSPO TRIM_LIST: ; Argument lists for calls to STR$TRIM .LONG 3 .ADDR TMPDSC .ADDR TMPDSC .ADDR TMPDSC TRIM_LIST_2: .LONG 3 .ADDR RECLEN .ADDR RECLEN .ADDR RECLEN TRMCTR: .ASCID \!AC!UW:\ ; Terminal FAO control string TRMDSC: .LONG TERM_BUF_LEN ; Terminal name descriptor .ADDR TRMBUF VT_TYPE=^A\VT\ ; Summary line FAO control strings SUMCTR: .ASCID \ !+!SL/!SL terminals in use at !+!%T\ SUMCTR_NODE: .ASCID \ !+!SL/!SL terminals in use on node !AS at !%T\ SUMCTR_MATCH: .ASCID \ !SL matches with !SL/!SL terminals in use at !+!%T\ SUMCTR_MATCH_NODE: .ASCID \ !SL matches with !SL/!SL terminals in use on node !AS at !%T\ SYSNODE: ; Current node logical name .ASCID \SYS$NODE\ TRMTAB: ; terminal types TTYTYP UNKNOWN TTYTYP VT05 TTYTYP VK100 TTYTYP VT173 TTYTYP TQ_BTS TTYTYP TEK401X TTYTYP FT1,I100 TTYTYP FT2, TTYTYP FT3,ADDS100 TTYTYP FT4, TTYTYP FT5, TTYTYP FT6, TTYTYP FT7, TTYTYP FT8, TTYTYP LA36 TTYTYP LA120 TTYTYP LA34 TTYTYP LA38 TTYTYP LA12 TTYTYP LA100 TTYTYP LA24 TTYTYP LN03 TTYTYP LQP02 TTYTYP LA84 TTYTYP VT52 TTYTYP VT55 TTYTYP VT100 TTYTYP VT101 TTYTYP VT102 TTYTYP VT105 TTYTYP VT125 TTYTYP VT131 TTYTYP VT132 TTYTYP VT200_Series,VT200 TTYTYP Pro_Series,PRO TRMTABLEN=.-TRMTAB/4 ; save upper limit BATTRM=.-TRMTAB/4 ; Batch type .SAVE_PSECT .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL 10$: .ASCIC /BATCH/ .RESTORE_PSECT .ADDR 10$ SUBTRM=.-TRMTAB/4 ; Subprocess type .SAVE_PSECT .PSECT STRINGS,BYTE,RD,NOWRT,NOEXE,SHR,GBL 20$: .ASCIC /SUB-PRC/ .RESTORE_PSECT .ADDR 20$ UIC_CTR: ; Control string for UIC .ASCID \[!3OW,!3OW]\ UIC_NONE: .ASCII \[ NO UIC]\ ; Message with no UIC WSET_LIST: ; Arg. list for OTS$CVT_L_TI .LONG 3 .ADDR WORK_SET .ADDR TMPDSC .LONG 1 WSET_NO: ; No info. message .ASCII \NONE\ .PSECT DATA_WRT,LONG,NOEXE,RD,WRT,NOSHR,GBL ; Read/Write data areas ACCVIO: .BLKW 8 ; for handlers to save accvio sig args CUR_TIME: ; Current system time .QUAD DONEPIDS: ; PIDs already processed ; .LONG 0[96] .LONG 0[192] DONEPIDS_LEN=.-DONEPIDS FNDNUM: .LONG 0 ; Number of search matches FLAGS: .LONG 0 FLAGS2: .LONG 0 GETDEVARG: .LONG 7 ; # of args DDB_ARG: .LONG 1 ; Indicate first pass through ; (system addrs negative) UCB_ARG: .LONG 0 ; For UCB .ADDR PID ; And pid .ADDR TRMLEN ; For terminal length .ADDR TRMDSC ; For terminal name TYPE_ARG: .LONG 0 ; For terminal type CLASS_ARG: .LONG DC$_TERM ; Specify looking for terminal JPILST: ; GETJPI list for everything .WORD USR_BUF_LEN,JPI$_USERNAME ; Username .ADDR USRNAM .ADDR USRLEN .WORD TERM_BUF_LEN,JPI$_TERMINAL ; Login terminal .ADDR LGNTRM .ADDR LGNTRML .WORD PRC_BUF_LEN,JPI$_PRCNAM ; Process name .ADDR PRCNAM .ADDR PRCLEN .WORD 4,JPI$_PRCCNT ; # sub-processes .ADDR SUBNUM .LONG 0 .WORD 4,JPI$_OWNER ; Process owner .ADDR OWNER_PID .LONG 0 .WORD IMAG_BUF_LEN,JPI$_IMAGNAME ; Executing image .ADDR IMGNAM .ADDR IMGLEN GETJPI_END: .LONG 0[<2*11>+1] .WORD 0[2*11] HDRBUF: .BLKB 256 ; Title buffer KEYBUF: .BLKB KEY_LEN ; Working storage for sort LOCBUF: .BLKB 256 ; Location buffer LOCLEN: .LONG 0 ; Location descriptor .ADDR LOCBUF LSTPID: .ADDR DONEPIDS ; Next open position in DONEPIDS MAP_PAGES: ; Pages global section mapped to .BLKQ 2 NEXT_SKEY: .LONG ; Next available sort key postion NODE: .LONG 64 ; Node name descriptor .ADDR .+4 .BLKB 64 NUMBER_LIST: ; Argument list for OTS$CVT_L_TI call .LONG 3 .BLKL 1 .ADDR TMPDSC .LONG 1 OWNPID: .LONG 0 ; Process owner PID PID: .BLKL 1 ; PID PIDQUE: .ADDR PIDQUE ; Queue of sub-proc PID's .ADDR PIDQUE ; .BLKL 96*3 ; Will hold 96 .BLKL 192*3 ; Will hold 192 PORTPASS: ; Count of passes through port file .BLKL 1 RECBUF: .BLKB 256 ; Output record buffer RECLEN: .LONG 256 ; Output record length .ADDR RECBUF RECUPP: .LONG 256 ; Upper case record .ADDR .+4 .BLKB 256 RESTPID: .LONG -1 ; Wild card PID for non-term. jobs RETPID: .BLKL 1 ; Return PID (for subprocs) SORT_DATA: ; Start of sort virtual memory .LONG TIME_PLIST: ; FAO param. list for times .BLKL 4 TMPDSC: .BLKL 2 ; Space for a temporary descriptor TRMLEN: .LONG 0 ; Terminal name length .ADDR TRMBUF TRMBUF: .BYTE BLANK[TERM_BUF_LEN] ; Terminal name buffer TRMNO: .LONG 0 ; Total number of terminals TRMNOU: .LONG 0 ; Number of terminals in use USR_FIELD_END: ; End of username output .LONG 0 USR_FIELD_LEN: ; Length of username output .LONG 0 WILDPID: ; Wildcard PID .LONG -1 VALUE_BUF: ; All things which should be initialized before GETJPI BASE_PRIO: .LONG 0 ; Process base priority BUF_IO: .LONG 0 ; Buffered I/O count CPUDSC: .LONG 8 ; Descriptor for CPU time .ADDR .+4 CPUSTR: .BYTE BLANK[11] ; Buffer for CPU time formatting CPUTIM: .LONG 0 ; CPU time DIR_IO: .LONG 0 ; Direct I/O count IMGLEN: .LONG 0 ; Image name length .ADDR IMGNAM IMGNAM: .BYTE BLANK[IMAG_BUF_LEN] ; Image name buffer LGNTRML: ; Login terminal length .LONG 0 .ADDR LGNTRM LGNTRM: .BYTE BLANK[TERM_BUF_LEN] ; Login terminal LOGIN_TIME: ; Login time .QUAD 0 OWNER_PID: ; Process owner PID .LONG 0 PAGE_FLTS: .LONG 0 ; Page faults PHYS_MEM: ; Pages in memory .LONG 0 PRCLEN: .LONG 0 ; Process name length .ADDR PRCNAM PRCNAM: .BYTE BLANK[PRC_BUF_LEN] ; Process name buffer PRIO: .LONG 0 ; Process priority STATE: .LONG 0 ; State SUBNUM: .LONG 0 ; Number of sub processes TIMEDSC: ; Descriptor for elapsed time .LONG 7 .ADDR TIMESTR TIMESTR: ; Buffer for elapsed time .BYTE BLANK[11] UIC: .LONG 0 ; Process UIC USRLEN: .LONG 0 ; Username length .ADDR USRNAM USRNAM: .BYTE BLANK[USR_BUF_LEN+PRC_BUF_LEN+3] ; Username buffer WORK_SET: .LONG 0 ; Working set size VALUE_BUF_LEN=.-VALUE_BUF MASTER_BUF: ; Copy of VALUE_BUF .BLKB VALUE_BUF_LEN .PAGE .SBTTL OUTPUT TABLES ; ; This is the area in which all flags are defined and output ; routines included. ; ; Each flag should have a call to OUTTAB macro to define it (this ; will define ITM_V_name and ITM_M_name (offset and mask)). For output ; flags the following additional information is required by the OUTTAB ; macro: ; HEAD - Title of the output field. This is included ; on the header line. If the output field has ; a leading blank the character BLANK_FILL should ; be used instead. ; HEAD_LONG - Title of the output field with "long" output. ; (will default to HEAD if not included) ; JPI - GETJPI symbol to be included in GETJPI list ; (JPI$_'JPI'). (optional) ; JPISIZ - Size of buffer for GETJPI information. ; (defaults to 4) ; JPIBUF - Buffer for GETJPI information. (required if ; JPI present) ; JPILEN - Longword to return length of JPIBUF used. ; (defaults to 0 (no return)) ; JPI2 - Same as JPI but for a second value. (optional) ; JPISIZ2 - Size of buffer for GETJPI information. ; (defaults to 4) ; JPIBUF2 - Buffer for GETJPI information. (required if ; JPI2 present) ; JPILEN2 - Longword to return length of JPIBUF2 used. ; (defaults to 0 (no return)) ; ; For flags dealing with command switches the following is used. ; SWITCH - TPARSE switch to be included for this item. ; ; After the call to OUTTAB for an output flag one should use the macro ; OUTRTN to establish the start of an output routine. Include the ; routine, and terminate it with a call to ENDRTN. These routines ; will add output to the output buffer. They should consist of a single ; entry and exit (top to bottom). They may use all registers but FP and ; SP must be restored to their original position, and AP contains the ; address of the next available byte in the output buffer and should ; be updated by the routine. Each routine can be considered as its ; own local block for local lable purposes. ; ; The flag ITM_V_LONG will be set in FLAGS for long format output. ; The flag ITM_V_FIRST will be set in FLAGS2 for the first output field. ; ; The macro INSERT_BLANK can be used to insert an optional leading blank ; (left out only if the field is the first one). ; ; The macro ALLOCATED causes a branch to the indicated label if the ; terminal is not allocated or there is no login terminal. If any ; parameter is included for NOT the opposite will occur (branch if ; the terminal IS allocated AND there is a login terminal. Format is: ; ALLOCATED LABEL[,NOT] BLANK_FILL= ^A\~\ ; Character to indicate leading blank ; Flags for the various items, and output formats OUTTAB INT,SWITCH=INTERACTIVE ; /INTERACTIVE OUTTAB BAT,SWITCH=BATCH ; /BATCH OUTTAB SORT,SWITCH=SORT ; /SORT OUTTAB SUB,SWITCH=SUBPROCESSES ; /SUBPROCESSES MULTI_SWITCH FLAGS=ITM_M_BAT!ITM_M_SUB!ITM_M_SORT!ITM_M_INT,- SWITCH=FULL OUTTAB TYPE=PID,HEAD=<~ PID >,SWITCH=PID ; /PID OUTRTN PID INSERT_BLANK MOVL #8,TMPDSC ; Convert to hex MOVL AP, CALLG PID_LIST,G^OTS$CVT_L_TZ ADDL2 #8,AP ; Update AP ENDRTN PID OUTTAB TYPE=USER,HEAD=<~Username>,- ; /USERNAME HEAD_LONG=<~Username >,SWITCH=USERNAME OUTRTN USER INSERT_BLANK MOVL USRLEN,R7 BEQL 10$ MOVL R7,TMPDSC MOVAB USRNAM, ; Trim user name CALLG TRIM_LIST,G^STR$TRIM MOVZWL TMPDSC,R7 MOVL R7,USR_FIELD_LEN BEQL 10$ BRB 20$ 10$: MOVZWL #NO_USR_LEN,R7 ; No info. MOVC3 #NO_USR_LEN,NO_USR,USRNAM MOVL R7,USR_FIELD_LEN 20$: MOVZWL #8,R6 ; Set field length BBS #ITM_V_LONG,FLAGS,25$ CMPL #8,USR_FIELD_LEN BGEQ 30$ MOVZWL #8,USR_FIELD_LEN BRB 30$ 25$: MOVZWL #12,R6 CMPL #12,USR_FIELD_LEN BGEQ 30$ MOVZWL #12,USR_FIELD_LEN 30$: MOVC5 R7,USRNAM,#BLANK,R6,(AP) ; Move string ADDL3 AP,USR_FIELD_LEN,USR_FIELD_END ADDL2 R6,AP ENDRTN USER OUTTAB TYPE=PROC,HEAD=<~(proc) >,- ; /PROCESS_NAME HEAD_LONG=<~(process name) >,- SWITCH=PROCESS_NAME OUTRTN PROC BBC #ITM_V_USER,FLAGS,10$ ; Concatenate to user CMPL USR_FIELD_END,AP BGEQ 10$ MOVL USR_FIELD_END,AP 10$: INSERT_BLANK MOVW PRCLEN,TMPDSC BEQL 20$ MOVAB PRCNAM, ; Trim process name CALLG TRIM_LIST,G^STR$TRIM MOVW TMPDSC,PRCLEN BEQL 20$ CMPC5 USRLEN,USRNAM,#BLANK,PRCLEN,PRCNAM BEQL 20$ ; Include process name? CMPB #^A\_\,PRCNAM BNEQ 30$ CMPL #^A\_JOB\,PRCNAM BEQL 20$ CMPL ,TRMBUF BNEQ 30$ 20$: CLRW TMPDSC 30$: BBC #ITM_V_USER,FLAGS,40$ ; Yes, add process name SUBL3 USR_FIELD_LEN,#<17-1>,R7 BBC #ITM_V_LONG,FLAGS,50$ SUBL3 USR_FIELD_LEN,#,R7 BRB 50$ 40$: MOVL #<17-8-1>,R7 BBC #ITM_V_LONG,FLAGS,50$ MOVL #,R7 50$: TSTW TMPDSC BEQL 60$ CMPL #2,R7 BGEQ 60$ SUBL2 #2,R7 MOVB #^A\(\,(AP)+ CMPW R7,PRCLEN BLEQ 55$ MOVC3 PRCLEN,PRCNAM,(AP) ADDL2 PRCLEN,AP MOVB #^A\)\,(AP)+ SUBL2 PRCLEN,R7 MOVC5 #0,(AP),#BLANK,R7,(AP) ADDL2 R7,AP BRB 70$ 55$: MOVC3 R7,PRCNAM,(AP) ADDL2 R7,AP MOVB #^A\)\,(AP)+ BRB 70$ 60$: MOVC5 #0,(AP),#BLANK,R7,(AP) ADDL2 R7,AP 70$: ENDRTN PROC OUTTAB TYPE=UIC,HEAD=<~ UIC >,JPI=UIC,JPIBUF=UIC,- ; /UIC SWITCH=UIC OUTRTN UIC INSERT_BLANK TSTL UIC BEQL 10$ MOVL #9,TMPDSC ; Set up for FAO MOVL AP, $FAO_S CTRSTR=UIC_CTR,OUTBUF=TMPDSC,P1=UIC+2,P2=UIC BRB 20$ 10$: MOVC3 #9,UIC_NONE,(AP) ; No UIC 20$: ADDL2 #9,AP ENDRTN UIC OUTTAB TYPE=TTY,HEAD=<~ TTY >,SWITCH=TERMINAL ; /TERMINAL OUTRTN TTY INSERT_BLANK BBS #ITM_V_HASTTY,FLAGS2,40$ 10$: TSTW LGNTRML ; For non-interactive jobs BEQL 40$ MOVAB LGNTRM,R0 ; It has a login terminal! 20$: CMPB #^A\_\,(R0) BNEQ 30$ INCL R0 DECW LGNTRML BEQL 40$ BRB 20$ 30$: MOVZWL LGNTRML,R1 DECL R1 CMPB #^A\:\,LGNTRM[R1] BNEQ 35$ DECW LGNTRML 35$: MOVC5 LGNTRML,(R0),#BLANK,#7,(AP) ; Use it MOVL R3,AP BRB 50$ 40$: LOCC #^A\:\,#7,TRMBUF ; Move in 6 characters SUBL2 #TRMBUF,R1 MOVC5 R1,TRMBUF,#BLANK,#7,(AP) MOVL R3,AP 50$: ENDRTN TTY OUTTAB TYPE=TYPE,HEAD=<~ Type >,SWITCH=TYPE ; /TYPE OUTRTN TYPE INSERT_BLANK TSTL OWNER_PID BEQL 10$ ; Sub-proc? MOVL #SUBTRM,R6 ; Yes, set type to SUB-PROC BRB 40$ 10$: BBC #ITM_V_BAT1,FLAGS2,20$ ; No, Batch job? MOVL #BATTRM,R6 ; Yes, set type to BATCH BRB 40$ 20$: BBS #ITM_V_HASTTY,FLAGS2,30$ ; No, non-interactive? MOVC5 #0,(AP),#BLANK,#7,(AP) ; Yes, blank field BRB 50$ 30$: MOVL TYPE_ARG,R6 ; No, use terminal type BLSS 35$ ; set unkn type if invalid CMPL R6,#TRMTABLEN ; past end of table? BLSS 40$ ; no, branch, it's ok 35$: MOVL #TT$_UNKNOWN,R6 ; yes, set unknown type 40$: MOVL TRMTAB[R6],R0 MOVZBL (R0)+,R1 MOVC5 R1,(R0),#BLANK,#7,(AP) 50$: ADDL2 #7,AP ENDRTN TYPE OUTTAB TYPE=IMAGE,HEAD=<~ Image >,- ; /IMAGE HEAD_LONG=<~ Image >,- SWITCH=IMAGE OUTRTN IMAGE INSERT_BLANK MOVL #9,R6 BBC #ITM_V_LONG,FLAGS,5$ MOVL #36,R6 5$: BBC #ITM_V_ALLOTRM,FLAGS2,10$ TSTW LGNTRML ; Login terminal? BEQL 10$ ; No then image=(alloc) MOVC5 #ALLOCL,ALLOC,#BLANK,R6,(AP) BRB 30$ 10$: ; TRIM_FILESPEC doesn't work for hidden device strings, such as those ; of system images ([SYS0.][SYSEXE]) so help out by first looking for ; ".]" or ".>" MOVZWL #^A/.]/,-(SP) ; object substring buf MATCHC #2,(SP),IMGLEN,IMGNAM ; look for substring match BEQL 15$ ; match found? yes, branch MOVZWL #^A/.>/,(SP) ; no, try another substring MATCHC #2,(SP),IMGLEN,IMGNAM ; match? BEQL 15$ ; yes, branch MOVZWL IMGLEN,R2 ; no, pick up entire string MOVAB IMGNAM,R3 15$: TSTL (SP)+ ; clean off substring ; build descr on stack PUSHL R3 ; addr one beyond last byt match PUSHL R2 ; num bytes remaining in src str PUSHL AP ; build descr for output str PUSHL R6 ; with width count for trim PUSHAQ (SP) ; addr of output str descr PUSHAQ 12(SP) ; addr of input str descr CALLS #2,G^LIB$TRIM_FILESPEC ; trim MOVAL 16(SP),SP ; clean off descriptors BLBS R0,30$ ; did trim work? MOVC5 #0,#0,#BLANK,R6,(AP) ; no, blank fill BRB 40$ 30$: ; Some folks think .EXE looks tacky in short form BBS #ITM_V_LONG,FLAGS,40$ ; is it long fmt? yes, branch MOVL #^A/.EXE/,-(SP) ; no, get substring for search MATCHC #4,(SP),R6,(AP) ; look for it BNEQ 35$ ; found? no, branch ADDL #4,R2 ; yes, include .EXE in count SUBL #4,R3 ; backup to point to . of .EXE MOVC5 #0,#0,#BLANK,R2,(R3) ; wipe out 35$: TSTL (SP)+ ; clean of substring 40$: ADDL2 R6,AP ENDRTN IMAGE OUTTAB TYPE=STATE,JPI=STATE,JPIBUF=STATE,- ; /STATE HEAD=<~State>,SWITCH=STATE OUTRTN STATE INSERT_BLANK ALLOCATED 10$ MOVC5 #0,(AP),#BLANK,#5,(AP) ; No state, or alloc. BRB 20$ 10$: MOVL STATE,R0 MOVL STATE_TAB[R0],R0 MOVZBL (R0)+,R1 MOVC5 R1,(R0),#BLANK,#5,(AP) 20$: ADDL2 #5,AP ENDRTN STATE OUTTAB TYPE=PRIO,JPI=PRI,JPIBUF=PRIO,- ; /PRIORITY JPI2=PRIB,JPIBUF2=BASE_PRIO,HEAD=<~Prio.>,- SWITCH=PRIORITY OUTRTN PRIO INSERT_BLANK ALLOCATED 10$ MOVC5 #0,(AP),#BLANK,#5,(AP) ; Blank for alloc. BRB 30$ 10$: TSTL BASE_PRIO BNEQ 20$ MOVC3 #5,PRIO_NO,(AP) ; No info. BRB 30$ 20$: MOVL #5,TMPDSC MOVL AP, $FAO_S CTRSTR=PRIO_CTR,OUTBUF=TMPDSC,P1=PRIO,P2=BASE_PRIO 30$: ADDL2 #5,AP ENDRTN PRIO OUTTAB TYPE=DIRIO,JPI=DIRIO,JPIBUF=DIR_IO,- ; /DIRECT_IO HEAD=< Dir IO>,HEAD_LONG=<~ Direct I/O>,- SWITCH= OUTRTN DIRIO BBC #ITM_V_LONG,FLAGS,10$ INSERT_BLANK 10$: ALLOCATED 30$ BBS #ITM_V_LONG,FLAGS,20$ ; Alloc. = blank MOVC5 #0,(AP),#BLANK,#7,(AP) BRB 70$ 20$: MOVC5 #0,(AP),#BLANK,#11,(AP) BRB 70$ 30$: TSTL DIR_IO BGTR 50$ BBC #ITM_V_LONG,FLAGS,40$ ; Zero gets no info MOVB #^A\-\,(AP) MOVW #^A\O \,8(AP) MOVB #^A\-\,10(AP) MOVC3 #7,NO_NUMBER,1(AP) BRB 70$ 40$: MOVC3 #7,NO_NUMBER,(AP) BRB 70$ 50$: MOVL #7,TMPDSC BBC #ITM_V_LONG,FLAGS,60$ MOVL #11,TMPDSC 60$: MOVL AP, MOVAL DIR_IO, CALLG NUMBER_LIST,G^OTS$CVT_L_TI 70$: ADDL2 #7,AP BBC #ITM_V_LONG,FLAGS,80$ ADDL2 #4,AP 80$: ENDRTN DIRIO OUTTAB TYPE=BUFIO,JPI=BUFIO,JPIBUF=BUF_IO,- ; /BUFFERED_IO HEAD=< Buf IO>,HEAD_LONG=<~Buffered IO>,- SWITCH= OUTRTN BUFIO BBC #ITM_V_LONG,FLAGS,10$ INSERT_BLANK 10$: ALLOCATED 30$ BBS #ITM_V_LONG,FLAGS,20$ ; Alloc. = blank MOVC5 #0,(AP),#BLANK,#7,(AP) BRW 70$ 20$: MOVC5 #0,(AP),#BLANK,#11,(AP) BRB 70$ 30$: TSTL BUF_IO BGTR 50$ BBC #ITM_V_LONG,FLAGS,40$ ; Zero gets no info MOVB #^A\-\,(AP) MOVW #^A\O \,8(AP) MOVB #^A\-\,10(AP) MOVC3 #7,NO_NUMBER,1(AP) BRB 70$ 40$: MOVC3 #7,NO_NUMBER,(AP) BRB 70$ 50$: MOVL #7,TMPDSC BBC #ITM_V_LONG,FLAGS,60$ MOVL #11,TMPDSC 60$: MOVL AP, MOVAL BUF_IO, CALLG NUMBER_LIST,G^OTS$CVT_L_TI 70$: ADDL2 #7,AP BBC #ITM_V_LONG,FLAGS,80$ ADDL2 #4,AP 80$: ENDRTN BUFIO OUTTAB TYPE=PAGEFLTS,JPI=PAGEFLTS,JPIBUF=PAGE_FLTS,- ; /PAGE_FAULTS HEAD=< Pg flt>,HEAD_LONG=<~Page faults>,- SWITCH= OUTRTN PAGEFLTS BBC #ITM_V_LONG,FLAGS,10$ INSERT_BLANK 10$: ALLOCATED 30$ BBS #ITM_V_LONG,FLAGS,20$ ; Alloc. = blank MOVC5 #0,(AP),#BLANK,#7,(AP) BRW 70$ 20$: MOVC5 #0,(AP),#BLANK,#11,(AP) BRB 70$ 30$: TSTL PAGE_FLTS BGTR 50$ BBC #ITM_V_LONG,FLAGS,40$ ; Zero gets no info MOVB #^A\-\,(AP) MOVW #^A\O \,8(AP) MOVB #^A\-\,10(AP) MOVC3 #7,NO_NUMBER,1(AP) BRB 70$ 40$: MOVC3 #7,NO_NUMBER,(AP) BRB 70$ 50$: MOVL #7,TMPDSC BBC #ITM_V_LONG,FLAGS,60$ MOVL #11,TMPDSC 60$: MOVL AP, MOVAL PAGE_FLTS, CALLG NUMBER_LIST,G^OTS$CVT_L_TI 70$: ADDL2 #7,AP BBC #ITM_V_LONG,FLAGS,80$ ADDL2 #4,AP 80$: ENDRTN PAGEFLTS OUTTAB TYPE=WSET,JPI=WSSIZE,JPIBUF=WORK_SET,- ; /WORKING_SET HEAD=<~Wset>,SWITCH= OUTRTN WSET INSERT_BLANK ALLOCATED 10$ MOVC5 #0,(AP),#BLANK,#4,(AP) ; Alloc. BRB 30$ 10$: TSTL WORK_SET BNEQ 20$ MOVC3 #4,WSET_NO,(AP) ; No info. BRB 30$ 20$: MOVL #4,TMPDSC MOVL AP, CALLG WSET_LIST,G^OTS$CVT_L_TI 30$: ADDL2 #4,AP ENDRTN WSET OUTTAB TYPE=PHMEM,JPI=PPGCNT,JPIBUF=PHYS_MEM,- ; /PHYSICAL_MEMORY HEAD=<~ Mem>,SWITCH= OUTRTN PHMEM INSERT_BLANK ALLOCATED 10$ MOVC5 #0,(AP),#BLANK,#4,(AP) ; Alloc. BRB 30$ 10$: TSTL PHYS_MEM BNEQ 20$ MOVC3 #4,PHMEM_NO,(AP) ; No info. BRB 30$ 20$: MOVL #4,TMPDSC MOVL AP, CALLG PHMEM_LIST,G^OTS$CVT_L_TI 30$: ADDL2 #4,AP ENDRTN PHMEM OUTTAB TYPE=CPU,JPI=CPUTIM,JPIBUF=CPUTIM,- ; /CPU_TIME HEAD=< CPU >,HEAD_LONG=<~ CPU >,- SWITCH= OUTRTN CPU BBC #ITM_V_LONG,FLAGS,5$ INSERT_BLANK 5$: ALLOCATED 10$ MOVC5 #0,TIMESTR,#BLANK,#11,TIMESTR BRW 50$ 10$: TSTL CPUTIM BNEQ 30$ ; If zero, say -NO INFO- MOVAB CPUSTR,R0 BBC #ITM_V_LONG,FLAGS,20$ MOVW #^A\ -\,CPUSTR MOVB #^A\-\, ADDL2 #2,R0 20$: MOVC3 #8,NOCPU,(R0) BRW 50$ 30$: ADDL2 #5,CPUTIM ; Otherwise... DIVL3 #6000,CPUTIM,R3 ; Get minutes MULL3 #6000,R3,R5 SUBL2 R5,CPUTIM DIVL3 #100,CPUTIM,R4 ; Get seconds MULL3 #100,R4,R5 SUBL2 R5,CPUTIM DIVL2 #10,CPUTIM ; Get tenths of seconds BBS #ITM_V_LONG,FLAGS,40$ ; format string MOVQ R3,TIME_PLIST MOVL CPUTIM, $FAOL_G SHORT_CPU_FAO BRB 50$ 40$: DIVL3 #60,R3,TIME_PLIST ; Get hours MULL3 #60,TIME_PLIST,R2 SUBL2 R2,R3 MOVQ R3, MOVL CPUTIM, $FAOL_G LONG_CPU_FAO 50$: MOVC3 CPUDSC,CPUSTR,(AP) ADDL2 CPUDSC,AP ENDRTN CPU OUTTAB TYPE=ELAPSED,JPI=LOGINTIM,JPIBUF=LOGIN_TIME,- ; /ELAPSED_TIME JPISIZ=8,HEAD=< Time >,HEAD_LONG=<~ Elapsed >,- SWITCH= OUTRTN ELAPSED BBC #ITM_V_LONG,FLAGS,5$ INSERT_BLANK 5$: ALLOCATED 10$ MOVC5 #0,TIMESTR,#BLANK,#11,TIMESTR 10$: TSTL LOGIN_TIME BNEQ 30$ ; If zero, say -NO INFO- MOVAB TIMESTR,R0 BBC #ITM_V_LONG,FLAGS,20$ MOVW #^A\ -\,TIMESTR MOVW #^A\- \, ADDL2 #2,R0 20$: MOVC3 #7,,(R0) BRW 50$ 30$: $GETTIM_S TIMADR=CUR_TIME ; Otherwise... SUBL2 LOGIN_TIME,CUR_TIME ; Get delta SBWC , EDIV #100000,CUR_TIME,R3,R4 ADDL2 #5,R3 DIVL3 #6000,R3,R4 ; Get minutes MULL3 #6000,R4,R5 SUBL2 R5,R3 DIVL3 #100,R3,R5 ; Get seconds BBS #ITM_V_LONG,FLAGS,40$ ; format string MOVQ R4,TIME_PLIST $FAOL_G SHORT_ELAP_FAO BRB 50$ 40$: MULL3 #100,R5,R6 SUBL2 R6,R3 DIVL3 #10,R3, ; Get tenths of seconds DIVL3 #60,R4,TIME_PLIST ; Get hours MULL3 #60,TIME_PLIST,R0 SUBL2 R0,R4 MOVQ R4, $FAOL_G LONG_ELAP_FAO 50$: MOVC3 TIMEDSC,TIMESTR,(AP) ADDL2 TIMEDSC,AP ENDRTN ELAPSED OUTTAB TYPE=LOC,HEAD=<~ Location>,- ; /LOCATION HEAD_LONG=<~ Location>,SWITCH=LOCATION OUTRTN LOC INSERT_BLANK ; This assumes that this is the LAST field in the list. ; ; Note that the below algorithm is fastest when the terminals found ; (currently opa0 followed by all other terminals in alphanumeric order) ; are in the same order as they are in the ports file. Note that the ; algorithm is SLOWEST when they are in reverse order, and, if a terminal ; does not exist in the ports file, the program will go through that file ; TWICE (at worst case) to discover that fact. ; the terminal name to key on is expected to be the first 5 characters ; (including ":") of the line in the file record BBC #ITM_V_BAT1,FLAGS2,20$ BBS #ITM_V_LONG,FLAGS,10$ ; Batch job MOVC5 LOCLEN,@,#BLANK,#30,(AP) ADDL2 #30,AP BRW 110$ 10$: MOVC3 LOCLEN,@,(AP) ADDL2 LOCLEN,AP BRW 110$ 20$: BBS #ITM_V_HASTTY,FLAGS2,50$ TSTW LGNTRML ; See if there is a login BNEQ 22$ BRW 110$ 22$: MOVZWL LGNTRML,TRMLEN MOVAB LGNTRM,R0 30$: CMPB #^A\_\,(R0) ; Get rid of leading _'s BNEQ 40$ DECL TRMLEN INCL R0 BRB 30$ 40$: MOVC3 TRMLEN,(R0),TRMBUF 50$: CMPW #RT_TYPE,TRMBUF ; Remote terminal BNEQ 70$ MOVC3 #RT_LOC_LEN,RT_LOC,(AP) ADDL2 #RT_LOC_LEN,AP 60$: BRW 110$ 70$: CMPW #VT_TYPE,TRMBUF BNEQ 77$ ; get physical name of virtual terminal PUSHL #0 ; end of list PUSHAW TRMLEN ; addr for returned length PUSHAB TRMBUF ; addr of buf PUSHL #DVI$_TT_PHYDEVNAM @16- ; code and buf len ! TERM_BUF_LEN MOVL SP,R0 ; get addr of list $GETDVIW_S - ; get phys term name DEVNAM=TRMLEN,- ITMLST=(R0) MOVAL 16(SP),SP ; clean off itmlst BLBS R0,76$ ; got a phys term name? BRW 110$ 76$: CMPB #^A/_/,TRMBUF ; name start with underscore? BNEQ 77$ ; no, got it right DECW TRMLEN ; reduce descr count by 1 MOVC3 TRMLEN,TRMBUF+1,TRMBUF ; shift string left by 1 77$: CLRL PORTPASS 80$: $GET RAB=PORTRAB ; Get a record BLBS R0,90$ ; If an error occurs in read TSTL PORTPASS ; Through file already? BEQL 85$ BBC #ITM_V_ALLOTRM,FLAGS2,83$ BRW 115$ ; Yes, then done 83$: BRW 120$ 85$: $REWIND RAB=PORTRAB ; No, try another pass INCL PORTPASS BRB 80$ 90$: ; Take into account comments LOCC #PORT_COMMENT,,LOCBUF SUBW2 R0, CMPW #5, BGTR 80$ ; No terminal here, loop CMPC5 TRMLEN,TRMBUF,#0,#5,LOCBUF BNEQ 80$ ; Not the same, loop LOCC #BLANK,PORTRAB+RAB$W_RSZ,LOCBUF SKPC #BLANK,R0,(R1) ; Get location descriptor BBS #ITM_V_LONG,FLAGS,100$ MOVC5 R0,(R1),#BLANK,#30,(AP) ; Short output ADDL2 #30,AP BRB 110$ 100$: MOVL R0,R6 MOVC3 R0,(R1),(AP) ADDL2 R6,AP 110$: BBC #ITM_V_ALLOTRM,FLAGS2,120$ MOVAB RECBUF, ; Say (alloc) if necessary SUBL3 #RECBUF,AP,TMPDSC CALLG TRIM_LIST,G^STR$TRIM ADDL3 TMPDSC,,AP 115$: MOVB #BLANK,(AP)+ MOVC3 #ALLOCL,ALLOC,(AP) ADDL2 #ALLOCL,AP 120$: ENDRTN LOC OUTTAB ALLO,SWITCH= ; /ALLOCATED_DEVICES OUTTAB ALL,SWITCH= ; /ALL_PROCESSES OUTTAB DCL,SWITCH= ; /DCL OUTTAB LONG,SWITCH=LONG ; /LONG MULTI_SWITCH FLAGS=ALL_OUT_FIELDS,SWITCH= OUTTAB EXACT,SWITCH=EXACT ; /EXACT OUTTAB MATCH.OR,SWITCH=MATCH.OR ; /MATCH=OR OUTTAB MATCH.AND,SWITCH=MATCH.AND ; /MATCH=AND OUTTAB MATCH.NOR,SWITCH=MATCH.NOR ; /MATCH=NOR OUTTAB MATCH.NAND,SWITCH=MATCH.NAND ; /MATCH=NAND FLAGDEF BAT1 ; Indicates cur. PID is batch FLAGDEF SUB1 ; Indicates cur. PID is sub. FLAGDEF SUB2 ; Indicates we are processing subs. FLAGDEF ALL1 ; Indicates current PID is non-INT. job FLAGDEF HASTTY ; Indicates this is from GETTTY FLAGDEF ALLOTRM ; Indicates terminal is not LOGIN one FLAGDEF FIRST ; Indicates this is first output field FLAGDEF SRCH ; Search string present .END WHERE