==Phrack Inc.== Volume Three, Issue Thirty-five, File 7 of 13 <:=--=:><:=--=:><:=--=:><:=--=:>\|/<:=--=:><:=--=:><:=--=:><:=--=:> <:=--=:> <:=--=:> <:=--=:> >>>>>=-* Users Guide to VAX/VMS *-=<<<<< <:=--=:> <:=--=:> <:=--=:> <:=--=:> Part I of III <:=--=:> <:=--=:> <:=--=:> <:=--=:> Part A: Basic Information <:=--=:> <:=--=:> Part B: Programming the VAX/VMS <:=--=:> <:=--=:> <:=--=:> <:=--=:> By: Black Kat <:=--=:> <:=--=:> <:=--=:> <:=--=:><:=--=:><:=--=:><:=--=:>/|\<:=--=:><:=--=:><:=--=:><:=--=:> Index ~~~~ Part A contains information on the following topics: o Background o Logical Names o Terminal Control Keys o System Default Logical Names o Logging in o Logical Name Tables o Digital Command Language (DCL) o User Environment o Error Messages o Terminal Characteristics o Command Line Editing o File Security o Files and Directories o EDT Text Editor o File Operations o EDT Help manual Part B contains information on the following topics: o Programming VAX/VMS o Parameters o DCL Expressions o Terminal I/O o Command Procedures o File I/O o Writing Command Procedures o Redirecting Command Procedure I/O o Comments o Branching and Conditionals o Labels o Loops o Debugging o Subroutines o Invoking Command Procedures o Error Handling o Symbols o Termination o Lexical Functions o Example Command Procedures <:=- Part A : Basic Information -=:> Introduction ~~~~~~~~~~~ VAX is an acronym for Virtual Address eXtension, a 32-bit computer developed by Digital in the 1970's. The VAX architecture supports multiprogramming, where many users running different programs can use the VAX simultaneously and each appears to have full control of the computer's resources. The multiprocessing VAX functions vary differently from the old timesharing systems, which would allocate a slice of CPU time to each user of the system in a rotating fashion, whether the time slice was required or not. The VAX/VMS environment, however, provides each user an allocation of processor time based on the user's needs and priority. If a user does not need his quantum of time, or a portion of it, it is given to the next user. This scheduling method is very efficient when compared to the old method of timesharing. The VAX is capable of addressing more than four billion addresses, through a method known as virtual memory addressing. Because the memory is virtual however, there is no need to have four billion bytes of physical memory. The VAX executes programs by a technique known as paging, whereby a single "page" of the program is read into memory at a time, and when a new page is needed, the old one is "swapped" back out to disk to make room for the new one. The VMS operating system ties everything together. The user interacts with VMS (Virtual Memory System) through a Command Language Interpreter (CLI), usually the Digital Command Language (DCL). When you use VAX/VMS, you are known to the system as a process, which is created when you log in to the system and deleted when you log out. This process carries with it various attributes to identify you from other system users (process name, identification, user identification code, privileges, etc). Terminal Control Keys ~~~~~~~~~~~~~~~~~~~ Ctrl-A Allows you to insert, rather than overstrike, characters on a DCL command line that you're editing. Ctrl-B Displays DCL commands that you've previously entered. Ctrl-C Interrupts the coessed or the program being executed. Ctrl-E Positions the cursor at the end of the line. Ctrl-H Positions the cursor at the beginning of the line. Ctrl-I Tab Ctrl-O Alternately suppresses and continues the display of the output terminal. Ctrl-Q Enables (toggles on) output to the display after CTRL-S. Ctrl-R Retypes the current input line and repositions the cursor atthe end of the retyped line. Ctrl-S Disables (toggles off) output to the display until CTRL-Q is pressed. Ctrl-T Displays process statistics. Ctrl-U Discards the current input line and performs carriage return. Ctrl-W Refreshes the screen. Ctrl-X Flushes the type-ahead buffer. Ctrl-Y Interrupts command or program execution and returns control to the DCL command line interpreter. Ctrl-Z Indicates end of file for data entered from terminal. Logging in ~~~~~~~~ Most VAX systems prompt you with something like this: Welcome to VAX1 Username: Type your username and press . You'll then be prompted for your password. If you enter the correct username/password combination, you'll be given something like the following: Welcome to VAX/VMS V4.4 Last interactive login on Monday, 16-JUL-87 16:12 Last non-interactive login on Friday, 13-JUL-87 00:14 $ If you entered an incorrect username and password, you'll receive the message: User authorization failure Just hit and you'll be prompted for your username again. Once you're logged in, you'll be given the DCL prompt ($). This indicates that the system is ready to accept interactive commands. To log out, use the command: $ LOGOUT The Digital Command Language (DCL) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DCL is comprised of more than 200 commands called verbs. Each DCL verb acts on a parameter or assumed parameter, and the action of these verbs and the scope of their parameters can be modified with qualifiers. The basic command structure is: $ LABEL: COMMAND-NAME PARAMETER(S) /QUALIFIER(S) !COMMENT | | | | | | | | | +-- Optional Comment | | | | | | | +-------------- Command modifier(s) | | | | | +---------------------------- Object of the Command | | | +-------------------------------------- DCL command verb | +-------------------------------------------------- Optional Label A label is an optional, user-specified string with a maximum length of 255 characters. It is most commonly used in command procedures. A DCL command verb defines the action the VAX will take when the command line is interpreted. Parameter(s) specify the object or a list of objects the DCL command verb will act upon. Multiple parameters may be specified but must be separated from one another by a space, multiple spaces, or a tab. If you enter a DCL command that requires parameters, but you don't enter them on the command line, the DCL interpreter will prompt you for them automatically. Qualifiers further define or modify the function the DCL command will perform. They consist of a keyword followed by a value or a list of values. The qualifier keyword must be preceded by a slash (/). Multiple qualifiers may be specified, but each must be preceded with a slash. Qualifiers usually aren't required. There are three kinds of qualifiers: parameter, positional, and command. A command qualifier applies to the whole command. Generally, these are placed at the end of the command. For example: $ DIRECTORY [BYNON],[BYNON.DECPRO]/FULL This displays a full listing of two directories, using the /FULL qualifier of the DIRECTORY command. A positional qualifier takes on a different meaning based on where it is located in the command. If a positional qualifier is placed after the command verb, but before the first parameter, the qualifier will affect the entire command. If the same positional qualifier is placed after a parameter, only that parameter will be affected. For example: $ PRINT/COPIES=3 MEMO1.TXT,MEMO2.TXT $ PRINT MEMO1.TXT/COPIES=2,MEMO2.TXT The first command prints three copies of each file. The second command prints two copies of the first file, but only one copy of the second. A parameter qualifier affects only the parameter it follows. In the following example, MEMO1.TXT is sent to the queue LASER and MEMO2.TXT is sent to queue FAST_PRINT: $ PRINT MEMO1.TXT/QUEUE=LASER,MEMO2.TXT/QUEUE=FAST_PRINT A comment is an optional, user-specified comment about the command. It is commonly used in command procedures to document the command. Error Messages ~~~~~~~~~~~~ Generally, error messages are of the format: % FACILIT-L-IDENT, TEXT | | | | | | | | | +-- explanation of the error message | | | | | | | +--------- abbreviated message text, for reference | | | | | +------------- error severity | | | +------------------- Vax/VMS facility or component (error source) | +----------------------- message number: "%" = first, "-" = subsequent A percent sign (%) indicates the first error message for a given command. All subsequent errors for that command are preceded with a hyphen (-). The facility indicates the source of the error. The source may be the DCL command line interpreter, one of the various VMS utilities, or a program image. The severity level indicator (L) will have one of the following values: S (successful completion), I (information), W (warning), E (error), or F (fatal or severe error). The ident is an abbreviation of the error message text. It can be referenced in the VAX/VMS System Messages manual. The text provides an explanation of the error message. Command line editing ~~~~~~~~~~~~~~~~~~ DCL stores the last 20 command lines entered. You can display a list of them with: $ RECALL /ALL The resulting display might look like: 1 DIR 2 COPY VAX1::$1$DUA5:[BYNON]LOGIN.COM LOGIN.COM;1 3 EDIT LOGIN.COM $ To recall a specific command from the recall buffer, use the DCL RECALL command with a command line number as a parameter. For example: $ RECALL 2 $ COPY VAX1::$1$6DUA5:[BYNON]LOGIN.COM LOGIN.COM;1 Files and Directories ~~~~~~~~~~~~~~~~~~~~ Files are organized much like MS-DOS, with a directory-tree structure. The user's default directory (assigned by the system administrator) is the "root" directory. Up to seven subdirectories may be created, each containing as many subdirectories as you like. The complete file specification looks like: VAX1 :: DUA0 : [BYNON.PROGRAMMING.FORTRAN]WINDOWS.FOR;3 | | | | | | | | | | | | node device directory filename | version type The node name identifies a computer system in a network. If no node name is specified, VMS assumes the file is located on the local node where you're logged in. The device name is the physical device where the file is stored. It is a four-character alphanumeric code which identifies the device type, hardware controller to which it is attached, and the unit number of the device on the controller. If you omit the device name from a file specification, VMS assumes you are referring to your default device. The directory entry is enclosed in brackets, and is the name of the directory that contains the file. If you omit the directory name from a file specification, VMS will assume you are referring to your default directory. The filename may consist of up to 39 alphanumeric characters. The file type is a code consisting of up to 39 alphanumeric characters, and it generally indicates the type of information supplied in the file. Some system programs and utilities supply a three character default file type. The version number is a 1 to 5 digit number the system assigns to every file by default. When a file is created, it is assigned a version number of 1. Each time the file is edited or another version of it is created, the version number is automatically incremented by 1. Alternatively, you may specify a version number of your choice. No blank spaces are allowed within any portion of a file specification. In VMS Version 4.x, the maximum lengths are as follows: node name up to 6 characters device name four characters directory name up to 39 characters subdirectory name up to 39 characters file name up to 39 characters file type up to 39 characters version number up to 5 decimal digits with a value between 1 and 32,767 File specifications must be unique; no two files can have completely identical specifications. It's conceivable to have many copies of NOTES.TXT in a subdirectory, but only one NOTES.TXT;8 may exist in the same subdirectory. Wildcards are similar to those in MS-DOS, with an asterisk (*) representing a filename or filetype, and a percent sign (%) indicating a single character. File operations ~~~~~~~~~~~~~~ Creating and modifying files: $ CREATE TEMP.DAT TEMP 1 TEMP 2 Renaming files: $ RENAME TEMP.DAT NEW.DAT $ RENAME TEMP.DAT [BYNON.PROG]TEMP.DAT Note: you cannot rename files across devices, just directories. Copying files: $ COPY TEMP.DAT NEW.DAT $ COPY TEMP.DAT,TEST.DAT NEW.DAT Appending files: $ APPEND TEMP.DAT NEW.DAT Deleting files: $ DELETE TEMP.DAT;1 $ DELETE *.DAT;* $ DELETE /CONFIRM .DAT;* (confirm each file) Displaying files: $ TYPE /PAGE TEMP.DATE (one page at a time) Directories: $ DIRECTORY $ DIRECTORY DJA1:[BYNON.PROG] Printing files: $ PRINT TEMP.DAT Purging files: $ PURGE *.DAT (erase all but latest version of .DAT files) Create a dir: $ CREATE/DIRECTORY [.BUDGET] Set default dir: $ SET DEFAULT [BYNON.PROG] $ SET DEFAULT [.PROG] Delete a dir: $ SET DEFAULT [BYNON.PROG] $ DELETE *.*;* $ SET DEFAULT [BYNON] $ SET PROTECTION=(0:D) PROG.DIR;1 $ DELETE BUDGET.DIR;1 Logical Names ~~~~~~~~~~~~ A logical name is a substitute for a file specification, portion of a file specification, or another logical name. They provide two primary functions: file and device independence and file specification shorthand. File and device independence means that you are not constrained by a physical element, such as a disk or printer name. If you use files nested deeply in subdirectories, with long names, or on devices or nodes other than your default, you can define a meaningful logical name to represent it. These shorthand names are faster to type and easier to remember. To define a logical name: $ DEFINE PARTS_DBF DJA2:[DATABASES]PARTS.DAT This example will associate the logical name PARTS_DBF with the file specification DJA2 : [DATABASES]PARTS.DAT. Now, PARTS_DBF may be used anywhere as a substitute for the complete file specification. Other commands also can be used to assign logical names. Assign : Associates equivalence names with a logical name Mount : Mounts a disk or tape volume and assigns a system logical for the volume. Allocate: Allocates a system device for private use and optionally (command qualifier) assigns a logical name to the device. Open : Opens a file for read or write operations and assigns a logical name to the file specification. To display the logical name translations: $ SHOW LOGICAL PARTS_DBF will display: "PARTS_DBF" = "DJA2:[DATABASES]PARTS.DAT" (LNM$PROCESS_TABLE). To deassign a logical name: $ DEASSIGN PARTS_DBF System default logical names ~~~~~~~~~~~~~~~~~~~~~~~~~~~ SYS$COMMAND The initial file, or input stream, from which the DCL command line interpreter reads input data. The logical name SYS$COMMAND is equated to your terminal for interactive processes. SYS$DISK Your default disk as assigned in the UAF. SYS$ERROR The device on which the system displays all error and informational messages. By default, SYS$ERROR is assigned to your terminal for interactive processes, and to the batch job log file for any batch processes. SYS$INPUT The default file or input stream from which data and commands are read by either the DCL command line interpreter or programs executing in your account. By default, SYS$INPUT is equated to your terminal for interactive processes and to the batch job stream (or command procedure) for batch processes. Logical Name Tables ~~~~~~~~~~~~~~~~~ Logical names are stored in system files called logical name tables. The following are the four most commonly used: Group table : Contains the logical names available to all users in your UIC (User Identification Code) group. Job table : Contains the logical names available to your process and any subprocess it creates. Process table: Contains the logical names available to your process only. System table : Contains the logical names that may be used by all users of the system. User Environment ~~~~~~~~~~~~~~ The User Authorization File (UAF) is a system file controlled and modified by the system manager. A record for each system user is contained in the UAF. A User Identification Code (UIC) is an identifier used by VAX/VMS to identify users and groups of users. It is used to identify processes, directories, files, and other objects in the system. A UIC may be specified numerically or alphanumerically, and is made up of two parts, a group and a member, specified in the format: [group,member]. For example, UIC [10,14] identifies group 10, user 14. The group number is an octal number in the range 1-37776, and the member is an octal number in the range 0-177776. An alphanumeric UIC contains a member name and optionally, a group name in the format: [member] or [group,member]. The group and member names in an alphanumeric UIC may contain 1 to 31 alphanumeric characters (A-Z, 0-9, underscore, dollar sign). Each user of the system is limited in the consumption of system resources, and these limits control the rate at which your process or any subprocesses you create may consume a resource. There are 32 levels of priority in the VAX/VMS system, 0 through 31, the highest being 31. The priorities are divided into two ranges: timesharing (0-15) and real-time (16-31). The default user priority is 4. Depending on how heavily the system is being used, your priority may be raised above the default, but never lowered below it. VAX/VMS maintains 35 privileges, divided into the following seven categories classified by how much damage could be done to the system by possessing them: None No privileges. Normal The minimum privilege needed to use the system effectively. Group The ability to effect members of the same UIC group. Devour The potential to consume noncritical system-wide resources. System The ability to interfere with normal system operation. File The potential to bypass file protection security. All The ability to take over the entire system. VAX/VMS systems keep a record of overall computer system use by account holder in a system file called ACCOUNTING.DAT. The system manager uses this file to produce reports with the Accounting Utility. This can be used to learn more about how the system is being used, how it performs, and how a particular user is using the system. It can also be used to bill users for system time. Terminal Characteristics ~~~~~~~~~~~~~~~~~~~~~~ Setting display width: $ SET TERMINAL/WIDTH=132 Shutting messages off: $ SET TERMINAL/NOBROADCAST This prevents other users from phoning you, sending mail messages, and some system messages from appearing on your screen. If you just want mail and phone messages screened, use: $ SET BROADCAST=(NOMAIL,NOPHONE). Increasing type-ahead buffer: $ SET TERMINAL/ALTYPEHD/PERMANENT Line editing modes: $ SET TERMINAL/INSERT or $ SET TERMINAL/OVERSTRIKE Defining keys: $ DEFINE/KEY PF1 "SET DEFAULT DUA3:[INV.SUP]" % DCL-I-DEFKEY, DEFAULT key PF1 has been defined Showing keys: $ SHOW KEY PF1 (or $ SHOW KEY ALL) DEFAULT keypad definitions: PF1 = "SET DEFAULT DUA3:[INV.SUP]" Deleting keys: $ DELETE/KEY PF1 (or $ DELETE/KEY ALL) % DCL-I-DELKEY, DEFAULT key PF1 has been deleted Changing prompt: $ SET PROMPT = "What now?" Displaying process information: $ SHOW PROCESS (add a qualifier) Changing process information: $ SET PROCESS/NAME="Bob" $ SET PROCESS/PRIVILEGES=OPER File Security ~~~~~~~~~~~~ UIC-based protection permits access to be granted or denied based on protection codes that reflect four user categories: System: system manager Owner : account owner Group : users in same UIC group World : all users of system, regardless of UIC Four type of file access can be granted or denied to members of these user categories: Read (R): read the file Write (W): create or modify the file Execute (E): run a program Delete (D): delete the file Generally, any category of user can be granted or denied file access with this protection scheme. However, you can read a file in a subdirectory with EXECUTE access if you know its filename and filetype. Also, since SYSTEM privileges include the ability to bypass all file protection, anyone within the SYSTEM category can read a file. CONTROL access, or the ability to change the protection and ownership of a volume, is never specified in the UIC-based protection code. This is the fifth type of protection that can be specified in an access control list (ACL). It's automatically granted to two user categories when VMS examines UIC-based protection. Users in the SYSTEM and OWNER categories receive CONTROL access by default while GROUP and WORLD categories are denied CONTROL access. File protection defaults are as follows: System: RWED Owner : RWED Group : RE World : No access To determine the existing or default protection of a file, use the SHOW PROTECTION command. The default in the previous example would be: $ SHOW PROTECTION SYSTEM=RWED, OWNER=RWED, GROUP=RE, WORLD=NO ACCESS If you want to see file protection in directories, use the /PROTECTION qualifier with the DIRECTORY command. To change the protection of a file, use the command: $ SET PROTECTION=(O:RWE,G,W) LOGIN.COM In this example, the account owner has READ, WRITE, and EXECUTE access to his LOGIN.COM file. The GROUP and WORLD categories have no access and SYSTEM access remains unchanged. Rules for specifying protection codes: 1. Access types must be abbreviated with one letter: R, W, E, or D. 2. User categories may be spelled out or abbreviated. 3. Each user category must be separated from its access types with a colon. 4. If you specify multiple user categories, separate each with a comma and enclose the entire code in parenthesis. 5. User categories and access types may be specified in any order. 6. If you include a user category, but do not specify an access type for that category, access is automatically denied. 7. If you omit a user category entirely, protection for that category is unchanged. Remember that VAX/VMS evaluates directory protection before file protection. If you grant WORLD:R access to a file, but the file is in a directory without WORLD:R access, another user couldn't read the file. EDT Text Editor ~~~~~~~~~~~~~~ When you enter EDT, you automatically enter line mode, indicated by the EDT prompt, an asterisk (*). All line mode commands are made at the asterisk prompt and terminated by pressing . Lines that you input are numbered sequentially by the editor. You can reference a line or group of li^S^Qnes based on the line number or range of line numbers. A list of basic EDT commands follows. Each command may be abbreviated to the characters in parenthesis. Complete information on all EDT line mode commands can be found through the use of the line mode EDT HELP command. Commands Function ~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Change (C) Change from line to keypad mode. To switch back from keypad mode to line mode, press . Copy (CO) Copy a line or group of lines from one place to another. If you enter the command CO 5 to 10, line 5 will be copied to the line immediately preceding line 10. The command CO 5:10 to 20 would copy the contents of lines 5 through 10 into the area immediately preceding line 20. Delete (D) Delete a line or group of lines. The command D13 would delete line 13, while D13:20 will delete lines 13 to 20. Exit (EX) Terminates the EDT session, saving all changes. This also creates a new version of the file being edited. Help (H) Display on-line help on all EDT line mode commands. The help messages will not be included in the file being edited. Include (INC) Copy text from an external file into the file being edited. When the EDT command INCLUDE FILENAME.TYPE is executed, the contents of FILENAME.TYPE are copied into the file being edited. Insert (I) Inserts specified text directly before the current position in the file. While inserting text, you will not receive the EDT "*" prompt. Press to return to the "*" prompt when you're finished inserting. Move (M) You can't cut and paste with a line-oriented editor. Text will be moved to the area immediately preceding a specified line. The command M 10:15 to 50 would move lines 10 through 15 to the area immediately preceding line 50. Quit (QUI) Exit the EDT editor without saving changes. Replace (R) Deletes a specified line or group of lines and enters the INSERT mode so you can add text in that place. The command R5:10 would delete lines 5 through 10 and switch to the INSERT mode to permit you to enter new text. To exit the INSERT mode, press . Resequence (RES) Numbers all of the lines in the file that you're editing in increments of 1. This is useful because text insertion, movement, or deletion causes the file to lose numeric sequence. Substitute (S) Substitute a new text element for an old one in the format s/oldtext/newtext/range. The old and new text elements must be enclosed in angle bracket (< >) delimiters and the range must be specified. Write (WR) Write a given range of text to a new file. WRHISTORY.TXT 50:100 would write lines 50 through 100 to a new file called HISTORY.TXT. EDT Help Manual ~~~~~~~~~~~~~ To dump the entire EDT Help file to disk, enter the following DCL command during a terminal session: $ ASSIGN EDTHELP.FIL SYS$OUTPUT. Now, enter line mode EDT and type: * HELP *. Now exit EDT and enter the DCL command: $ ASSIGN TTnn: SYS$OUTPUTT (TTnn: is your terminal number). <:=- Part B : Programming VAX/VMS -=:> Introduction ~~~~~~~~~~~ A symbol is a name chosen to represent a string of characters, a numeric value, or a logical (true/false) value. A symbol may be used wherever the value it represents would normally be found, and can be up to 255 characters long. Symbols must begin with a character, dollar sign, or underscore, and are not case-sensitive. Symbols are created like this: symbol_name = value (local symbol) symbol_name == value (global symbol) A global symbol may be used at any command level, but local symbols are lost when command procedures are finished. For example: $ WIDE = "SET TERMINAL/WIDTH=132" Now, anytime you type WIDE at the DCL command line, the terminal width will be changed to 132 characters. To show the contents of a symbol: $ SHOW SYMBOL ANSWER ANSWER = 1584 HEX = 00000630 OCTAL = 000000003060 The SHOW SYMBOL command uses the local symbol table by default. To show the value of a global symbol, use the /GLOBAL qualifier. To show all symbols, use the /ALL qualifier (or /GLOBAL/ALL). To delete symbols, use: $ DELETE/SYMBOL symbol_name command (with /GLOBAL if it's global). When a DCL command is executed, symbols in the following positions are automatically translated: o the beginning of the command o in a lexical function o in a WRITE or IF statement o on the right side of an = or == assignment statement o inside brackets on the left side of an assignment statement when you're preforming string substitution If none of these cases fits, apostrophes will force the translation: $ DIRECTORY 'PARTS' (after $ PARTS = "DJA2:[DBA]PARTS.DAT") Symbols are commonly used for shorthand. For example, to clear the screen: $ ESC[0,8] == 27 $ CLEAR == "[J" $ HOME == "[H" $ CLR == WRITE SYS$OUTPUT ESC,HOME,ESC,CLEAR Now, anytime you enter CLR, the screen will be cleared. Symbols can also be used to execute command procedures: $ NETBACK == "@SYS$LOGIN:NETBACKUP" Finally, foreign commands unknown to DCL can be executed by using symbols: $ KERMIT == RUN SYS$$SYSTEM:KERMIT DCL Expressions ~~~~~~~~~~~~~~ Expressions are built by combining data elements with operators. A logical comparison evaluates the relationship between two components as true or false (True = 1, False = 0). Lexical functions are VAX/VMS routines that return process or system information, or manipulate user-supplied data. Lexical functions are unique because the result is returned in the function name, allowing it to be used as a symbol (much like Pascal). Lexical functions are called with the following format: F$function_name(parameter, parameter...) For example, the following lexical function manipulates user-supplied data: $ STRING = "Go home right now!" $ STRING = F$EDIT(STRING, "COMPRESS, UPCASE") $ SHOW SYMBOL STRING STRING = "GO HOME RIGHT NOW!" Command Procedures ~~~~~~~~~~~~~~~~~ A command procedure is a file consisting of a sequence of DCL commands which can be executed interactively or as a batch job (like a .BAT file in MS-DOS or a REXX EXEC in VM/SP). Command procedures are used in VAX/VMS to perform repetitive or complex tasks and to save time. With a command procedure, you can execute many DCL commands with a single statement. Command procedures aren't bound by simple lists of DCL commands executed in sequence. They can take advantage of labels, lexical functions, symbols and relational operators to build sophisticated procedures which act like VAX/VMS programs. Command procedures are flexible. They can be written to take specific actions based on responses to questions, or even to perform a given function depending on the time or date. Writing Command Procedures ~~~~~~~~~~~~~~~~~~~~~~~ A text editor such as EDT or EVE is used to create and edit command procedures, which should be named "PROCEDURE_NAME.COM". The file type ".COM" is the default procedure file type, and if a different file type is included, it must be included when the procedure is invoked. Each new command line must begin with a dollar sign ($). Multiple spaces or tabs may be included after the "$" for readability, and command lines may be extended past a single line by ending the previous line with a hyphen (-) and not starting the next line with a dollar sign. Data input to programs, such as responses, must be entered without the dollar sign. Data lines are used by the program running and are not processed by the DCL command line interpreter. For example: $ MAIL <--- invokes the Mail Utility SEND <--- Mail SEND command JONES, BOB <--- response to Mail prompt "To:" Memo <--- response to Mail prompt "Subj:" Bob, <--- Mail message How's it going?'? Joe $ <--- terminates Mail program $ EXIT <--- terminates command procedure Comments ~~~~~ Comments may be included by preceding them with an exclamation point (!), which causes everything to the right of it to be ignored by the DCL command interpreter. Comments make command procedures easier to debug and modify later. Spelling DCL commands out rather than using the abbreviations also makes the command procedure more readable. Labels ~~~ Labels are used by the DCL command line interpreter for conditional processing and repetitive looping. Labels should be placed on separate lines, making them easier to find. Labels can be 255 characters long, may not contain blanks, and must be terminated with a colon (:). Debugging ~~~~~~ The SET VERIFY command tells DCL to display each command as it processes it. This allows you to see where errors are generated, and how strings are translated. SET NOVERIFY turns the verify mode off. The SHOW SYMBOL command displays the contents of defined symbols, and is used to show the contents of a symbol in a command procedure as it is being executed. Invoking Command Procedures ~~~~~~~~~~~~~~~~~~~~~~~~~~ Command procedures may be invoked interactively by typing the "at" sign (@) followed by the procedure name. The file type must also be included if it is not ".COM" (the default). Command procedures may be invoked at the command line or from within another command procedure, called nesting. The DCL SUBMIT command will place your command (job) in a batch queue with other jobs waiting to be run. Command procedures are generally submitted as batch jobs when you want them to execute at a specific time, they will take a long time to run, or when a job must run at a reduced priority. The following command submits the command procedure ACCOUNT.COM to the VAX/VMS batch processor: $ SUBMIT ACCOUNT Job ACCOUNT (queue SYS$BATCH, entry 103) started on SYS$BATCH The SYS$BATCH queue is the default and is used unless otherwise specified with the /QUEUE qualifier. When VAX/VMS runs this job, a process with your rights and privileges will be created and the procedure executed within that process. Symbols ~~~~~~ Symbols may be local (single equal sign) or global (double equal sign). Local symbols are recognized by DCL only at the command level at which it was defined and more deeply nested levels (subsequently called command procedures). Global symbols are recognized at any command level. Local symbols should be used when the symbols is only needed for the duration of the command procedure employing it. You should only define global symbols if you're going to use them in other command procedures or for the duration of your login session. An asterisk can be used to tell the command line interpreter (CLI) to accept abbreviations. For example: $ NO*TES == "@SYS$LOGIN:NOTES" This tells the CLI to accept NO, NOT, NOTE, or NOTES as a valid abbreviation for the NOTES command. This notation is usevul for long symbol names. Lexical Functions ~~~~~~~~~~~~~~~~ Lexical functions allow you to obtain basically the same information as DCL SHOW commands. However, it's easier to manipulate information which comes from a lexical function. As an example, the following two command give the same information: $ SHOW TIME ! DCL SHOW TIME command 12-JUN-1989 14:29:23 $ WRITE SYS$OUTPUT F$TIME() ! lexical function 12-JUN-1989 14:29:25.17 The second command is more usable, however: $! Show_Date.COM $! $ TIME&DATE = F$TIME() $ DATE = F$EXTRACT(0,11,TIME&DATE) $ WRITE SYS$OUTPUT DATE This procedure displays only the date portion of the string returned by the lexical function F$TIME(). (Use @SHOW_DATE to invoke it) VAX/VMS supports lexical functions to manipulate text strings, convert data types, and return information about the system, your process, symbols, files and devices. Parameters ~~~~~~~~~ Eight reserved symbols (P1 through P8) are available to command procedures to supply data to process. By using these parameters in a command procedure, different data can be specified each time it's run. Parameter specification is done on the command line where the procedure is called. Unless designed to, the command procedure will not prompt for parameters. Parameters are separated with spaces and may be character strings, integers, or symbols. If you want to skip a parameter, us a null string (" "). $! Add.Com $! command procedure to demonstrate passing parameters $! (add the first and third parameter) $! $ WRITE SYS$OUTPUT P1+P3 $ @ADD 12 " " 14 26 If a command procedure requires multiple letters or words as a single parameter, enclose it in quotes and it will be treated as one parameter and not converted to uppercase. Terminal Output ~~~~~~~~~~~~ The WRITE and TYPE commands send data to the terminal. TYPE is used to display the contents of a file, but may also be used to print lines of text from within a command procedure. TYPE may only be used to output text strings. Since the WRITE command is processed be DCL, expressions, symbols and lexical functions are evaluated before the data is sent to the terminal. The output expression must translate to a string and be sent to the logical device SYS$OUTPUT, but may be a string, lexical function, symbol, or any combination of the three. Here's an example of a command procedure that uses terminal output: $! Writing a simple text string $! $ WRITE SYS$OUTPUT "This is a test..." $! $! Displaying multiple lines at the terminal $! $ TYPE SYS$OUTPUT Warning! It's been 30 days since you changed your password. Change it now! $! $! Writing a string with a lexical function $! $ WRITE SYS$OUTPUT " "HI' You are in directory "F$DIRECTORY()' " Terminal Input ~~~~~~~~~~~ The INQUIRE command's default device is the terminal keyboard, while the READ command must be told where to accept data from. The INQUIRE command prompts for input, reads data and assigns it to a symbol. All data is accepted as a character string and is converted to uppercase and compressed (extra blanks removed). The READ command prompts for input if the /PROMPT qualifier is used, accepts data from a specified source and assigns it to a symbol. The data is accepted with no string conversion or compression occurring. Here's an example of a command procedure that uses terminal input: $! Puts whatever you type in the symbol NAME $! the /NOPUNCTUATION qualifier will suppress the colon $! and space INQUIRE puts at the end of the prompt $! $ INQUIRE /NOPUNCTUATION NAME "What is your name? " $! $! Example of READ using SYS$INPUT (terminal) for data $! $ READ /PROMPT = "First value: " SYS$INPUT VALUE_1 $ READ /PROMPT = "Second value: " SYS$INPUT VALUE_2 $ WRITE SYS$OUTPUT VALUE_1," + ",VALUE_2," = ",VALUE_1+VALUE_2 File I/O ~~~~~~~ The basic steps to read and write files from within command procedures are similar to most other languages. Use the OPEN command to open the file. If it does not exist, OPEN will create it. Use the READ or WRITE commands to read or write text records from the file. Use the CLOSE command to close the file when you're done. To open a file for writing, you must use the /APPEND or /WRITE qualifier. The /WRITE qualifier creates a new file and places the record pointer at the beginning of the file. If the file already exists, a new version will be created by OPEN/WRITE. The /APPEND qualifier is used to add records to the end of an existing file. The file must already exist before using the OPEN/APPEND command, and when the file is opened, the record pointer is placed at the end of the file. To open a file for reading, use the /READ qualifier (the default for the OPEN command). A file opened for reading may not be written to, and the record pointer will initially be placed at the first record in the file. Each time a record is read, the pointer is moved down to the next record. The WRITE/UPDATE must be used to write over an existing record. Here's an example of a command procedure using file input and output: $ OPEN/APPEND OUTPUT_FILE NEW.DAT $ OPEN/READ INPUT_FILE OLD.DAT $ READ INPUT_FILE RECORD $ WRITE SYS$OUTPUT "First record from OLD.DAT - ",RECORD $ WRITE OUTPUT_FILE "First record from OLD.DAT - ",RECORD To open a file for both reading and writing, use both the /READ and /WRITE qualifiers. The record pointer will be placed at the first record in the file. Using this method, however, you can only overwrite the record you most recently read, and records you replace must be the same length. Redirecting Command Procedure I/O ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Command procedures often invoke VAX/VMS utilities, and these programs will normally get input from the logical device SYS$INPUT. While executing a command procedure, SYS$INPUT is directed to the command procedure itself, and this is why you can put command and data lines for a utility or program directly in the procedure. SYS$COMMAND defaults to the terminal from where a command procedure is being executed, and by redirecting SYS$INPUT to SYS$COMMAND you can use utilities and other programs interactively from command procedures: $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND: $ EDIT JUNK.DAT The /USER_MODE qualifier causes the re-assignment to be in effect only for the next command. Normally command procedure output is displayed at your terminal. You may redirect output to a file by using the /OUTPUT qualifier: $ @SHOW_TIME/OUTPUT = TIME.DAT By default, DCL error and severe error messages are directed to the file represented by the logical name SYS$ERROR, which usually points to your terminal. If you want to log error messages, simply redirect SYS$ERROR to a file. If you redirect SYS$ERROR without also redirecting SYS$OUTPUT, DCL will send error messages to both, and you'll receive the error messages twice -- at your terminal and in the file. To completely suppress error messages you can redirect both SYS$ERROR and SYS$OUTPUT to the null device (NL:) or you can use the SET MESSAGE command to turn off all message output. To suppress all messages, use: SET MESSAGE/NOTEXT/NOIDENTIFICATION/NOFACILITY/NOSEVERITY. Branching and Conditionals ~~~~~~~~~~~~~~~~~~~~~~~~~ You can use the DCL IF/THEN statements and conditional operators withing command procedures to cause the execution of a command based on the evaluation of a condition. The basic use is: $ IF condition THEN command. The condition is a Boolean expression (True or False) and the command is any legal DCL command. The following is a list of conditional operators: Operator Function ~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .EQ. / .EQS. Determines if two numbers/character strings are equal .GE. / .GES. Tests to see whether the first number/character string is greater than or equal to the second .GT. / .GTS. Determines if the first number/character string is greater than the second .LE. / .LES. Tests to see if the first number/character string is less than or equal to the second .LT. / .LTS. Determines if the first number/character string is less than the second .NE. / .NES. Tests to see whether the two numbers/character strings are not equal .AND. Combines two numbers with a logical AND (boolean algebra) .OR. Combines two numbers with a logical OR (boolean algebra) .NOT. Logically negates a value The following is a command procedure using conditional branching: $! Time.Com $! $ TIME = F$TIME() $ HOUR = F$EXTRACT(12,2,TIME) $ IF HOUR .LT. 12 THEN GOTO MORNING $ IF HOUR .LT. 17 THEN GOTO AFTERNOON $ IF HOUR .LT. 18 THEN GOTO EVENING $ GOTO END $ MORNING: $ WRITE SYS$OUTPUT "Good morning!" $ AFTERNOON: $ WRITE SYS$OUTPUT "Good afternoon!" $ EVENING: $ WRITE SYS$OUTPUT "Good evening!" $ END: $ EXIT Loops ~~ Loops are used to repeat a statement or group of statements until a given condition is met. DCL supports both DO WHILE and DO UNTIL loops. The DO WHILE loop tests the condition before evaluation: $ LOOP: $ IF .NOT. condition THEN GOTO END . . . $ GOTO LOOP $ END: $ EXIT The DO UNTIL loop executes the statement(s) and then tests the condition: $ LOOP: . . . $ IF condition THEN GOTO LOOP $ EXIT Subroutines ~~~~~~~~ The DCL command GOSUB transfers execution control to a label and the RETURN command terminates subroutine execution, returning control to the statement after the GOSUB command. Subroutines are useful where you need to do the same series of commands repeatedly in different parts of a command procedure. They also make procedures easier to read and more compact. The DCL commands GOSUB and RETURN are not supported in VAX/VMS versions before VAX/VMS Version 4.4. The following is an example procedure using a subroutine: $! Personal.Com $! $! opens the personal info file $! $ OPEN/WRITE OUTPUT_FILE PERINFO.DAT $! $! collect info $! $ INQUIRE RECORD "Enter full name" $ GOSUB WRITE_FILE $ INQUIRE RECORD "Enter address" $ GOSUB WRITE_FILE $ INQUIRE RECORD "Enter phone number" $ GOSUB WRITE_FILE $ CLOSE OUTPUT_FILE $ EXIT $! $! subroutine WRITE_FILE $! $ WRITE_FILE: $ WRITE OUTPUT_FILE RECORD $ RETURN Error Handling ~~~~~~~~~~~~~ The command interpreter will execute an EXIT command if a severe error occurs, terminating the procedure and returning control to the previous command level, unless the DCL ON command is used to specify an action for the command interpreter to take. The ON command supports the three keywords WARNING, ERROR, and SEVERE_ERROR. To override error handling for procedure warnings, for example, use something like this: $ ON WARNING THEN EXIT or $ ON WARNING THEN GOTO label WARNING causes the command procedure to take action if a warning, error, or severe error occurs. ERROR causes the action if an error or severe error occurs, and SEVERE_ERROR causes the action only if a fatal error occurs. $STATUS and $SEVERITY are reserved DCL global symbols, and each time a command is executed, values are assigned to these symbols. $STATUS holds the full condition code of the last statement and $SEVERITY holds an error severity level. The condition code in $STATUS is valid to the VAX/VMS MESSAGE facility and can be used in conjunction with F$MESSAGE to obtain the actual text message associated with the code: $ SET DEFAULT DUB1:[BYNON] $ WRITE SYS$OUTPUT $STATUS $X00000001 $ WRITE SYS$OUTPUT F$MESSAGE(%X00000001) % SYSTEM-S-NORMAL, normal successful completion All DCL commands will return a condition code, but not all condition codes have text messages. Condition codes without text messages will return the message "%NONAME-E-NOMSG Message number (8-digit code)". The message text isn't very useful for making conditional decisions though, so $SEVERITY is used. It contains one of five possible values extracted from the first three bits of $STATUS. Here are the codes: Code Definition ~~~ ~~~~~~~~~~ 0 Warning 1 Success 2 Error 3 Information 4 Severe Error Odd values (1,3) indicate success while even values (0,2,4) indicate failure. There are basically two ways to use the status and severity codes to handle errors. The first is to treat $STATUS as a Boolean value: $ SET NOON $ command ! a DCL command $ IF $STATUS THEN GOTO NO_ERR ! test $STATUS for T or F . . ! handle the error . $ NO_ERR ! continue processing . . . $ EXIT The second method is to trap the error with the ON WARNING command, then use the severity level to determine an appropriate course of action: $ SET NOON $ ON WARNING GOTO ERR_TRAP $ command ! a DCL command $ command ! a DCL command . . . $ EXIT $! $! error trap code $! $ ERR_TRAP: $ SEVERITY = $SEVERITY ! save the error code $ IF SEVERITY = 0 THEN command ! if warning... $ GOTO DONE $ IF SEVERITY = 2 THEN command ! if error... $ GOTO DONE $ IF SEVERITY = 4 THEN command ! if severe error... $ DONE: . . . $ EXIT Error checking can be completely disabled with the SET NOON command. When this is in effect, the command interpreter continues updating the condition code, but does not perform any error checking. The DCL command SET ON restors error checking to normal. For example: $ SET NOON ! turn off error checking $ command ! a DCL command $ SET ON ! restor error checking Termination ~~~~~~~~~~ The EXIT command will terminate the current command procedure and return control to the command level that called it while the STOP command terminates all command procedures (if nested) and returns control to DCL. Example Command Procedures ~~~~~~~~~~~~~~~~~~~~~~~~~ The following are two example command procedures to demonstrate some of the previously discussed techniques. Login.Com ~~~~~~~~ $! Login.Com - executed each time you log in $! $! Check for a network or batch login $! $ IF F$MODE() .EQS. "NETWORK" THEN GOTO NETWORK $ IF F$MODE() .EQS. "BATCH" THEN GOTO BATCH $! $! Define process permanent symbols for convenience $! $ SD == "SET DEFAULT" $ SH == "SET HOST" $ WI*DE == "SET TERMINAL/WIDTH=132" $ NA*RROW == "SET TERMINAL/WIDTH=80" $ DIR*ECTORY == "DIRECTORY/SIZE" $ PU*RGE == "PURGE/LOG/KEEP=2" ! keep latest 2 version $ HO*ME == "SET DEFAULT SYS$LOGIN:" $ WHO == "SHOW USERS" $ EVE == "EDIT/TPU" $ EDT == "EDIT/EDT/COMMAND=SYS$LOGIN:EDTINI.EDT" $ BR*OWSE == "TYPE/PAGE" $! $! Define special keys $! $ DEFINE/KEY/NOLOG/TERM PF1 "DIR" ! term ends with $ DEFINE/KEY/NOLOG PF2 "EDIT" $ DEFINE/KEY/NOLOG/TERM/NOECHO PF3 "LOGOUT" $ DEFINE/KEY/NOLOG/TERM/NOECHO HELP "SHOW KEY/ALL" $! $! Modify terminal characteristics $! $ SET TERMINAL/INSERT ! insert mode $ SET PROMPT = "[BYNON]> " $! $! Show time and quit $! $ SHOW TIME $ EXIT $! $! If it's a network login, we can now $! perform some other commands if desired. $! Just quit for now though. $! $ NETWORK: $ EXIT $! $! If it's a batch job login, set verification on and quit. $! $ BATCH: $ SET VERIFY $ EXIT Subdir.Com ~~~~~~~~~ $! Subdir.Com - how to search and parse character strings $! $ WRITE SYS$OUTPUT F$DIRECTORY()+ " Subdirectories:" $ WRITE SYS$OUTPUT " " $! $! Search for subdirectory names and display them on the terminal $! $ DIR$LOOP: $ FILE = F$SEARCH("*.DIR") $! $! If DCL returns a null string (" ") we're done $! $ IF FILE .EQS. " "THEN GOTO END$DIR$LOOP $! $! Find the position of the period $! $ DOT = F$LOCATE(".",FILE) $! $! Find the position of the right bracket $! $ BRACKET = F$LOCATE("]",FILE) $! $! Extract the string between the dot and bracket $! $ FILE = F$EXTRACT(BRACKET+1,DOT-BRACKET-1,FILE) $! $! Display the subdirectory name and start over $! $ WRITE SYS$OUTPUT " ' 'FILE' " $ GOTO DIR$LOOP $ END$DIR$LOOP: $ EXIT ______________________________________________________________________________