Previous | Contents | Index |
Table A-1 lists the obsolete DCL commands and the current services that replace them.
Obsolete Command | Replaced by |
---|---|
SET ACL | SET SECURITY/ACL |
SET PROTECTION | SET SECURITY/PROTECTION |
SET PROTECTION/DEVICE | SET SECURITY/PROTECTION/CLASS=DEVICE |
SET UIC | Not replaced. |
SHOW ACL | SHOW SECURITY |
UNLOCK | SET FILE/UNLOCK |
The OpenVMS Version 8.4 release introduces support for storage devices up to 1.98 TB in size. For customers and products that will use devices over 1 TB, some changes to DCL procedures are necessary to keep them functioning properly. If you do not plan to use storage devices over 1 TB in size, there is likely no need to change any of your DCL code related to reading or changing disk values.
The document is mainly intended to address issues with large disks but
the methods used are not specific to the large disk support project.
B.2 Introduction
Herein are some DCL examples handling retrieval and arithmetic on integer values that lie outside the DCL symbol integer limits. The document concentrates on processing values returned from the DCL $GETDVI lexical function. The examples can be used as guidelines for your specific needs. Examples are not warranteed or guaranteed to meet any specific requirement. Examples center on handling disk storage size and free storage measurement but methodologies can be more generally applied.
The example procedures are designed to clearly demonstrate the
methodology. The specific operations may be more efficiently performed
by complex single statement DCL commands. The document chooses ease of
reading over efficiency in the examples.
B.2.1 Problem Statement
OpenVMS system configuration and management procedures can update or monitor almost all possible system resource values with signed 32-bit longword integers. Over a period of time, a number of resource value maximums moved beyond the signed longword limit. For example, the number of virtual memory pages available to a process on OpenVMS Alpha and Integrity server systems require 64-bit integer storage for the maximum value. Unfortunately, the DCL command language stores and performs arithmetic only on 32-bit signed longwords. From the "OpenVMS User's Manual Chapter 12, Defining Symbols, Commands and Expressions":
"12.7.2 Internal Storage of Numbers
Numbers are stored internally as signed 4-byte integers, called longwords; positive numbers have values of 0 to 2147483647 and negative numbers have values of 4294967296 minus the absolute value of the number. The number -15237, for example, is stored as 4294952059. Negative numbers are converted back to minus-sign format for ASCII or decimal displays; however, they are not converted back for hexadecimal and octal displays. For example, the number -15237 appears in displays as hexadecimal FFFFC47B (decimal 4294952059) rather than hexadecimal --00003B85. "
This DCL behavior poses problems for scripts monitoring and modifying
large valued resource settings on OpenVMS systems. OpenVMS version 8.4
will introduce support for large disks, up to 1.98 terabytes. It is
expected that many DCL procedures will be adversely affected as disk
block counts will now exceed the signed maximum value and appear as
negative numbers in DCL integer symbols. The F$GETDVI lexical function
items MAXBLOCK, FREEBLOCKS, EXPSIZE and VOLSIZE are typically used to
return disk information. All of these F$GETDVI items may return
negative numbers on Version 8.4.
B.2.2 Prerequisites
A moderate knowledge of DCL programming is required. Availability of a
disk sized over 1 TB.
B.3 DCL Examples
Some examples and procedures are included in this section to
demonstrate ways to perform range checks and percentage calculations in
Version 8.4 on systems with large disks.
B.3.1 DCL code checking a value in range 0 to 2147483647
A simple method to check for a minimum value or a range with a maximum value less than 2147483647 is demonstrated here.
change:
IF F$GETDVI(device,"FREEBLOCKS") .GT. 100000 THEN ... |
to:
IF F$GETDVI(device,"FREEBLOCKS") .LT. 0 .OR. - F$GETDVI(device,"FREEBLOCKS") .GT. 100000 THEN ... |
One method to check a range or size value exceeding the signed longword maximum is to convert the values to zero filled ASCII strings. After the conversion the DCL string logical operators can be used to perform the comparison.
$! Begin Example $! $ disk = P1 $ if disk .EQS. "" then disk = "SYS$LOGIN_DEVICE" $ length = f$length("4294967296") ! string length of 2TiB in blocks $ maxblocks = f$fao("!''length'ZL",F$GETDVI(disk,"MAXBLOCK")) $ freeblocks = f$fao("!''length'ZL",F$GETDVI(disk,"FREEBLOCKS")) $ expsize = f$fao("!''length'ZL",F$GETDVI(disk,"EXPSIZE")) $ volsize = f$fao("!''length'ZL",F$GETDVI(disk,"VOLSIZE")) $ MinBlocks = f$fao("!''length'ZL",500000) $! $ write sys$output "Results for Freeblocks=''freeblocks' .comparison. MinBlocks=''MinBlocks'" $ write sys$output ".eqs. " + F$string((freeblocks .eqs. MinBlocks)) $ write sys$output ".nes. " + F$string((freeblocks .nes. MinBlocks)) $ write sys$output ".les. " + F$string((freeblocks .les. MinBlocks)) $ write sys$output ".ges. " + F$string((freeblocks .ges. MinBlocks)) $ write sys$output ".lts. " + F$string((freeblocks .lts. MinBlocks)) $ write sys$output ".gts. " + F$string((freeblocks .gts. MinBlocks)) $ write sys$output "" $ write sys$output "Results for maxblocks=''maxblocks' .comparison. volsize=''volsize'" $ write sys$output ".eqs. " + F$string((maxblocks .eqs. volsize)) $ write sys$output ".nes. " + F$string((maxblocks .nes. volsize)) $ write sys$output ".les. " + F$string((maxblocks .les. volsize)) $ write sys$output ".ges. " + F$string((maxblocks .ges. volsize)) $ write sys$output ".lts. " + F$string((maxblocks .lts. volsize)) $ write sys$output ".gts. " + F$string((maxblocks .gts. volsize)) $! $! End example |
Common disk management operations include calculating the unused percentage of a disk or determining if there is sufficient free space on the target disk for a copy or backup. This section provides examples on handling these particular functions on large disks.
One approach is to assume that any negative value returned on a FREEBLOCKS check means that there are sufficient freeblocks to perform whatever storage operation you require.
IF F$GETDVI(device,"FREEBLOCKS") .LT. 0 THEN GOTO SUCCESS |
This example demonstrates how to check if the system device has at least 5% free blocks. It calls a subroutine PERCENT_FREE to perform the check. The subroutine scales the disk values so signed arithmetic can be performed.
$! begin Example $! $ percent_free == -1 $! $ CALL percent_free "sys$sysdevice" $ IF $status .AND. percent_free .gt. 0 $ then $ if percent_free .ge. 5 $ then $ write sys$output "Sufficient freeblocks on disk" $ else $ write sys$output "Warning Insufficient freeblocks on disk" $ endif $ else $ write sys$output "Problem obtaining information for disk" $ endif $! $ EXIT $ $! $ percent_free: subroutine $ ! $ ! This subroutine will return, as an integer, the percentage of free $ ! disk blocks for a given volume. The percentage free is given by: $ ! $ ! (number of free blocks on the volume) $ ! Percentage Free = ------------------------------------- * 100 $ ! (volume size in blocks) $ ! $ ! The volume name is passed in P1 and the result is returned in the $ ! global symbol PERCENT_FREE. For example: $ ! $ ! $ call percent_free "disk$test" $ ! $ write sys$output "Free space is ", percent_free, "%" $ ! $ ! Since DCL does signed 32 bit arithmetic, all calculations and results $ ! are done with the sign bit (bit 31) clear. So, for values of free $ ! blocks and volume size larger than %x7FFFFFFF, first clear the sign $ ! bit, divide by two (shift right one bit) and then turn on bit 30. $ ! $ freeblocks = f$getdvi(p1,"freeblocks") $ volsize = f$getdvi(p1,"volsize") $ ! $ if (freeblocks .lt. 0) $ then pipe freeblocks[31,1] = 0 ; freeblocks = freeblocks / 2 ; freeblocks[30,1] = 1 $ else freeblocks = freeblocks / 2 $ endif $ ! $ if (volsize .lt. 0) $ then pipe volsize[31,1] = 0 ; volsize = volsize / 2 ; volsize[30,1] = 1 $ else volsize = volsize / 2 $ endif $ ! $ if ((volsize / 100) .gt. 0) $ then percent_free == freeblocks / (volsize / 100) $ else percent_free == 0 $ endif $ ! $ endsubroutine |
The pre Version 8.4 F$CUNITS() lexical function allowed conversion of a value of blocks to the corresponding value of bytes. The output of the lexical was automatically scaled to KB, MB, and so on depending upon the size of the resultant value. In Version 8.4 the lexical is enhanced to support bytes to blocks conversions. Additional units keyword values are introduced to allow the user to specify the resultant value scaling. The format of a F$CUNITS lexical call is:
result = F$CUNITS(value, from-units, to-Units) |
where:
value: a value in the range 1 to 4294967295
Pre Version 8.4:
from-units: "BLOCKS" ! optional, default is BLOCKS to-units: "BYTES" ! optional, default resultant BYTES are autoscaled |
Version 8.4:
from-units: unit ! optional, default is BLOCKS to-units: unit ! optional, default resultant BYTES are autoscaled |
where unit is one of:
"BYTES","BLOCKS","KB","MB","GB","TB" |
For large disks it may be more convenient to work or display values in units other than blocks.
The next example demonstrates usage of the F$CUNITS function to convert blocks to bytes. It calculates the percent of free disk space while exercising the F$CUNITS lexical. The example also contains an easy method to approximate the percentage.
$! $ if p1 .nes. "" Then GOTO show_device_info $ thisproc = f$environment("procedure") $Loop: $ disk = F$DEVICE("*","DISK") $ if disk .eqs. "" then EXIT $ @'thisproc' 'disk' $ goto Loop $show_device_info: $! Example: $! $! Demonstrate the use of the F$CUNITS() lexical and $! calculate the percent free of a disk $! $ disk = P1 $ if P1 .eqs. "" then disk = "sys$sysdevice" $ if .NOT. ( f$getdvi(disk,"EXISTS") .AND. - f$getdvi(disk,"AVL") .AND. - f$getdvi(disk,"MNT") ) then EXIT $ write sys$output "Results for disk : ''disk'" $ line = f$fao("!4(16AS)","Units","Total", "FREE", "Percent") $ write sys$output line $! $! do direct calculation or approximation first (BLOCKS) $! $ TotalSize = f$fao("!UL",f$getdvi(disk,"MAXBLOCK")) $ FreeSize = f$fao("!UL",f$getdvi(disk,"FREEBLOCKS")) $ TotalDisplay = TotalSize $ FreeDisplay = FreeSize $ if f$length(TotalSize) .lt. 7 then GOTO No_approximation $ TotalSize = f$extract(0,7,f$fao("!10ZL",f$getdvi(disk,"MAXBLOCK"))) $ FreeSize = f$extract(0,7,f$fao("!10ZL",f$getdvi(disk,"FREEBLOCKS"))) $! $No_approximation: $ uindex = -1 $ units = "BLOCKS,KB,MB,GB,TB" $! $! show approximation $! $ unit = "Approx" $! $ GOTO Compute_Percent $! $Fcunits_display: $! $Get_Unit: $!-------- $ unit = f$element(uindex,",",units) $ if unit .eqs. "," then EXIT $! $ TotalSize = f$cunits(f$string(f$fao("!UL",f$getdvi(disk,"MAXBLOCK"))),"BLOCKS",unit) - "''unit'" $ FreeSize = f$cunits(f$string(f$fao("!UL",f$getdvi(disk,"FREEBLOCKS"))),"BLOCKS",unit) - "''unit'" $! $ TotalDisplay = TotalSize $ FreeDisplay = FreeSize $! $! for unit >= gigabytes retain the fractional value $! $ if uindex .lt. 4 then goto Edit_Units_002 $! $ if f$locate(".",TotalSize) .eq. f$length(TotalSize) $ then $ TotalSize = TotalSize + "00" $ else $ TotalSize = TotalSize - "." $ endif $ if f$locate(".",FreeSize) .eq. f$length(FreeSize) $ then $ FreeSize = FreeSize + "00" $ else $ FreeSize = FreeSize - "." $ endif $! $ GOTO Compute_Percent $! $Edit_Units_002: $! $! For units < Gigabytes truncate any fraction $! $ if f$locate(".",TotalSize) .lt. f$length(TotalSize) $ then $ TotalSize = f$extract(0,f$length(TotalSize)-3,TotalSize) $ endif $! $ if f$locate(".",FreeSize) .lt. f$length(FreeSize) $ then $ FreeSize = f$extract(0,f$length(FreeSize)-3,FreeSize) $ endif $! $Compute_Percent: $! $! check for overflow on percentage calculation $! $ PCTfree = -1 $ if (((f$integer(FreeSize)*100)/100) .ne. f$integer(FreeSize)) .OR. - f$length(FreeSize) .gt. 8 .OR f$length(TotalSize) .gt. 8 $ then $ PCTfree = "Overflow" $ else $ if TotalSize .eq. 0 .OR. FreeSize .eq. 0 $ then $ PCTfree = 0 $ else $ PCTfree = f$integer( (FreeSize*100) / TotalSize) $ endif $ endif $! $ line = f$fao("!4(16AS)",Unit, TotalDisplay, FreeDisplay, f$string(PCTfree)) $ write sys$output line $! $ uindex = uindex + 1 $ GOTO Get_Unit $! $ EXIT $! |
This section describes some ways to identify DCL code and source code
modules that may not function correctly when accessing devices over 1TB
size.
B.4.1 DCL Code Search Example
This example demonstrates a simple search to identify DCL code lines
that definitely need to be addressed. DCL code may supply lexical items
as symbols or split lexical calls into multiple lines and this
procedure will not identify such cases.
$ search := search/numbers/wind=1/MATCH=AND/statistics $ filespec = 'your_filespec' $! $! The results of the search command on the next 3 lines $! show DCL command lines that MUST be addressed on systems $! accessing disks over 1tb. $ search 'filespec' "F$GETDVI","MAXBLOCK" $ search 'filespec' "F$GETDVI","VOLSIZE" $ search 'filespec' "F$GETDVI","EXPSIZE" $! $! The results of the search command on the next line $! show DCL command lines that should be changed on $! systems accessing disks over 1tb. $! The DCL command is likely to return a value that will $! not fit in a signed longword. $ search 'filespec' "F$GETDVI","FREEBLOCKS" |
Index | Contents |