SYSPRO2@TAMVENUS.BITNET.UUCP (02/13/87)
Here is a copy of the program written by Gerard Newman. The program has been modified by Brad Wilson. The program would crash my machine if I passed a RT terminal type to the program. Brad's fix took care of this. .Title LAT_Info - Get information about a LAT terminal .Ident /V01.000/ .Enable SUP .Default Displacement,Word .Subtitle Introduction ;+ ; ; ----- LAT_Info: Get information about a LAT terminal ; ; ; Facility: ; ; VAX/VMS system programming ; ; Abstract: ; ; This module provides a routine which can be called from any ; VAX native language to obtain information about a specific ; LAT terminal. ; ; Environment: ; ; VAX/VMS native mode, VMS V4.2 or later, LATPlus V01.012, CMKRNL ; privilege. ; ; ; ; Version: V01.000 ; Date: 19-Dec-1986 ; ; Gerard K. Newman ; San Diego Supercomputer Center ; GA Technologies ; P.O. Box 85608 ; San Diego, CA 92138 ; 619.534.5076 ; ; GKN@SDSC.ARPA, GKN@SDSC.BITNET ; ; Modifications: ; ; BMW001 -- (5-jan-1987) Check for non-zero physical UCB before ; following chain of indirection. ; BMW002 -- (5-jan-1987) Use intermediate buffering to avoid some ; sticky problems: (1) allow other types of ; descriptors by copying info from local buffers ; to user buffers (in user mode). (2) Modify ; internal calling mechanism to include length ; arguments, thus avoid modifying the descriptor ; which was only probed for read access. ; ; ;- .Page .Subtitle Local definitions .Library "SYS$LIBRARY:LIB" ;Get special macros from here .Link "SYS$SYSTEM:SYS.STB"/Selective_Search ;Ease the link ; ;process a bit .NoCross ;Save a tree $DCDEF ;Device class & type definitions $DDBDEF ;Device data block offsets $DSCDEF ;Descriptor symbols (BMW002) $SSDEF ;System service codes $TTYUCBDEF ;Terminal UCB offsets $UCBDEF ;UCB offsets .Cross ;Turn CREF back on ; Local definitions ; Constants that are likely to change in a future release of VMS that are not ; defined in SYS.STB or in a macro anywhere. These values come from looking ; at the running system with SDA. ; Offset in an LT UCB to the length of the port name, which is a counted ; string. Immediately following the port name is another counted string ; which is the LAT node name. UCB$B_LT_PORT = ^X134 ;Offset to the port name length UCB$B_LT_SESS = ^X195 ;Offset to the session number .Page .Subtitle LAT_INFO - Get information about a LAT terminal ;+ ; ; ----- LAT_INFO: Get information about a LAT terminal ; ; ; This routine can be called by any VAX native language to obtain the server ; name, port name and session number of a LAT connection given a LT device ; name. The calling program must have CMKRNL privilege and must be linked ; with SYS.STB. ; ; Caveats: ; ; Will only work with fixed (non-dynamic) string descriptors. ; (BMW002) modified to work with any type string descriptor. ; ; Call sequence: ; ; status.wlv = LAT_INFO (terminal.rt.dx, session.wlr, ; server.wt.dx, port.wt.dx) ; ; Inputs: ; ; 4(AP) - Address of a descriptor of the LT device name. ; 8(AP) - Address of a longword to return the session number in. ; 12(AP) - Address of a descriptor to return the server name. ; 16(AP) - Address of a descriptor to return the server port name. ; ; Outputs: ; ; R0 - SS$_NOPRIV: No CMKRNL privilege. ; - SS$_ACCVIO: One of the arguments is not accessible. ; - SS$_NOSUCHDEV: The specified LT device can't be found. ; - SS$_IVDEVNAM: The specified device isn't a LAT terminal. ; - SS$_NORMAL: Success. ; (BMW002) other status codes may be returned by the RTL ; ; (BMW002) ; ; Internally, the routine calls a kernel mode routine which does ; the actual lookup. This k-mode routine can only handle fixed ; length string descriptors for the two output parameters, and ; will only accept fixed length or dynamic string descriptors for ; the terminal name (which is read-only). In order to implement ; other string types, the routine provides intermediate buffering ; of the three string parameters. Two additional parameters are ; passed to the kernel mode routine. These are used to receive ; the actual lengths of the server name and port name. In essence, ; the internal k-mode routine is called with the following argument ; list: ; ; status = krtn( terminal.rt.dx, session.wlr, ; server.wt.dx, port.wt.dx, ; slength.wwr, plength.wwr ) ; ; 4(AP) - address of dynamic string descriptor containing ; the terminal name (read-only). ; 8(AP) - address of a longword to receive the session ; number (copied directly from the user's ; argument list). ; 12(AP) - address of a fixed length string descriptor to ; receive the server name. ; 16(AP) - address of a fixed length string descriptor to ; receive the port name. ; 20(AP) - address of a word to receive the length of the ; server name. ; 24(AP) - address of a word to receive the length of the ; port name. ; ; (BMW002) ;- ;+ ; (BMW002) Add local data Psect ;- .Psect LAT_DATA,REL,CON,NOEXE,LCL,NOPIC,WRT,NOSHR,QUAD Server_Name: .blkb 128 ; reserve 128 characters for name Server_Length=.-Server_Name Port_Name: .blkb 128 ; reserve 128 characters for name Port_Length=.-Port_Name .align quad ; start descriptors on quad boundary ; ; (not absolutely necessary) ; Set up the descriptors. We will use a dynamic string for the terminal ; name, since it is treated as read-only by the kernel mode routine ; (i.e. additional space will not need to be allocated once in kernel ; mode). The server and port names are set up as statically allocated ; strings so that the kernel mode routine may precheck the buffers for ; write accessibility. We could use dynamic strings for them also, but ; we would have to call LIB$SGET_DD to get space before calling the ; kernel mode routine (the k-mode routine is incapable of allocating ; dynamic string space itself). Terminal_Desc: .word 0 ; Empty Dynamic string .byte DSC$K_DTYPE_T ; character-coded text .byte DSC$K_CLASS_D ; Dynamic string descriptor .long 0 ; Empty Dynamic string Server_Desc: .word Server_Length ; length of buffer .byte DSC$K_DTYPE_T ; character-coded text .byte DSC$K_CLASS_S ; scalar string descriptor .address Server_Name ; buffer address Port_Desc: .word Port_Length .byte DSC$K_DTYPE_T .byte DSC$K_CLASS_S .address Port_Name Arglist: .blkl 7 ; intermediate arglist SName_Length: .blkw 1 ; space for length of server name PName_Length: .blkw 1 ; space for length of port name ;+ ; (BMW002) End of added Psect ;- .Psect LAT_INFO,EXE,RD,NOWRT,PIC,SHR,PAGE .Entry LAT_INFO,^M<R2,R3,R4,R5,R6> ;Entry here MOVL #SS$_INSFARG,R0 ; Assume things are bad (BMW002) CMPB #4,(AP) ; Check number of arguments (BMW002) BNEQ 5$ ; Not enough arguments (BMW002) MOVL 4(AP),R0 ; Point R0 to input terminal name MOVAL Terminal_Desc,R1 ;Point R1 to output descriptor ; ; Note that the call to LIB$SCOPY_DXDX to copy the string has the ; side effect (since the output string is dynamic) of allocating ; space to the output string. ; JSB G^LIB$SCOPY_DXDX6 ;Copy string BLBC R0,5$ ; Exit on error MOVL #SS$_ACCVIO,R0 ; Assume bad things MOVL #6,ARGLIST ; Init count field of arglist (BMW002) MOVAL Terminal_Desc,ARGLIST+4 ; move terminal name (BMW002) MOVL 8(AP),ARGLIST+8 ; move session param directly (BMW002) BEQL 5$ ; exit if it was omitted (BMW002) MOVAL Server_Desc,ARGLIST+12 ; (BMW002) MOVAL Port_Desc,ARGLIST+16 ; (BMW002) MOVAL SName_Length,ARGLIST+20 ; (BMW002) MOVAL PName_Length,ARGLIST+24 ; (BMW002) BRB 6$ ; Some of the above branches are ; ; out of range. (BMW002) 5$: RET ; so we need 5$ to move the exit closer 6$: $CMKRNL_S ROUTIN=B^20$,- ;Do this ARGLST=ARGLIST ; in kernel mode (BMW002) BLBC R0,10$ ; On error, return (BMW002) ;+ (BMW002) ; ; We now use the RTL routines to copy from our intermediate buffers ; (set up as static strings) into the user's buffers. This is done ; in normal user mode, so dynamic strings can be used without ; problems. ; ;- MOVZWL SName_Length,R0 ; Setup for string copy MOVAL Server_Name,R1 MOVL 12(AP),R2 JSB G^LIB$SCOPY_R_DX6 ; Do copy BLBC R0,10$ ; On error, return PUSHL R0 ; Else, save status MOVZWL PName_Length,R0 ; Setup for string copy MOVAL Port_Name,R1 MOVL 16(AP),R2 JSB G^LIB$SCOPY_R_DX6 ; Do copy POPL R1 ; Get previous status into R1 BLBC R0,10$ ; Return if error on 2nd copy CMPL #SS$_NORMAL,R1 ; If 1st was a total success, BEQL 10$ ; Return status from 2nd copy CMPL #SS$_NORMAL,R0 ; If 2nd copy was not ok, BNEQ 10$ ; Return it's status MOVL R1,R0 ; 2nd was ok, return 1st status ;+ (BMW002) ; ; End of string copy ;- 10$: RET ;Done, status in R0 ; Here in kernel mode to do all of the actual work. 20$: .Word ^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11> ;Here in kernel mode ; ;to get some info ; First, check to see if we can read the argument list. MOVL #SS$_ACCVIO,R0 ;Presume we can't IFNORD #<7*4>,(AP),10$ ;Probe the argument list (BMW002) ; Check the number of arguments MOVL #SS$_INSFARG,R0 ;Presume we have too few arguments CMPB #6,(AP) ;Do we have enough arguments? BNEQ 10$ ;If NEQ no, it's wrong somehow ; Check to see if we can write the session number. MOVL #SS$_ACCVIO,R0 ;Presume we can't IFNOWRT #4,@8(AP),10$ ;Probe the output session number ; See if we can read the device name descriptor. MOVL 4(AP),R1 ;Address the LT device name descriptor JSB G^EXE$PROBER_DSC ;Probe the descriptor BLBC R0,10$ ;Sigh. MOVQ R1,-(SP) ;Save a safe copy of the probed descriptor MOVL SP,R11 ;Remember where it is CLRW 2(R11) ;Never mind the type and class info ; See if we have write access to the two output descriptors. MOVL 12(AP),R1 ;Address the server name output descriptor JSB G^EXE$PROBEW_DSC ;Probe the descriptor BLBC R0,10$ ;Sigh. MOVQ R1,-(SP) ;Stash a safe copy of the descriptor MOVL SP,R10 ;Remember where I put it CLRW 2(R10) ;Never mind the type and class info MOVL 16(AP),R1 ;Address the port name output descriptor JSB G^EXE$PROBEW_DSC ;Probe the descriptor BLBC R0,10$ ;Sigh. MOVQ R1,-(SP) ;Stash a safe copy of said descriptor MOVL SP,R9 ;Remember where it is CLRW 2(R9) ;Never mind the type and class info ; Probe the Server length for write access (BMW002) IFNOWRT #2,@20(AP),10$ ; (BMW002) ; Probe the Port length for write access (BMW002) IFNOWRT #2,@24(AP),10$ ; (BMW002) ; Ok. Now go hunt down the device the user told us was a LAT terminal ; and see if it really is. MOVL G^SCH$GL_CURPCB,R4 ;Get my PCB address JSB G^SCH$IOLOCKR ;Lock the I/O database mutex MOVL R11,R1 ;Address the device name descriptor JSB G^IOC$SEARCHDEV ;Go search for the device. BLBC R0,30$ ;We lose. ; Now check to see if it's even a terminal, and if it is see if it's a LAT ; terminal. Remember to chain to the physical UCB first in case this is ; a disconnectable terminal. MOVL #SS$_IVDEVNAM,R0 ;Presume it isn't a terminal CMPW #UCB$C_TT_LENGTH,UCB$W_SIZE(R1) ;Check length of UCB (BMW001) BGTR 30$ ;UCB too short for term (BMW001) TSTL UCB$L_TL_PHYUCB(R1) ;Check for phys UCB (BMW001) BEQL 25$ ;no phys UCB, skip next (BMW001) MOVL UCB$L_TL_PHYUCB(R1),R1 ;Get to the "real" UCB 25$: CMPB #DC$_TERM,UCB$B_DEVCLASS(R1) ;Is it a terminal? (BMW001) BNEQ 30$ ;If NEQ no. MOVL UCB$L_DDB(R1),R2 ;Find the DDB CMPW #^A/LT/,DDB$T_NAME+1(R2) ;Is this a LAT terminal? BNEQ 30$ ;If NEQ no ; It's a LAT terminal all right. Obtain the server name, port name and ; session number. MOVZBL UCB$B_LT_SESS(R1),@8(AP) ;Stash the session number MOVAB UCB$B_LT_PORT(R1),R1 ;Address the port name MOVL R9,R6 ;Here's the output descriptor address BSBB MOVE_ASCIC ;Move the port name MOVW (R6),@24(AP) ;Return the length (BMW002) MOVL R10,R6 ;R1 now points at the server name BSBB MOVE_ASCIC ;So go move it, too MOVW (R6),@20(AP) ;Return the length (BMW002) MOVL #SS$_NORMAL,R0 ;Success! 30$: PUSHL R0 ;Save the return status MOVL G^SCH$GL_CURPCB,R4 ;Get my PCB address again JSB G^SCH$IOUNLOCK ;Unlock the I/O database mutex SETIPL #0 ;Drop back down from IPL$_ASTDEL POPL R0 ;Restore the return status RET ;Back to user mode ; Short subroutine to move a .Ascic string to a place described by a ; descriptor. Forms a proper descriptor of the result, and handles ; short buffers, etc. ; ; Inputs: ; ; R1 - Address of the .Ascic string ; R6 - Address of the output descriptor ; ; Outputs: ; ; R1 - Address of one byte past the end of the .Ascic string ; R0-R5 - Smashed MOVE_ASCIC: ;Here to move a .Ascic string MOVZBL (R1)+,R0 ;Grab the string length CMPW (R6),R0 ;Check the string length BGEQU 10$ ;If GEQU then we can use it MOVZWL (R6),R0 ;Else only copy what will fit 10$: MOVW R0,(R6) ;Stash the length MOVC3 R0,(R1),@4(R6) ;Copy the string RSB ;Done .End