From: SMTP%"MARSHALL@nebula.ssd.lmsc.lockheed.com" 18-MAY-1993 19:56:28.24 To: EVERHART CC: Subj: ZTDRIVER user interface enhancements Date: Tue, 18 May 1993 16:58:13 -0700 (PDT) From: Bob Marshall Org 6791 Bldg 561 x65737 To: MOELLER@gwdgv1.dnet.gwdg.de, EVERHART@arisia.gce.com Message-Id: <930518165813.20803922@NEBULA.SSD.LMSC.LOCKHEED.COM> Subject: ZTDRIVER user interface enhancements Wolfgang/Glenn, I have ZTDRIVER running pretty well now. I still need to do some thinking about really bullet-proofing the whole thing, though. I've been working from home 160 miles away from the actual nodes I'm using for testing, so it's difficult to do exhaustive testing. Anyway, here is an example of how things look from the ZT-side when everything is successful (NEBULA is the "ZT-side", and VCS is the "real-tape" side) : ---------------------------------------------------- NEBULA> rmt :== @sys$sysp:[remotetape]rmt NEBULA> rmt Name of node with tape drive [VCS] : Name of remote tape device [VCS$MUA0:] : Mount your tape on VCS$MUA0: now. Press when the tape is mounted and the drive is on-line... Stand by, VCS is attempting to mount the tape... %VCS-I-MESSAGE, %MOUNT-I-MOUNTED, GUY_03 mounted on _VCS$MUA0: Now a subprocess will be spawned to allow you to use the tape drive. You may issue any necessary commands, e.g., MOUNT, BACKUP, COPY, etc. When you are done with the drive, simply LOGOUT to terminate the subprocess and return control to this procedure. %DCL-S-SPAWNED, process RMT_20803922 spawned %DCL-S-ATTACHED, terminal now attached to process RMT_20803922 RMT_NEBULA> show device/full zta0 Magtape $1$ZTA0: (NEBULA), device type TE16, is online, record-oriented device, file-oriented device. Error count 0 Operations completed 646 Owner process "" Owner UIC [0,0] Owner process ID 00000000 Dev Prot S:RWED,O:RWED,G:RWED,W:RWED Reference count 0 Default buffer size 4 Density 1600 Format Normal-11 Allocation class 1 Volume status: no-unload on dismount, position lost, odd parity. RMT_NEBULA> mount/for zta0: %MOUNT-I-MOUNTED, GUY_03 mounted on _$1$ZTA0: (NEBULA) RMT_NEBULA> backup/list zta0: Listing of save set(s) Save set: 05_12.BCK Written by: SYSTEM UIC: [000001,000004] Date: 12-MAY-1993 06:58:19.68 Command: BACKUP/NOREWIND/LOG/IGNORE=LABEL/BEFORE=-5-00:00:00/DELETE VC S$LOG:VCS$19%%_%%_%%.LOG;*,VCS$LOG:VCS$EVENT*.LOG MUA0:05_12.BCK Operating system: VAX/VMS version V5.5 BACKUP version: V5.5 CPU ID register: 08000000 Node name: _VCS:: Written on: _VCS$MUA0: Block size: 8192 Group size: 10 Buffer count: 38 [VCS.LOG]VCS$1993_04_29.LOG;1 2118 29-APR-1993 00:00 Interrupt RMT_NEBULA> logout Process RMT_20803922 logged out at 18-MAY-1993 15:51:29.54 %DCL-S-RETURNED, control returned to process ttttrrrrrrrrr Cleaning up... Dismounting $1$ZTA0... Terminating the ZT2 program... Telling remote node that we are done... Closing network link... NEBULA> show device zta0 Device Device Error Volume Free Trans Mnt Name Status Count Label Blocks Count Cnt $1$ZTA0: (NEBULA) Offline 0 NEBULA> ------------------------------------------------------------ I haven't changed any of the original code. All I have really done is to write two command procedures, one which resides on the "ZT-side", and the other which resides on the "real-tape" side (as a network object). They are not finished products, but I thought I'd run them by you anyway to make sure there are no major errors in philosophy : RMT.COM (ZT-side) : $! RMT.COM $! $! This procedure is used to implement the remote mag tape utility for $! using a mag tape on the node defined by default by the logical name $! RMT_REMOTE_NODE. The default remote tape drive to be used is defined $! by the logical name RMT_REMOTE_TAPE. $! $! Usage : $! $! o Mount the tape on the remote node and put the drive on-line $! o @dev:[dir]RMT $! $! (Gory details at end of procedure) $! $! Written by : Bob Marshall $! 17 May 1993 $!************************************************************************** $! $ set noon $! $ default_remote_node = f$trnlnm("RMT_REMOTE_NODE") $ write sys$output "" $ if default_remote_node .eqs. "" $ then $ read/prompt="Name of node with tape drive : " sys$command remote_node $ if remote_node .eqs. "" then exit ! Ya gotta enter something! $ else $ read/prompt="Name of node with tape drive [''default_remote_node'] : " - sys$command remote_node $ if remote_node .eqs. "" then remote_node = default_remote_node $ endif $! $ default_remote_tape = f$trnlnm("RMT_REMOTE_TAPE") $ if default_remote_tape .eqs. "" then default_remote_tape = "MUA0:" $! $ write sys$output "" $ read/prompt="Name of remote tape device [''default_remote_tape'] : " - sys$command remote_tape $ if remote_tape .eqs. "" then remote_tape = default_remote_tape $! $ write sys$output "" $ write sys$output - "Mount your tape on ''remote_tape' now. Press when the tape" $ read/prompt="is mounted and the drive is on-line..." sys$command dummy $! $! Open the network link to the remote node $! $! (Note : to use an object number other than 142, specify that number here) $! $ open/read/write/err=err_openlink netline 'remote_node'::"142=" $! $ this_node = f$trnlnm("sys$node") - "::" - "_" $ write netline this_node $ write netline remote_tape $ on control_y then goto done $! $ write sys$output "" $ write sys$output "Stand by, ''remote_node' is attempting to mount the tape..." $! $ readloop: $! $! Read any output from the remote side, looking for the string "**CONTINUE**" $! $ k = 0 $ read/time_out=60/err=err_start_server netline message $ if message .eqs. "**ERROR**" then goto close $ if message .nes. "**CONTINUE**" $ then $ if message .nes. "" then - write sys$output "%''remote_node'-I-MESSAGE, ",message $ k = k + 1 $! if k .gt. 10 then goto err_start_server $ goto readloop $ endif $! $! At this point things seem to be OK on the remote side; now just wait for $! ZTA0: to come on-line. $! $ wait_for_zta0: $! $ tape_status = f$getdvi("$1$ZTA0:","STS") $ if (tape_status .and. %X10) .ne. %X10 $ then $ wait 00:00:05.00 $ goto wait_for_zta0 $ endif $! $! OK, ZTA0: is on-line $! $ prompt = f$environment("PROMPT") $ type sys$input Now a subprocess will be spawned to allow you to use the tape drive. You may issue any necessary commands, e.g., MOUNT, BACKUP, COPY, etc. When you are done with the drive, simply LOGOUT to terminate the subprocess and return control to this procedure. $ pid = f$getjpi("","pid") ! Generate a useful process name $ spawn/prompt="RMT_''prompt'"/process="RMT_''pid'" ! SPAWN $! $ done: $! $! Clean up (dismount tape, zap ZT2, close the link) $! $ set noon $ write sys$output "" $ write sys$output "Cleaning up..." $ if f$getdvi("$1$ZTA0:","MNT") $ then $ write sys$output "Dismounting $1$ZTA0..." $ dismount/nounload $1$zta0: ! Remove the /NOUNLOAD after testing $ endif $ write sys$output "Terminating the ZT2 program..." $ run sys$sysp:[remotetape]zt2_forcex $ write sys$output "Telling remote node that we are done..." $ write netline "**DONE**" $ read/err=continue/time_out=60 netline message $ wait 00:00:05.00 ! Give remote process time to die $! $! Comment the following stuff out for now...I think we don't need $! to do it. It would be used if we didn't $FORCEX ZT2 and instead $! just stopped ZTNS2 (actually we are doing both). $! $! save_message = f$environment("MESSAGE") $! set message/nofac/notext/nosever/noident $! mount/for/noassist $1$ZTA0: $! set message 'save_message' $! $ close: $! $ write sys$output "Closing network link..." $ close netline $ write sys$output "" $ exit $! $ err_openlink: $! $ write sys$output "" $ write sys$output - "%RMT-F-OPENLINK, Error opening network link to ''remote_node'" $ write sys$output "" $ exit $! $ err_start_server: $! $ write sys$output "" $ write sys$output - "%RMT-F-NOSTART, Error starting remote tape server on ''remote_node'" $ write sys$output "" $ write netline "**DONE**" $ close netline $ exit $!********************************************************************* $! $! Gory details : $! $! This procedure performs the following tasks in cooperation with a $! network object on the remote node : $! $! o Prompts the user for the name of the remote node, and the name of $! the remote tape device. $! o Opens a network link to network object #142 on the node with the $! tape drive. Object #142 is just a command procedure that does $! various things, described below. $! o Waits for the command procedure on the remote side to take the steps $! necessary to put ZTA0: on-line. $! o Spawns a subprocess to allow the user to use ZTA0: as he pleases. When $! the user logs out of the subprocess control is returned to this $! procedure to allow things to be cleaned up neatly (hopefully). $! o Cleanup involves dismounting ZTA0 if necessary, $FORCEX'ing the process $! which is running the ZT2 image, telling the other side that we are $! all done, and then closing the network link. $! $! Network object #142 is a command procedure on the remote that performs $! the following tasks : $! $! o Opens a channel on SYS$NET to communicate with this procedure $! o Checks on the availability of the requested device, i.e., does it exist, $! and is it unallocated? Bail out if not. $! o MOUNTs the tape $! o Runs the server image ZTNS2 as a subprocess. ZTNS2 starts up a network $! object back on this side that fires up the ZT2 image. When all of this $! happens, ZTA0: magically comes on-line (hopefully)! $! o Now the procedure issues a READ on SYS$NET, waiting for a control string $! that indicates that the other side is done with the drive. It also can $! detect whether the other side has closed the network link abnormally. $! o Dismounts the tape, and closes the network link $! o Logs out, thus killing the subprocess running ZTNS2. --------------------------------------------------------------------- And this is RMT_OBJECT.COM, which sits on the "real-tape" side " $! RMT_OBJECT.COM $! $! This procedure is run as a network object to allow a remote DECNET node $! to use a tape drive located on this node. The following tasks are performed : $! $! o Opens a channel on SYS$NET to communicate with an inbound network $! object request. $! o Checks on the availability of the requested device, i.e., does it exist, $! and is it unallocated? Bail out if not. $! o MOUNTs the tape. $! o Runs the server image ZTNS2 as a subprocess. ZTNS2 starts up a network $! object on the other side that fires up the ZT2 image. When all of this $! happens, ZTA0: magically comes on-line on the other side (hopefully)! $! o Then the procedure issues a READ on SYS$NET, waiting for a control string $! that indicates that the other side is done with the drive. It also can $! detect whether the other side has closed the network link abnormally, $! in which case it cleans up neatly. $! o Dismounts the tape, and closes the network link $! o Logs out, thus killing the subprocess running ZTNS2. $! $! Written by : Bob Marshall $! 18 May 1993 $!************************************************************************ $! $ set noon $! $! Open a channel to SYS$NET $! $ open/read/write/err=oh_well netline sys$net $! $ define/nolog sys$output netline $ define/nolog sys$error netline $! $! Read two messsages from the remote procedure. The first should be the $! the name of the remote node, and the second should be the name of $! the tape drive to use. $! $ read/end=oops/err=oops netline remote_node $ read/end=oops/err=oops netline local_tape $! $ local_tape = local_tape - ":" + ":" ! Add a colon, if necessary $! $! Make sure the device exists! $! $ if .not. f$getdvi(local_tape,"EXISTS") $ then $ write sys$output "" $ write sys$output "%RMT-F-NOSUCHDEV, device ''local_tape' does not exist" $ write sys$output "" $ write netline "**ERROR**" $ goto oops $ endif $! $! Make sure it's not allocated to someone else $! $ if f$getdvi(local_tape,"ALL") $ then $ write sys$output "" $ write sys$output - "%RMT-F-ALLOCATED, device ''local_tape' is allocated to another process" $ write sys$output "" $ write netline "**ERROR**" $ goto oops $ endif $! $! OK, looks like we're cleared for take-off $! $ define/nolog zt_tape 'local_tape' ! Used by ZTNS2 $! $! MOUNT the tape; use /NOASSIST so that if the user forgot to physically $! prepare the drive, even after being warned, then he loses and has to $! start all over. $! $! Note : Remove the /nounload switch when done with testing $! $ mount/for/noassist/nounload/multi_volume zt_tape ! Requires VOLPRO priv $! $! If the MOUNT failed for any reason, bail out $! $ if .not. $status $ then $ write/err=oops netline "**ERROR**" $ goto oops $ endif $! $! Change the next line if a network object number other than 141 is desired. $! $ define/nolog zt_netobject "''remote_node'::""141=""" ! Used by ZTNS2 $! $! Run the ZTNS2 program as a subprocess. ZTNS2 will create a link to $! object #141 on the ZT-side, which runs a command procedure to run $! the ZT2 program. Once this happens, ZTA0: comes on-line on the ZT-side. $! By running ZTNS2 in a subprocess, we can have control return to this $! command procedure to communicate via SYS$NET. $! $ spawn/nowait/nolog/output=nla0: run ztns2 $! $ wait 00:00:05.00 ! Wait a bit $ write/err=link_gone netline "**CONTINUE**" ! Tell the other side we're ready $! $! Now just sit and wait for a message to come from the ZT-side indicating $! that they are done. If for some reason we never get a "**DONE**" message, $! then the READ statement below will return an EOF error, and we can just $! clean things up. $! $ loop: $! $ read/end=link_gone/err=done netline message $ if message .nes. "**DONE**" then goto loop $! $ done: $! $ write/err=link_gone netline "**CLOSE**" $! $ link_gone: $! $! REMINDER : Remove /NOUNLOAD after testing $! $ if f$getdvi(local_tape,"MNT") then dismount/nounload zt_tape $! $ oops: $! $ close netline $ deassign sys$output $ deassign sys$error $! $ oh_well: $! $ purge/keep=3 netserver.log $ logout/brief $ exit ----------------------------------------------------------------------- And some preliminary installation instructions : In the discussion below, the node with the actual mag tape device is referred to as the "real-tape" side; the remote node wishing to use the drive is referred to as the "ZT-side". Building the software (do this on the ZT-side) ---------------------------------------------- $ @BUILD Things to do on the ZT-side --------------------------- o $ COPY ZTDRIVER.EXE SYS$COMMON:[SYS$LDR] o In SYSTARTUP.COM, add these lines somewhere : $ SYSGEN CONNECT ZTA0/NOADAPTER $ INSTALL ADD dev:[dir]ZT2.EXE/OPEN/HEADER/PRIV=CMKRNL $ INSTALL ADD dev:[dir]ZT2_FORCEX.EXE/OPEN/HEADER/PRIV=WORLD $ DEFINE/SYSTEM RMT_REMOTE_NODE nodename ! Nodename with real-tape device $ DEFINE/SYSTEM RMT_REMOTE_TAPE device ! Default remote drive name o In NCP, define the ZT2 network object : $ RUN SYS$SYSTEM:NCP NCP> SET/DEFINE OBJECT ZT2 NUMBER 141 FILE dev:[dir]ZT2.COM - [USERNAME username PASSWORD password] (Note : The number 141 is arbitrary; to use a different number just edit RMT_OBJECT.COM and replace "141" with the desired number) o Define a global symbol in SYLOGIN.COM to run RMT.COM : $ RMT :== @dev:[dir]RMT.COM Things to do on the real-tape side ---------------------------------- o Copy RMT_OBJECT.COM and ZTNS2.EXE to an appropriate place o Add NCP object : $ RUN SYS$SYSTEM:NCP NCP> SET/DEFINE OBJECT RMT_OBJECT FILE NUMBER 142 - dev:[dir]RMT_OBJECT.COM - USERNAME username PASSWORD password Notes : - The number 142 is arbitrary. To use a different number just edit the file RMT.COM and specify a different number. - The username specified for the object must have VOLPRO privilege in order to make the MOUNT/FOREIGN/MULTI_VOLUME command in RMT_OBJECT.COM work. For example : $ SET DEFAULT SYS$COMMON:[SYSEXE] $ RUN SYS$SYSTEM:AUTHORIZE UAF> ADD username/UIC=[g,m]/PASSWORD=password/DEVICE=device- /DIRECT=[directory]/PRIV=VOLPRO/DEFPRIV=VOLPRO- /NOBATCH/NOLOCAL/NODIALUP/NOREMOTE/NETWORK UAF> EXIT (The username/password combination must match that specified in the NCP SET/DEFINE object command) Bob Marshall marshall@nebula.ssd.lmsc.lockheed.com