.MCALL .MODULE .MODULE BUPRS,VERSION=18,IDENT=NO ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .SBTTL BUPRES - Common RESTORE Code ; 01-Mar-89 RHH V5.5 Work .MCALL .LOOKUP, .ENTER, .PURGE, .READW, .WRITW .MCALL .CLOSE, .PRINT, .SPFUN, .HERR, .SERR .MCALL .RCTRLO, .FPROT, .SFDAT, .POKE, SOB DEBUG = 0 .MACRO ...... .ENDM .PSECT RESDAT,D .NLIST BEX VMSG: .ASCIZ / Files verified:/ RMSG: .ASCIZ / Files restored:/ OFMSG: .ASCII / of /<200> DECRT: .ASCII /DECRT11A / NOTRTV: .ASCII /?BUP-W-Output volume not initialized; Are you sure? /<200> TRUMSG: .ASCII /?BUP-W-Output volume will be truncated; Are you sure? /<200> NEEDSQ: .ASCIZ /?BUP-W-Output volume not resized. SQUEEZE before using./ CLOBMS: .ASCIZ /?BUP-U-Reboot/ .EVEN ; Data for UPDDIR DEVSIZ: .WORD 0 AVAIL: .WORD 0 AVAILP: .WORD 0 UNUSD: .WORD E.MPTY ; proto < UNUSED > entry .RAD50 / EMPTYFIL/ .WORD 0 .WORD 0 .WORD 0 RBUFAD: .WORD 0 ; SPFUN buffer pointer TEMP: .WORD 0 MSGAD1: .WORD VXCOP, SXCOP, SVXCOP ; SIGSTA message pointers .SBTTL Load overlay and go to RESTORE code ; Load this overlay and then go to appropriate backup overlay .PSECT RESCOD,I .LIST BEX XBACK:: JMP XBACKO ; Go to DISK RESTORE code TRES:: JMP TRESO ; Go to TAPE RESTORE code TFRES:: JMP TFRESO ; Go to TAPE RESTORE code .SBTTL CHKHMB - Check for special case of Homeblock on DM and DL ;+ ; Before writing a chunk of blocks to the output disk, check to see ; if it is a DM or DL device. If so, are we writing to the home block? ; If so, preserve the portion of the old home block that constitutes ; the disk's bad-block-replacement table. ; ; Throughout, R3 points to the buffer about to be written to disk ;- .ENABL LSB CHKHMB::TSTB VONLY ; COMPARE-ONLY operation? BMI 10$ ; If so, get out of here. TSTB BBRDEV ; Bad-block-replacement device? BNE 20$ ; branch if so 10$: RETURN ; Otherwise, return. ...... 20$: MOV R0,-(SP) ; Save registers MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV R3,RBUFAD ; buffer address for SPFUN CMPB DEV1,#DEV.DM ; is this an RK06 or RK07? BNE 30$ ; branch if not. ; The RK06 and RK07 (DM) devices return a status word in the first ; word of the buffer. Account for this by shifting things up one ; word. Save the 1st word of block 2 in TEMP, for restoration below. MOV R3,R1 ADD #2000,R1 ; point just beyond block 1 MOV R1,R0 MOV (R1)+,TEMP ; save the 1st word of block 2 MOV #1000,R2 ; move 512 words up by one word 22$: MOV -(R0),-(R1) ; because of the silly RK06/7 SOB R2,22$ TST (R3)+ ; allow for error word ; Write block 0 in its place to make buffer available... 30$: CLR R1 ; BLOCK 0 MOVB #376,R2 ; CODE = WRITE CALL DSPF ; ***** Do SPFUN to WRITE ***** BCC 50$ ; branch if no error. 40$: MOV #WR2,R1 ; <-F-Output error filespec> BR 70$ ...... ; Read disk's home block (block 1) into mem where block 0 was... 50$: INC R1 ; BLOCK 1 (was 0) INC R2 ; CODE = READ 377 (was WRITE=376) ; MOVB #377,R2 ; CODE = READ ; MOV #1,R1 ; BLOCK 1 CALL DSPF ; ***** Do SPFUN to READ ***** BCC 80$ ; block 1 into block 0's buffer 60$: MOV #RE2,R1 ; <-F-Input error dev:> 70$: JMP OUTERR ; Fatal error on output device ...... ; Check to see whether the output device has been initialized DECRT11A 80$: MOV R3,R0 ADD #DK.VTO,R0 ; Point to System Ident field MOV #DECRT,R1 ; and to "DECRT11A " in data area MOV #12.,R2 90$: CMPB (R0)+,(R1)+ ; Is it "DECRT11A "? BNE 140$ ; Branch if not. SOB R2,90$ ; The device was already RT-11 initialized. ; Copy BBRT from old home block (buffer 0) to block buffer 1. MOV R3,R0 ; It is DECRT11A. Copy BBRT. MOV R3,R1 ; Point src to block 0 buffer ADD #1000,R1 ; Point dest to home block buf MOV #65.,R2 ; This many words in BBR part of hmblk 100$: MOV (R0)+,(R1)+ ; Copy bad block replacement SOB R2,100$ ; table to new homeblock buffer ; Re-read block zero from disk (so that it can be re-written by the ; undisturbed controlling routine.) 110$: MOVB #377,R2 ; CODE = READ CLR R1 ; BLOCK 0 CALL DSPF ; ***** Do SPFUN to READ ***** BCS 60$ ; into block 0's buffer ; Operation complete. If RK06/7, move the block data down one word ; and restore the 1st word of block 2. CMPB DEV1,#DEV.DM BNE 120$ ; Allow for RK06/7's weird status MOV R3,R1 ; move blocks 0 & 1 back down 1 word TST -(R1) ; R1 points 1 word below R3 MOV #1000,R2 ; do 512. words 116$: MOV (R3)+,(R1)+ SOB R2,116$ MOV TEMP,@R1 ; restore 1st word of block 2 ; Return to caller after restoring registers. 120$: MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 130$: CLC ; Indicate no error RETURN ...... ; The volume is NOT recognized as RT-initialized. Prompt "Are you sure?" 140$: MOV #NOTRTV,R1 ; Not RT-11 initialized! CALL ANSWRP ; Are you sure? BMI 140$ ; Huh? BNE 150$ ; YES? Go ahead. JMP ABOOP ; NO. Abort ...... ; User answered YES - wants to clear the BBR 150$: CLR @R3 ; Effectively clear BBR, MOVB #376,R2 ; CODE = WRITE MOV #1,R1 ; BLOCK 1 CALL DSPF ; ***** WRITE BLOCK 1 ***** MOVB #374,R2 ; CODE = RE-READ BBR CALL DSPF ; so that it has new effect BR 110$ ; then proceed. ...... ; Perform SPFUN to BBR device and return to code above. DSPF: .SPFUN #EMTARE,OUTCHA,R2,RBUFAD,#256.,R1,#0 RETURN ...... .DSABL LSB .SBTTL SIGSTA - Signal start of restore ;+ ; The following code prints a message on the terminal signaling the start ; of a copy operation from a given volume. ;- .ENABL LSB SIGSTA::TSTB GIV.W ; /NOLOG? BMI 40$ ; If so, don't print anything. CALL PRVMSG ; Print restore message prefix 30$: .PRINT #STARTD ; "operation started on " MOV VOLNUM,R2 ; Get volume number MOV R1,-(SP) CALL DECIMA ; Print it MOV (SP)+,R1 .PRINT #CRLF ; End of line 40$: RETURN ...... PRVMSG: CLR R1 ; Default to 1st message TSTB VONLY ; Verify only? BMI 50$ TST (R1)+ ; Advance to next message pointers TSTB GIV.V ; Verifying while Restoring? BEQ 50$ ; Branch if not TST (R1)+ ; Advance to third message pointers 50$: MOV MSGAD1(R1),R0 ; point to 1st message .PRINT ; Signal start of RESTORE... RETURN ...... .DSABL LSB .SBTTL XFORMS - Transform /SAVESET command .ENABL LSB ;+ ; If command line is of the form OUT:=IN:[xxx]/X then change it now to ; be equivalent to OUT:=IN:BACKUP.BUP/S[,xxx]/X/I/F. ;- XFORMS:: MOVB GIV.R,R0 ; input SUBSET specified? BISB GIV.S,R0 ; or input SAVESET specified? BPL 40$ ; If not, force default saveset. TST NONAME ; input name supplied? BPL 70$ ; branch if so ; Insert a default saveset name 40$: MOV #INFIL+2,R0 ; point to input file spec BIT #,OPTACT ; /RESTORE/DEVICE or /REST/FILE? BEQ 60$ ; branch if not. ; Transform restore /DEVICE or /FILE command TST NONAME ; input name specified? BPL 80$ ; skip if so. MOV OUTDEV,(R0)+ ; let input = out devnam CLR (R0)+ MOV #^RBUP,(R0)+ BR 80$ ...... ; Transform file restore command 60$: MOV #DEFNAM,R1 ; point to default saveset name .REPT 3 MOV (R1)+,(R0)+ ; let input = default saveset name .ENDR MOV #<3*400+'S>,SSSPEC ; to inhibit File Not Found msg 70$: MOV #OPTACT,R0 ; point to ACTION-bit word BIT #X$OPT,@R0 ; simple /X specified? BEQ 80$ ; branch if not. BIS #XIF$OP,@R0 ; Set the /DEVICE/FILE option bit BIC #,@R0 ; Clear /DEVICE and file restore bits 80$: RETURN ...... .DSABL LSB .SBTTL CHKBBR - Check for BBR device ; Look at the output device, to see if it's an RL01/2 or a RK06/7. ; These devices have Bad-block replacement tables in the homeblock ; that must not be overwritten. Set a flag for later checking. .ENABL LSB CHKBBR::CLRB BBRDEV ; Assume not BBR device CMPB DEV1,#DEV.DL ; Is output dev RL01/RL02? BEQ 10$ CMPB DEV1,#DEV.DM ; Is output dev RK06/RK07? BNE 20$ 10$: INCB BBRDEV ; Set flag for DM or DL device 20$: RETURN ...... .DSABL LSB .SBTTL FILALL - Open output for FILE restore ;+ ; An entry into the output device is attempted to the size of the ; blocks to be restored. If there is no room, the operation is ; aborted and a message printed. The entry is made with the filename ; given or the input filename if no filename was given on the command ; line. ;- .ENABL LSB FILALL::.SERR TSTB VONLY ; Doing /VERIFY:ONLY? BPL 30$ ; If not, go ENTER .LOOKUP #EMTARE,OUTCHA,#OUTFIL ; Look for existing file MOV R0,-(SP) ; save file size ROR R1 ; save C-bit across .HERR .HERR ROL R1 MOV (SP)+,R0 ; restore file size BCS 10$ CMP R0,FILSIZ ; Must be same size BEQ 40$ BSZMSG: .CLOSE OUTCHA MOV #BSZ,R1 ; Size doesn't agree BR 90$ ...... 10$: MOV #LO1,R1 ; LOOKUP returned error BR 90$ ...... 30$: CMPB DEV1,#DEV.TT ; Output to TT? BNE 34$ TST NFTRAN ; First time? BNE 40$ ; skip .ENTER if not. 34$: .ENTER #EMTARE,OUTCHA,#OUTFIL,FILSIZ ;Ask for necessary space MOVB @#$ERRBY,R1 ROL R1 ; save C-bit and $ERRBY across .HERR .HERR ROR R1 BCS 60$ ; Branch if error 40$: MOV #OUTFIL,R0 ; Success - get filename MOV #LOGLIN,R1 CALL $FNASC ; Convert RAD50 to ASCII filename CLRB @R1 ; Null terminate the result 50$: RETURN ...... 60$: TSTB R1 ; Error code = 0? BEQ LO2OUT ; branch if Channel in use BPL 70$ ; Negative .ENTER codes... CMPB R1,#-6 ; Directory full? BEQ DFLOUT ; <-F-Directory full > BR WR1OUT ; <-F-Directory I/O Error > ...... ; Positive .ENTER codes... 70$: CMPB R1,#3 ; Protected file already exists? BEQ 80$ ; If Yes, branch. SPAOUT: MOV #SPA,R1 ; <-E-No room on output device> BR 90$ ...... 80$: MOV #FEP,R1 ; <-E-File already exists> 90$: .ERR #ERRARE,R1,LEVEL=ERROR,RETURN=YES,FILE=#OUTFIL SEC RETURN ...... DFLOUT: MOV #DFL,R1 ; <-F-Directory full > BR 120$ ...... WR1OUT: MOV #WR1,R1 ; <-F-Directory I/O error > 120$: .PURGE OUTCHA OUTERR: MOV OUTFIL,DEVSPC ; Force proper device in message JMP FATALD ...... LO2OUT: MOV #LO2,R1 ; <-F-Channel in use> JMP FATAL ...... .DSABL LSB .SBTTL DEVFIT - Open output for DEVICE restore ;+ ; This routine opens an output device for a /RESTORE/DEVICE operation. ; This size of the device is compared with the number of blocks to ; restore to see if there is enough room. ;- .ENABL LSB DEVFIT::.SERR MOV OUTDEV,DEVSPC ; Ensure OUTPUT device .LOOKUP #EMTARE,OUTCHA,#DEVSPC ; Open output device NFS ROL R1 ; save carry across .HERR ; .HERR ROR R1 ; get back LOOKUP status BCC 10$ ; Branch if no error TSTB @#$ERRBY ; Which class of error? BNE WR1OUT ; <-F-Directory I/O error> BR LO2OUT ; <-F-Channel in use> ...... 10$: CALL GSIZE1 ; Get size of device MOV R1,DEVSIZ ; save it CMP R1,TOTLLN ; Is there room on output? BLO 20$ ; Error if not. 15$: RETURN ...... 20$: TSTB VONLY ; /V:ONLY? BPL 30$ ; If not, JMP BSZMSG ; Print ...... 30$: MOV R1,TOTLLN ; Use device's size MOV #SPA,R1 ; <-W-Insufficient space on output> CALL WARNER MOV #TRUMSG,R1 ; <-I-...truncated; Are you sure?> 40$: CALL ANSWRP ; Are you sure? BMI 40$ ; Huh? BNE 15$ ; YES? Go ahead. JMP START2 ; NO. Abort ...... .DSABL LSB .SBTTL UPDDIR - Update final for /DEVICE restore ; Update the output device's directory to reflect the actual number ; of free blocks for the device. .ENABL LSB UPDDIR:: TSTB VONLY ; /VERIFY:ONLY? BMI 35$ ; If so, don't do this. MOV BUFADD,R4 ; Buffer address MOV R4,R3 ; make a working copy MOV #6,INBLK ; Start at beginning of directory MOV OUTFIL,DEVSPC ; for error messages ; Read directory segments until the last one is found. 10$: .READW #EMTARE,OUTCHA,R4,#512.,INBLK BCC 30$ MOV #RE1,R1 ; -F-Directory input error BR 110$ ...... ; Check the segment for RT-11 directory-ness. 30$: MOV R4,R1 ; Pass segment address CALL SEGVAL ; segment valid? BCC 40$ MOV #IND,R1 CALL WARNER ; <-F-Invalid directory > 35$: RETURN ...... 40$: MOV D.NEXT(R3),R0 ; Get next segment no. BEQ 50$ ; If zero, it's the last one. DEC R0 ; Otherwise, make it zero-based ASL R0 ; and get its block no. ADD #6,R0 MOV R0,INBLK BR 10$ ; and read next segment. ...... ; The last segment is now in the buffer. Get the starting data block ; number and search through the entries for the last block used. 50$: MOV D.STRT(R3),R2 ; Get starting block number MOV #E.ELEN,R1 ; Default directory entry size ADD D.EXTR(R3),R1 ; add any extra bytes per directory ADD #D.LENG,R3 ; Point to 1st entry CLR AVAIL ; Init the 1st avail block value ;.ASSUME E.STAT EQ 0 60$: BIT #E.EOS,@R3 ; End of Segment? BNE 90$ ; If so, branch because we're done. BIT #E.MPTY,@R3 ; ? BNE 70$ ; save its info if so. CLR AVAIL ; otherwise, assume perm file. BR 80$ ...... 70$: MOV R2,AVAIL ; save as potential 1st available blk MOV R3,R0 ADD #E.LENG,R0 ; save pointer to length MOV R0,AVAILP 80$: ADD E.LENG(R3),R2 ; account for file entry's length ADD R1,R3 ; Point to next entry BR 60$ ...... ; The END_OF_SEGMENT entry of the last segment is reached. ; Calculate actual unused space for final entry, deposit it ; and write the segment back to the output disk directory. 90$: TST AVAIL ; final entry ? (dont spoil R2) BEQ 130$ ; If not, make one or report. MOV AVAIL,R2 100$: MOV DEVSIZ,R0 ; Get actual device size SUB R2,R0 ; subtract 1st available block MOV R0,@AVAILP ; store as entry length .WRITW #EMTARE,OUTCHA,R4,#512.,INBLK BCC 120$ MOV #WR1,R1 ; -F-Directory output error 110$: JMP FATALD ...... 120$: RETURN ...... ; The final directory entry was not . Try to make an ; entry. 130$: MOV R3,R0 ; get current location in dir seg SUB R4,R0 ; make an offset ASR R0 ; compare half the distance CMP R0,R1 ; room for EOS and ? BGE 140$ .PRINT #NEEDSQ ; report warning if not. RETURN ...... ; Move the EOS over by one entry, and insert an one. ; Point to it for update code above. Remember that R2 still holds ; the next available block, and R1 holds the number of bytes per entry. 140$: MOV R3,R0 ; point to current EOS entry ADD #E.LENG,R0 ; point to future length value MOV R0,AVAILP ; save it for later. MOV R3,R0 ; point again to current EOS entry. ADD R1,R0 ; point to new EOS area ASR R1 ; no. of words per entry MOV #UNUSD,R5 ; point to prototype 150$: MOV @R3,(R0)+ ; copy the End-of-segment (EOS) MOV (R5)+,(R3)+ ; insert DEC R1 ; until an entry's worth is copied. BGT 150$ BR 100$ ; now, go update the entry. ...... .DSABL LSB .SBTTL RVERER - Report verify error ; Report a verification error during /RESTORE/VERIFY or /RESTORE/VERIFY:ONLY ; ; The block number is passed in R2 .ENABL LSB RVERER::.PRINT #VERMES ; Print verify message, CALL DECIMA ; Print block number, BIT #XI$OPT,OPTACT ; /DEVICE? BNE 10$ .PRINT #OFMSG ; print " of " .PRINT #LOGLIN ; filename BR 20$ 10$: .PRINT #CRLF 20$: INC VBAD ; add 1 to error counter RETURN ...... .DSABL LSB .SBTTL FINFIL - Finish output file ; Finished with individual file restore. Set it's date and protection ; attributes. Log the transfer on the console. .ENABL LSB FINFIL::TSTB VONLY ; Doing /VERIFY:ONLY? BMI 10$ ; Don't set date or protection if so. TST DSTOUT ; Output to non-random-access dev? BPL 10$ ; Don't set date or protection if so. MOV #,R1 ; point to file entry's date word .SFDAT #EMTARE,OUTCHA,#OUTFIL,@R1 ; set it. TST DIRENT ; Check high bit of entry status word BPL 10$ .FPROT #EMTARE,OUTCHA,#OUTFIL,#1 ; Protect restored file if so 10$: TSTB GIV.W ; /NOLOG? BMI 40$ ;;; TSTB WILDFG ; any wildcards specified? ;;; BEQ 40$ ; branch if not. TST NFTRAN ; any files transferred yet? BNE 30$ MOV #RMSG,R0 ; point to "Files restored" message TSTB VONLY ; /VERIFY:ONLY? BPL 20$ MOV #VMSG,R0 ; then point to "Files verified" 20$: .PRINT R0 ; print restored or verified msg 30$: .PRINT #LOGLIN ; display the file transferred 40$: INC NFTRAN ; count the file. RETURN ...... .DSABL LSB .SBTTL RESDON - RESTORE done. Print summary messages. ;+ ; Finish a FILE RESTORE operation by printing appropriate messages. ;- .ENABL LSB RESDON::.RCTRLO ; Wake up user BIT #XIF$OP,OPTACT ; Restoring files from saveset? BEQ 60$ ; Branch if not. TSTB GIV.P ; /EXCLUDE operation? BMI 60$ ; don't do this then. ; Loop for all input file specs, checking the IGTENT bit that indicates ; a match was found. For any zero values, display ; ; ?BUP-E-File Not Found MOV #3,R5 ; Spec number of 1st input spec MOVB NISPEC,R2 ; Number of non-/S input specs BEQ 60$ ; None? MOVB GIV.R,R0 ; was /R given? BISB GIV.S,R0 ; or was /S actually given? BMI 10$ ; Branch if yes CLRB SSSPEC+1 ; declare no saveset filespec BR 20$ 10$: INC R2 ; Account for /S or /R file 20$: MOV FNDBTS,R3 ; Bitmap of matches found MOV #,R4 ; FSPEC input area 30$: ADD #INSPSZ,R4 ; Next input spec CMPB SSSPEC+1,R5 ; Is this the /S file? BEQ 50$ ; No message for it then. 40$: ROR R3 ; Get the bit for input file BCS 50$ ; Branch if file was found MOV INPDEV,@R4 ; Set proper inp dev for msg .ERR #ERRARE,#LO1,LEVEL=ERROR,RETURN=YES,FILE=R4 50$: INC R5 ; Next spec number DEC R2 ; Count down no. of inputs BGT 30$ ; Branch if more to do. ; Now finish by printing "Restore operation complete" or "No files restored" 60$: TSTB GIV.W ; /NOLOG? BMI 80$ ; If so, return without message. BIT #,OPTACT ; /DEVICE or /FILE image operation? BNE 70$ ; Skip check for files transferred. TST NFTRAN ; anything transferred? BEQ 110$ ; then print No files restored 70$: CALL PRVMSG ; Print restore message prefix .PRINT #COMPMS ; print "is complete" 80$: TSTB CLOBSY ; is SY clobbered? BEQ 120$ ; usually not. .PRINT #CLOBMS ; But if it is, halt. 90$: INC NFTRAN ; loop a few thousand times BNE 90$ ; to allow message display... MOV #EMTARE,R2 .POKE R2,#0,#0 ; HALT instruction at loc 0 .POKE R2,#4,#0 ; Let Vector 4 point to 0 .POKE R2,#10,#0 ; Let Vector 10 point to 0 100$: HALT BR 100$ ...... ; This seemingly FATAL error is an -E-level message so that IND ; command files can distinguish between "-E-No files restored" ; and "-F-File not found" (end of tape) terminations. 110$: .ERR #ERRARE,#NOF,LEVEL=ERROR,RETURN=NO ; ?BUP-E-No files restored ;; MOV #NOF,R1 ; ?BUP-F-No files restored ;; JMP FATAL ...... ; Display a warning message (indicated by R1) WARNER: .ERR #ERRARE,R1,LEVEL=WARNING,RETURN=YES,FILE=#DEVSPC 120$: RETURN ...... .DSABL LSB .END