.title GET_DISK -- gets disk names .ident /V1-00/ ;+++ ; ; FACILITY: ; GET_DISK ; ; ENVIRONMENT: ; VAX/VMS Kernel Mode (call by $CMKRNL GET_DISK) ; V3.00 or greater ; ; IMPLICIT INPUTS: ; NONE ; ; IMPLICIT OUTPUTS: ; R0 - contains SS$_NORMAL if a disk was found or ; SS$_NOSUCHDEV if no more disks in the DDB ; ; IMPLICIT OUTPUTS: ; Modified global locations: ; DISK_LENGTH : (word) ; DISK_NAME : (less than 16 bytes of data) ; UNIT_NUMBER : (word) ; ; AUTHOR: ; Joel M Snyder (1-Aug-1983) ; CompuServe Incorporated, Research and Development ; ; MODIFIED BY: ; ; ; ABSTRACT: ; GETDISK is a subroutine that is used to determine the disk ; drives used on a system. The subroutine is not absolutely ; brilliant -- it doesn't check to see that the device which ; it thinks is a disk drive is indeed a disk drive, but ; the heuristic it uses is accurate for my VAX, and that's all ; I can test it on. ; GETDISK does have a minor problem -- it modifies global data ; areas, in direct violation of the VAX Modular Coding Standard. ; But this was the easiest way to write the subroutine, both ; from a user's standpoint and from the programmer's standpoint. ; GETDISK requires that global areas DISK_NAME(15 bytes, no less), ; DISK_LENGTH (1 longword) and UNIT_NUMBER (1 longword) be defined ; and available at link-time. For example: ; .GLOBAL DISK_NAME,DISK_LENGTH,UNIT_NUMBER ; DISK_NAME: .blkb 15 ; DISK_LENGTH: .blkl 1 ; UNIT_NUMBER: .blkl 1 ; ; GET_DISK maintains it's own 'context' within the system device ; table. This could cause problems on a system which is highly ; volatile in terms of disks, but I can't imagine such a system, ; so I assume that the disks configured into the system are ; not removed during runs of programs which call GETDISK. ; GETDISK returns SS$_NORMAL for each call in which a new ; disk drive got placed in global data. On the next call, it ; returns SS$_NOSUCHDEV, and then resets itself, ready to ; trace through the system DDB again. ; ; GETDISK selects disk on this criterion: ; IF the first character of the name in the DDB is "D" ; THEN the device is a disk. ; I suppose that the correct thing to do is a bit test for ; DEV$V_FOD (file oriented) and perhaps DEV$V_DIR (directory ; device) with secondary tests for DEV$V_AVL (device available) ; and DEV$V_MNT (device mounted) in UCB$L_DEVCHAR (defined ; by $DEVDEF), but I have a feeling that you don't really need ; to worry about that. The really correct thing to do is ; to test that UCB$B_DEVCLASS is DC$_DISK (in $DCDEF). GETDISK ; does this. ; ; In DISK_LENGTH is placed the length of DISK_NAME (usually ; three or four characters; this does NOT include the UNIT ; NUMBER). In DISK_NAME (up to 15 characters) is the name ; from the DDB. In UNIT_NUMBER (a longword) is a unit number ; of this disk. ;--- ; ; library definitions ; .library /SYS$LIBRARY:LIB/ $DDBDEF $SSDEF $UCBDEF $DCDEF ; ; external definitions ; .external DISK_NAME,DISK_LENGTH,UNIT_NUMBER .psect Get_Disk_Data SAVED_R11: .long 0 SAVED_R10: .long 0 .psect Get_Disk_Code .ENTRY GET_DISK,^M movl SAVED_R11,R11 ; get R11 (DDB address) movl SAVED_R10,R10 ; and get R10 (UCB address) tstl r10 ; is R10 zero (on first call) ? bnequ get_a_ucb ; if R10#0, get another UCB ; if R10=0, initialize ddb table moval L^IOC$GL_DEVLIST-DDB$L_LINK,R11 ; get the address of the first DDB get_a_ddb: movl DDB$L_LINK(R11),R11 ; get the next DDB bnequ got_a_ddb ; if R11#0, we got a DDB brw no_more_ddb ; if R11=0, there are no more DDBs got_a_ddb: movzbl DDB$T_NAME(R11),R6 ; get number of characters in name cmpb #^A/D/, DDB$T_NAME+1(R11) ; is this device a disk? bnequ get_a_ddb ; if not a disk, get another DDB movc3 R6,DDB$T_NAME+1(R11),W^DISK_NAME ; if a disk, save disk name movzbl R6,W^DISK_LENGTH ; ... and disk name length movl DDB$L_UCB(R11),R10 ; see if there is a UCB for this beqlu get_a_ddb ; ... DDB. If not, get another DDB moval DDB$L_UCB-UCB$L_LINK(R11), R10 ; get address of address of 1st UCB get_a_ucb: ; ignoring grammar movl UCB$L_LINK(R10),R10 ; get next UCB beqlu get_a_ddb ; if no more UCBs, get a DDB cmpb #DC$_DISK,UCB$B_DEVCLASS(R10) ; is this a disk? bnequ get_a_ucb ; no, get the next ucb movw UCB$W_UNIT(R10),W^UNIT_NUMBER ; save the unit number for this one movl R10,SAVED_R10 ; Save R10 (the UCB address) and movl R11,SAVED_R11 ; R11 (the DDB address) for later movzwl #SS$_NORMAL,R0 ; and give a status return ret ; EXIT POINT no_more_ddb: clrl SAVED_R10 ; clear out the UCB address clrl SAVED_R11 ; and DDB address in case called again movzwl #SS$_NOSUCHDEV,R0 ; give a status return ret ; EXIT POINT .end