User Tools

Site Tools


anatomy_of_your_login-dot-com_script

This is an old revision of the document!


Anatomy of Your LOGIN.COM Script

Your LOGIN.COM command file (or script) may be one of the most important files you'll ever use and maintain on a VMS system. It is stored in your own “home directory” (logical name SYS$LOGIN), and your version or instance of LOGIN.COM is yours alone, unique to you and your needs.

Your LOGIN.COM script is also a “work-in-progress”… you will likely find reasons to modify and update it frequently over the years (especially if you're reading these PARSEC Wiki Articles out of curiosity or a desire to learn more), and as such, it's “never done!” It is:

  • The means by which you “tailor” or “customize” your own VMS login environment, making it specific and useful to your needs.
  • An expression of your on-going development with VMS tools and concepts.
  • A place to keep notes, ideas and experiments with VMS concepts and resources.

Maintaining Your LOGIN.COM

You maintain (update, change, evolve) your LOGIN.COM with any standard VMS text editor, such as EVE, EDT, Emacs, or whatever you like to use:

$ SHOW DEFAULT
DSA2:[LRICKER]
$ ! equivalent to SYS$LOGIN for this user...
$ SHOW LOG SYS$LOGIN /FULL
   "SYS$LOGIN" [exec] = "DSA2:[LRICKER]" (LNM$JOB_859C3940)
$
$ EDIT /TPU LOGIN.COM

  ... edit window/buffer appears, editing occurs ...

Don't forget to save your work (changes) frequently – each editing file SAVE or WRITE operation creates a new version of your LOGIN.COM file, so you can “always go back” if something doesn't turn out right. PURGE this file if and whenever necessary.

Structure of LOGIN.COM (template, skeleton)

When you first got your own VMS login account (username, home directory, etc.), your VMS system administrator likely “seeded” a site-specific stock copy of a LOGIN.COM command file in your home directory when s/he created it. That “seed file” may have been well organized and thought-out… or maybe it wasn't.

Let's look at a trivial, empty LOGIN.COM script, a sort of “skeleton” for the various parts that a well-organized LOGIN.COM script should look like:

$ ! LOGIN.COM -- "My" login script -- template/skeleton version   'F$VERIFY(0)'
$ !
$ GOTO 'F$MODE()'                                      !  3
$ !
$ ! ==========                                         !  5
$INTERACTIVE:                                          !  6
$ SET TERMINAL /INQUIRE                                !  7
$ !
$ ! Interactive login process definitions go here...   !  9
$ !
$ EXIT    ! 'F$VERIFY(0)'                              ! 11
$ !
$ ! ==========                                         ! 13
$BATCH:                                                ! 14
$ !
$ ! Batch job definitions, if any, go here...          ! 16
$ ! (Why don't we do a SET TERMINAL command here?)     ! 17
$ !
$ EXIT    ! 'F$VERIFY(0)'                              ! 19
$ !
$ ! ==========                                         ! 21
$NETWORK:                                              ! 22
$OTHER:                                                ! 23
$ ! This section is rarely, if ever, used...           ! 24
$ !
$ EXIT    ! 'F$VERIFY(0)'                              ! 26
$ !

The non-empty (comment) lines are numbered above. After the first (line #1) comment, internal-documentation line, here's how these lines work or function in this skeleton script:

  • Line 3 – The most important line in the whole script. This GOTO command functions much like a case statement in another, higher-level language; this is DCL's best shot at a case-like statement/function. Its purpose is to immediately direct DCL flow-of-execution to one of three “stanzas” (sections) of code (statements), each labelled with one of the strings-of-characters “INTERACTIVE”, “BATCH”, “NETWORK” or “OTHER” – see line-#s 6, 14, 22 and 23. The GOTO statement's “target” is determined by the DCL Lexical Function F$MODE(), which (when called or invoked) returns one of those four character strings, depending on the execution mode of the process (your login process, for example) when it executes your LOGIN.COM file.
  • Lines 5, 13 and 21 – these lines $ ! ========== are simply used as visual separators between the execution-mode stanzas (sections).
  • Line 6 – The label “INTERACTIVE:” which is the line that the $ GOTO F$MODE() statement (line 3) jumps to when the process is executing LOGIN.COM as an interactive process.
  • Line 14 – The label “BATCH:” which is the line that the $ GOTO F$MODE() statement (line 3) jumps to when the process is executing LOGIN.COM as a batch process.
  • Lines 22 and 23 – The labels “NETWORK:” and “OTHER:”, the lines that the $ GOTO F$MODE() statement (line 3) jumps to when the process is executing LOGIN.COM as either a network or a detached (“other”) process.
  • Line 7 – This $ SET TERMINAL /INQUIRE command ensures that your terminal (PuTTY) window is set up as a VT-terminal compatible device, necessary so that you can do full-screen editing and other screen-oriented tasks. And if you prefer overstrike-mode line editing to insert-mode line editing (the default), change this line to read: $ SET TERMINAL /INQUIRE /OVERSTRIKE – will take effect the next time you login, or if you execute $ @LOGIN immediately after saving this file edit.
  • Line 9 – The comment on this line suggests that you'll be replacing it (the comment) with actual command alias (global symbol) and logical name definitions to tailor your VMS environment for interactive work and com-line use. This is “where the action is”… You'll add, change and enhance DCL statements here over the months and years of VMS use to keep your environment “up to date” and useful.
  • Line 9 – A place-holder comment, suggesting that you will replace it with “real stuff,” actual DCL command alias and logical name definitions (and other things) that contribute together to make up your own VMS login environment – VMS the way you want it.
  • Line 16 – Similar to Line 9 above, but here only a few commands (if any) are used to define or enhance your process environment for batch jobs. Minimally used (by most folks), but useful for some specific things.
  • Line 17 – A comment which asks a reasonable question: Why don't we do a SET TERMINAL command in the BATCH stanza? If you try it, you'll see why (and don't forget to take that test command out of your LOGIN.COM when you've figured this out!).
  • Line 24 – Similar to Lines 9 and 16 above, but this comment is rarely replaced, as network and detached process environments are usually self-defining, and don't need much from LOGIN.COM.
  • Lines 11, 19 and 26 – DCL EXIT commands (which also use the Lexical Function F$VERIFY(0) to ensure that command file execution-verification (tracing) is turned off (if it was on).

The above is nothing more than a skeleton, a template, for a real LOGIN.COM file. It has the advantage of being well-structured and simple to understand, therefore simple to maintain and extend into your future. Other forms and contents of the file are possible, and you may see those other formats. Unfortunately, the contents of many LOGIN.COM files that we've seen “in the wild” are unstructured, often a tangled mass of:

$ IF F$MODE() .EQS. "INTERACTIVE" THEN do-something
...
$ IF F$MODE() .EQS. "BATCH" THEN do-something-else
...
$ IF F$MODE() .EQS. "INTERACTIVE" THEN declare-something-elsse
$ IF F$MODE() .NES. "BATCH" THEN GOTO some-other-lable
...

…Well, you get the idea. Spaghetti code is not much fun to extend or maintain. We advocate and teach the skeleton-template form above.

First Enhancement to LOGIN Script

Here's a possible first pass which extends the template LOGIN.COM file, maybe suitable for an “ordinary, normal user” of VMS:

$ ! LOGIN.COM -- "My" login script -- 1st version                  'F$VERIFY(0)'
$ !
$ ! Likely want this set the same way for all process types:
$ SET PROTECTION=(S:RWED,O:RWED,G,W) /DEFAULT
$ !
$ GOTO 'F$MODE()'
$ !
$ ! ==========
$INTERACTIVE:
$ SET TERMINAL /INQUIRE /INSERT
$ !
$ CALL CreDir "LOGS"  ! create a sub-dir for batch log-files     ! ***
$ !
$ ! VMS-style command aliases (symbols) --                       ! ***
$ dir      == "DIRECTORY /SIZE /DATE /PROTECTION"                ! ***
$ move     == "RENAME"                                           ! ***
$ prlj     == "PRINT /QUEUE=LASERJET /LOG"                       ! ***
$ ssys*tem == "PIPE SHOW SYSTEM | SEARCH SYS$PIPE "              ! ***
$ SUBM*IT  == "SUBMIT /NOTIFY /NOPRINT /LOG_FILE=logs:"          ! ***
$ count    == "PIPE SHOW SYSTEM | SEARCH SYS$PIPE /STATISTICS "  ! ***
$ ! ...                                                          ! ***
$ !
$ SET PROMPT="''F$DIRECTORY()'$ "                                ! ***
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$ ! ==========
$BATCH:
$ !
$ ! Batch job definitions, if any, go here...
$ ! (Why don't we do a SET TERMINAL command here?)
$ !
$ ! Replicate this interactive symbol, for consistency
$ !   in self-SUBMITted batch jobs --
$ SUBM*IT  == "SUBMIT /NOTIFY /NOPRINT /LOG_FILE=logs:"          ! ***
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$ ! ==========
$NETWORK:
$OTHER:
$ ! This section is rarely, if ever, used...
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$CreDir: SUBROUTINE
$ ! P1 : Subdirectory to test and create
$ ! P2 : Job logical name to define
$ IF ( P2 .EQS. "" ) THEN P2 = P1
$ homedd = F$TRNLNM("SYS$LOGIN") - "]"
$ IF ( F$SEARCH("''P1'.DIR;1") .EQS. "" )
$ THEN CREATE /DIRECTORY [.'P1']
$ ENDIF
$ DEFINE /JOB /NOLOG 'P2' 'homedd'.'P1']
$ EXIT 1
$ ENDSUBROUTINE  ! CreDir
$ !

The comments ! *** mark the lines where are added to replace INTERACTIVE stanza Line 9 in the original template/skeleton, plus a line added to the BATCH stanza to make re-submits easier.

This also includes a DCL subroutine, labelled CreDir (for “create directory”) at the end of this script, to test for a user's home directory subdirectory, conditionally creating it plus a suitable logical name if it doesn't already exist.

Note that these enhancement lines were easy to add right into the appropriate INTERACTIVE or BATCH stanza, and didn't take any complicated IF/THEN/ELSE logic to make things work right. It's always best to keep things simple…

Enhancements for a Power User

Here's a version for a VMS “power user”:

$ ! LOGIN.COM -- "My" login script -- 2nd version                  'F$VERIFY(0)'
$ !
$ ! Likely want this set the same way for all process types:
$ SET PROTECTION=(S:RWED,O:RWED,G,W) /DEFAULT
$ !
$ GOTO 'F$MODE()'
$ !
$ ! ==========
$INTERACTIVE:
$ SET TERMINAL /INQUIRE /INSERT
$ SET CONTROL=(Y,T)
$ !
$ CALL CreDir "SYS$SCRATCH"
$ CALL CreDir "LOGS"
$ CALL CreDir "COM"
$ !
$ EveInitF = "sys$login:eve$init.eve"
$ IF ( F$SEARCH(EveInitF) .EQS. "" )
$ THEN CREATE 'EveInitF'  ! a *nix-style "here-doc":
! EVE$INIT.EVE -- sets EDT-keypad and bound-cursor modes:
SET KEYPAD EDT
SET CURSOR BOUND
$ ! -- end of "here-doc" data
$ ENDIF
$ DEFINE /PROCESS /NOLOG eve$init 'EveInitF'
$ !
$ ! VMS-style command aliases (symbols) --
$ dir      == "DIRECTORY /SIZE /DATE /PROTECTION"
$ ed*it    == "EDIT /TPU /INIT=eve$init"
$ move     == "RENAME"
$ prlj     == "PRINT /QUEUE=LASERJET /LOG"
$ ssys*tem == "PIPE SHOW SYSTEM | SEARCH SYS$PIPE "
$ SUBM*IT  == "SUBMIT /NOTIFY /NOPRINT /LOG_FILE=logs:"
$ count    == "PIPE SHOW SYSTEM | SEARCH SYS$PIPE /STATISTICS "
$ !
$ ! Linux/Unix-style command aliases (symbols) --
$ cd       == "SET DEFAULT"
$ pwd      == "SHOW DEFAULT"
$ cls      == "TYPE /PAGE=CLEAR_SCREEN NLA0:"
$ cp       == "COPY"
$ rm       == "DELETE"
$ mv       == "RENAME"
$ ls       == "DIRECTORY /SIZE /DATE /PROTECTION"
$ home     == "PIPE SET DEFAULT sys$login ; SHOW DEFAULT"
$ upt*ime  == "SHOW SYSTEM /NOPROCESS /FULL"
$ !
$ PgSize  = F$INTEGER(F$GETDVI("TT","TT_PAGE")) - 2    ! allow some margin
$ PgWidth = F$INTEGER(F$GETDVI("TT","DEVBUFSIZ")) - 2
$ tail     == "TYPE /TAIL=''PgSize'"
$ ! ...
$ !
$ nodename = F$EDIT( F$GETSYI("NODENAME"), "TRIM,UPCASE" )
$ SET PROMPT="''nodename'$ "
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$ ! ==========
$BATCH:
$ !
$ ! Batch job definitions, if any, go here...
$ ! (Why don't we do a SET TERMINAL command here?)
$ !
$ ! Replicate this interactive symbol, for consistency
$ !   in self-SUBMITted batch jobs --
$ SUBM*IT  == "SUBMIT /NOTIFY /NOPRINT /LOG_FILE=logs:"
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$ ! ==========
$NETWORK:
$OTHER:
$ ! This section is rarely, if ever, used...
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$CreDir: SUBROUTINE
$ ! P1 : Subdirectory to test and create
$ ! P2 : Job logical name to define
$ IF ( P2 .EQS. "" ) THEN P2 = P1
$ homedd = F$TRNLNM("SYS$LOGIN") - "]"
$ IF ( F$SEARCH("''P1'.DIR;1") .EQS. "" )
$ THEN CREATE /DIRECTORY [.'P1']
$ ENDIF
$ DEFINE /JOB /NOLOG 'P2' 'homedd'.'P1']
$ EXIT 1
$ ENDSUBROUTINE  ! CreDir
$ !

The CreDir subroutine is called for two more (suggested) subdirectories.

Sys-Admin's LOGIN script

Here's a version with command-tools for a VMS system administrator:

$ ! LOGIN.COM -- "My" login script -- 3rd version                  'F$VERIFY(0)'
$ !              with System Administrator tools
$ !
$ ! Likely want this set the same way for all process types:
$ SET PROTECTION=(S:RWED,O:RWED,G,W) /DEFAULT
$ !
$ GOTO 'F$MODE()'
$ !
$ ! ==========
$INTERACTIVE:
$ SET TERMINAL /INQUIRE /INSERT
$ SET CONTROL=(Y,T)
$ !
$ CALL CreDir "SYS$SCRATCH"
$ CALL CreDir "LOGS"
$ CALL CreDir "COM"
$ !
$ EveInitF = "sys$login:eve$init.eve"
$ IF ( F$SEARCH(EveInitF) .EQS. "" )
$ THEN CREATE 'EveInitF'  ! a *nix-style "here-doc":
! EVE$INIT.EVE -- sets EDT-keypad and bound-cursor modes:
SET KEYPAD EDT
SET CURSOR BOUND
$ ! -- end of "here-doc" data
$ ENDIF
$ DEFINE /PROCESS /NOLOG eve$init 'EveInitF'
$ !
$ ! VMS-style command aliases (symbols) --
$ IF F$GETSYI("ARCH_NAME") .NES. "VAX"
$ THEN dir == "DIRECTORY /ACL /SIZE /DATE /PROT /WIDTH=(FILENAME=24,SIZE=10)"  !Alpha, Itanium
$ ELSE dir == "DIRECTORY /ACL /SIZE /DATE /PROT /WIDTH=SIZE=7"
$ ENDIF
$ ed*it    == "EDIT /TPU /INIT=eve$init"
$ move     == "RENAME"
$ prlj     == "PRINT /QUEUE=LASERJET /LOG"
$ ssys*tem == "PIPE SHOW SYSTEM | SEARCH SYS$PIPE "
$ SUBM*IT  == "SUBMIT /NOTIFY /NOPRINT /LOG_FILE=logs:"
$ count    == "PIPE SHOW SYSTEM | SEARCH SYS$PIPE /STATISTICS "
$ !
$ ! Linux/Unix-style command aliases (symbols) --
$ cd       == "SET DEFAULT"
$ pwd      == "SHOW DEFAULT"
$ cls      == "TYPE /PAGE=CLEAR_SCREEN NLA0:"
$ !           See also [...BEGINNER]ANSISEQ.COM for a better approach to clr-screen
$ cp       == "COPY"
$ rm       == "DELETE"
$ mv       == "RENAME"
$ ls       == "DIRECTORY /SIZE /DATE /PROTECTION"
$ home     == "PIPE SET DEFAULT sys$login ; SHOW DEFAULT"
$ upt*ime  == "PIPE SHOW SYSTEM /NOPROCESS | SEARCH /HIGHLIGHT=UNDERLINE sys$pipe uptime"
$ !
$ PgSize  = F$INTEGER(F$GETDVI("TT","TT_PAGE")) - 2    ! allow some margin
$ PgWidth = F$INTEGER(F$GETDVI("TT","DEVBUFSIZ")) - 2
$ tail     == "TYPE /TAIL=''PgSize'"
$ !
$ ! Pick up TCP/IP command set (if HP-stack):
$ tcpipdef = "sys$manager:tcpip$define_commands.com"
$ IF ( F$SEARCH(tcpipdef) .NES. "" ) THEN @'tcpipdef'
$ ! (If your TCP/IP stack is MultiNet or TCPware, then the above doesn't apply,
$ !  and your TCP-commands will be defined differently, see your doc-set.)
$ !
$ ! System Administrator tools --
$ anim*age    == "ANALYZE /IMAGE /SELECT=(ARCH,IMAGE_TYPE,IDENT=IMAGE,NAME)"
$ break*in    == "SHOW INTRUSION /TYPE=ALL"
$ delbreak*in == "DELETE /INTRUSION_RECORD"
$ chks*um     == "CHECKSUM /ALGORITHM=MD5 /SHOW=ALL"
$ crc         == "CHECKSUM /ALGORITHM=CRC /SHOW=ALL"
$ disk*s      == "SHOW DEVICE /MOUNTED D"
$ dheader     == "DUMP /HEADER /BLOCK=COUNT=0"
$ sclu*ster   == "SHOW CLUSTER /CONTINUOUS"
$ IF F$SEARCH("sys$login:show_cluster$init.ini") .NES. ""
$ THEN DEFINE /PROCESS /SUPERVISOR /NOLOG show_cluster$init sys$login:show_cluster$init.ini
$ ENDIF
$ !
$ privcomf = "com:privilege.com"  ! (from Lorin's repository)
$ IF ( F$SEARCH( privcomf ) .NES. "" )
$ THEN priv   == "@''privcomf'"
$      pow*er == "@''privcomf'" - ".COM" - " ONE$SHOT" + " ONE$SHOT"
$      sudo   == "''power'"   ! make a Linux-synonym too...
$ ENDIF
$ !
$ IF F$TYPE(authorize) .EQS. "" THEN auth*orize == "$SYS$SYSTEM:AUTHORIZE"
$ IF F$TYPE(sysgen)    .EQS. "" THEN sysgen     == "$SYS$SYSTEM:SYSGEN"
$ IF F$TYPE(sysman)    .EQS. "" THEN sysman     == "$SYS$SYSTEM:SYSMAN SET ENV/CLU"
$ IF F$TYPE(lancp)     .EQS. "" THEN lancp      == "$SYS$SYSTEM:LANCP"
$ IF F$TYPE(ncp)       .EQS. "" THEN ncp        == "$SYS$SYSTEM:NCP"
$ IF F$TYPE(ncl)       .EQS. "" THEN ncl        == "$SYS$SYSTEM:NCL"
$ !
$ nodename = F$EDIT( F$GETSYI("NODENAME"), "TRIM,UPCASE" )
$ SET PROMPT="''nodename'$ "
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$ ! ==========
$BATCH:
$ !
$ ! Batch job definitions, if any, go here...
$ ! (Why don't we do a SET TERMINAL command here?)
$ !
$ ! Replicate this interactive symbol, for consistency
$ !   in self-SUBMITted batch jobs --
$ SUBM*IT  == "SUBMIT /NOTIFY /NOPRINT /LOG_FILE=logs:"
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$ ! ==========
$NETWORK:
$OTHER:
$ ! This section is rarely, if ever, used...
$ !
$ EXIT    ! 'F$VERIFY(0)'
$ !
$CreDir: SUBROUTINE
$ ! P1 : Subdirectory to test and create
$ ! P2 : Job logical name to define
$ IF ( P2 .EQS. "" ) THEN P2 = P1
$ homedd = F$TRNLNM("SYS$LOGIN") - "]"
$ IF ( F$SEARCH("''P1'.DIR;1") .EQS. "" )
$ THEN CREATE /DIRECTORY [.'P1']
$ ENDIF
$ DEFINE /JOB /NOLOG 'P2' 'homedd'.'P1']
$ EXIT 1
$ ENDSUBROUTINE  ! CreDir
$ !

This final sample just adds more command aliases suitable for a system manager's needs.

Hopefully, these samples will give you some good ideas for your own LOGIN.COM file.

anatomy_of_your_login-dot-com_script.1542836193.txt.gz · Last modified: 2018/11/21 21:36 by lricker

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki