.TITLE SEND_FUNCTIONS -- Macro functions for the SEND command. .IDENT /01/ .LIBRARY "SYS$LIBRARY:LIB.MLB" ; ; Author: Mark Snititly ; Date: June 15, 1980 ; ; This file contains three functions that are employed by the Pascal SEND ; program: ; 1) GET_COMMANDLINE: ; Returns a string descriptor containing the current command line. ; 2) FIND_USER_NAME: ; Given the process's name, attempts to locate a unique process that ; has that name. Called only if process's name is not within the ; sending process's UIC group. Returns PID if successful. ; 3) FIND_USER_TERM: ; Given the PID of a process, returns a string descriptor containing ; the device name of the terminal allocated to the process. ;******************************************************************************* ; GET_COMMANDLINE: ; This routine returns the command line to the calling process. The only ; parameter is a string descriptor. ; ; Pascal external declaration: ; ; PROCEDURE GET_COMMANDLINE(VAR CMD_DSCR: STRDSCR); EXTERN; ; $CLIDEF ; command language interpreter definition $CLISERVDEF COM: $CLIREQDESC CLI$K_GETCMD FILL: .BYTE ^A/ / .ENTRY GET_COMMANDLINE,^M PUSHAB COM ; Push CLI request descriptor. CALLS #1,SYS$CLI ; Get the command line descriptor. MOVAQ COM+CLI$Q_RQDESC,R0 ; Put addr of command line dscr in R0. MOVL 4(AP),R1 ; Put addr of user's dscr in R1. MOVL (R0),(R1) ; Copy length of command line. MOVC3 (R0),@4(R0),@4(R1) ; Copy the command line dscr to ; user's dscr. RET ;******************************************************************************* ; FIND_USER_NAME: ; This function tries to find a unique process from a specified user name. ; Only invoked if user name is not within group. If more than one name is ; found, then SS$_TOOMUCHDATA is returned. ; ; Pascal external declaration: ; ; FUNCTION FIND_USER_NAME(VAR USER_PID: INTEGER; ; VAR USER_DSCR: STRDSCR): INTEGER; EXTERN; ; $IPLDEF ; Interrupt priority level definition. $PCBDEF ; Process control block definition. ARGLIST1: .LONG 2 ; Two parameter. .BLKL 2 ; Parameters for Kernel Mode routine. .ENTRY FIND_USER_NAME,^M MOVQ 4(AP),ARGLIST1+4 ; Save params for Kernel mode routine. MOVL 8(AP),R1 ; Move address of device name to R1. BNEQ TEST_PID1 ; Continue if specified. BAD_PARAM1: MOVZWL #SS$_BADPARAM,R0 ; Specify a bad parameter. BRB EXIT1 TEST_PID1: ; Test for access to PID. IFNOWRT #4,@4(AP),ACCVIO1 ; Abort if PID can't be written. CLRL @4(AP) ; Clear contents of PID parameter. IFRD #8,(R1),GET_LENGTH1 ; Continue if desc can be accessed. ACCVIO1:MOVZWL #SS$_ACCVIO,R0 ; Abort with access violation. BRB EXIT1 GET_LENGTH1: ; Test length in the dscriptor. MOVQ (R1),R1 ; Move descriptor to R1 and R2. CMPL R1,#15 ; Test against maximum length. BGTR BAD_LENGTH1 ; Abort if too long. TSTL R1 ; Test against minimum length BGTR TEST_NAME1 ; Continue if > 0. BAD_LENGTH1: MOVZWL #SS$_IVLOGNAM,R0 ; Invalid logical name. BRB EXIT1 TEST_NAME1: IFNORD R1,(R2),ACCVIO1 ; Abort if string can't be read. $CMKRNL_S FIND_NAME,ARGLIST1 ; Execute kernal mode routine. EXIT1: RET ; Return. FIND_NAME: ; Kernel mode routine that finds the PCB given process name. .WORD ^M ; Entry mask. SETIPL #IPL$_ASTDEL ; Disable (some) interrupts. MOVL 8(AP),R2 ; Put address of name in R2. MOVQ (R2),R2 ; Put length in R2 & string addr in R3. MOVL G^SCH$GL_MAXPIX,R4 ; Initialize process index. BSB PIXLOOP ; Find first occurance of process name. BLBC R0,DONE ; Abort if not found. MOVL R1,R5 ; Save PID of process for later. BSB PIXLOOP ; Any more occurrances of the same name? BLBC R0,ONLY_ONE_NAME ; No, go set success status. MOVZWL #SS$_TOOMUCHDATA,R0 ; Yes, set error status BRB DONE ; and go abort. ONLY_ONE_NAME: MOVL PCB$L_PID(R5),@4(AP) ; Return the PID. MOVZWL #SS$_NORMAL,R0 ; Set success status code. DONE: SETIPL #0 ; Set user's IPL RET ; and return. FIND_NEXT_NAME: ; Subroutine that finds nest occurrance of specified name. TSTL R4 ; Have all PCB's been tested? BLSS NONE ; Yes, exit immediately. PIXLOOP: MOVAB G^SCH$GL_PCBVEC,R1 ; Move address of vector to R1. MOVL @(R1)[R4],R1 ; Get PCB from vector. CMPB R2,PCB$T_LNAME(R1) ; Are string length equal? BNEQ NEXPIX ; No, advance to next PCB. PUSHR #^M ; Save registers. CMPC R2,(R3),PCB$T_LNAME+1(R1); Are the strings equal? POPR #^M ; Restore registers. BEQL FOUND_PCB ; Yes, exit loop. NEXPIX: SOBGEQ R4,PIXLOOP ; No, go try the next PCB. NONE: MOVZWL #SS$_NONEXPR,R0 ; Process doesn't exist, BRB RTN ; so abort. FOUND_PCB: DECL R4 ; Advance R4 for next call. MOVZWL #SS$_NORMAL,R0 ; Set success return status RTN: RSB ; and return. ;******************************************************************************* ; FIND_USER_TERM ; This routine attemps to find the terminal that is allocated to a specified ; user given its PID. If successful, then the device name of the terminal is ; returned in the string descriptor parameter. ; ; If no terminal is allocated to the user, then the error status SS$_DEVOFFLINE ; is returned. If more than one terminal is allocated to the user, then the ; error status SS$_DEVICEFULL is returned. ; ; Pascal external declaration: ; ; FUNCTION FIND_USER_TERM(%IMMED PID: INTEGER ; VAR DEVICE_DSCR: STRDSCR): INTEGER; EXTERN; ; $DCDEF ; Device class definition. $DDBDEF ; Device data block definition. $IPLDEF ; Interrupt priority level definition. $PCBDEF ; Process control block definition. $UCBDEF ; Unit control block definition. ARGLIST: .LONG 2 ; Two parameters. .BLKL 2 ; Parameters for Kernel Mode routine. DDB: .BLKL 1 UCB: .BLKL 1 STATUS: .BLKL 1 .ENTRY FIND_USER_TERM,^M MOVQ 4(AP),ARGLIST+4 ; Save params for Kernel mode routine. MOVL 8(AP),R1 ; Move address of device name to R1. BNEQ TEST_PID ; Continue if specified. BAD_PARAM: MOVZWL #SS$_BADPARAM,R0 ; Specify a bad parameter. BRB EXIT TEST_PID: ; Test for non-zero PID. TSTL 4(AP) ; If PID = 0, BEQL BAD_PARAM ; then abort. TEST_DSCR: ; Test if descriptor is valid. IFRD #8,(R1),GET_LENGTH ; Continue if desc can be accessed. ACCVIO: MOVZWL #SS$_ACCVIO,R0 ; Abort with access violation. BRB EXIT GET_LENGTH: ; Test length in the dscriptor. MOVQ (R1),R1 ; Move descriptor to R1 and R2. CMPL R1,#63 ; Test against maximum length. BGTR BAD_LENGTH ; Abort if too long. CMPL R1,#5 ; Test against minimum length BGTR TEST_NAME ; Continue if > 5. BAD_LENGTH: MOVZWL #SS$_IVLOGNAM,R0 ; Invalid logical name. BRB EXIT TEST_NAME: IFNORD R1,(R2),ACCVIO ; Abort if string can't be read. $CMKRNL_S FIND_TT,ARGLIST ; Execute kernal mode routine. EXIT: RET ; Return. FIND_TT: ; Kernel mode routine that finds the user's terminal. .WORD ^M ; Entry mask. CHECK_PID: ; Test if process is valid. SETIPL #IPL$_SYNCH ; Disable interrupts. MOVZWL 4(AP),R1 ; Put process index in R1. CMPL R1,G^SCH$GL_MAXPIX ; Test against maximum index. BGTRU NONEX ; Not there if greater than max. MOVAB G^SCH$GL_PCBVEC,R0 ; Move address of vector to R0. MOVL @(R0)[R1],R1 ; Get PCB from vector. CMPL 4(AP),PCB$L_PID(R1) ; Is the PID valid? BEQL GET_1ST_DDB ; Yes, continue. NONEX: MOVZWL #SS$_NONEXPR,R0 ; Set nonexistent process status BRW ABORT ; and go abort. GET_1ST_DDB: ; Get the address of the first terminal Device Data Block (DDB). MOVL @#SCH$GL_CURPCB,R4 ; Get address of current PCB. JSB SCH$IOLOCKR ; Lock data base for read. MOVL @#IOC$GL_DEVLIST,R2 ; Get address of first DDB. MOVL DDB$L_UCB(R2),R5 ; Put address of next UCB in R5. BSB FIND_PID ; Attempt to find user's PID. MOVL R0,STATUS ; Save status in case of error. BLBC R0,UNLOCK ; Abort if user not found. MOVL R2,DDB ; Save DDB address. MOVL R4,UCB ; Save UCB address. BSB FIND_PID ; See if user has another terminal. BLBC R0,ONLY_1_TERM ; Continue if only one terminal. MOVZWL #SS$_DEVICEFULL,STATUS ; More than one terminal: Set error BRB UNLOCK ; and abort. ONLY_1_TERM: ; Only one terminal was found so set the device descriptor. MOVL 8(AP),R1 ; Put address of dscr into R1. MOVZBL #6,(R1) ; Set length of device name. MOVL 4(R1),R1 ; Put address of string into R1. MOVQ DDB,R2 ; Put DDB addr in R2 & UCB addr in R3. MOVL DDB$T_NAME(R2),(R1) ; Put chars 2-->4 into string. MOVB #^X<5F>,(R1) ; Put "_" into first char of string. ; Note the use of R4 is current UCB & R5 is next UCB. ADDB3 UCB$W_UNIT(R3),- ; Put unit number into fifth char #^X<30>,4(R1) ; of the string. MOVB #^X<3A>,5(R1) ; Put colon into sixth char. MOVZWL #SS$_NORMAL,STATUS ; Set status code for success. UNLOCK: MOVL @#SCH$GL_CURPCB,R4 ; Get address of current PCB. JSB G^SCH$IOUNLOCK ; Unlock data base. MOVZWL STATUS,R0 ; Set return code. ABORT: SETIPL #0 ; Set to user IPL RET ; and return. ; FIND_PID -- Searches for specified PID within terminal I/O Data Base. ; ; Inputs: 4(AP) = PID ; R5 = next UCB to test. ; R2 = current DDB. ; ; Output: if found R4 = UCB of terminal. (SS$_NORMAL) ; Not found returns status of SS$_DEVOFFLINE. ; Inputs are invarient. ; FIND_PID: MOVL R5,R4 ; Current UCB <-- Next UCB BNEQ SET_NEXT_UCB ; Don't advance DDB if valid. MOVL DDB$L_LINK(R2),R2 ; DDB <-- DDB^.next BNEQ VALID_DDB ; If valid DDB then continue MOVZWL #SS$_DEVOFFLINE,R0 ; else User not found: set error code RSB ; and return. VALID_DDB: ; Advanced to a new terminal DDB. MOVL DDB$L_UCB(R2),R4 ; Current UCB <-- DDB^.UCB SET_NEXT_UCB: ; Set up next UCB for next iteration. MOVL UCB$L_LINK(R4),R5 ; Next UCB <-- Current UCB^.next CMPB #DC$_TERM,- ; Is this UCB UCB$B_DEVCLASS(R4) ; a terminal? BNEQ FIND_PID ; No, try next UCB. CMPL UCB$L_PID(R4),4(AP) ; Do the PID's match? BNEQ FIND_PID ; No, try next UCB. MOVZWL #SS$_NORMAL,R0 ; Yes, set success status code RSB ; and return. .END