.MCALL .MODULE .MODULE BUPMT2,VERSION=26,IDENT=NO,GLOBAL=.BPMT2 ; 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 TAPE RESTORE and TAPE DIRECTORY Overlay .ENABL GBL,LC ; 23-Feb-89 RHH V5.5 work .SBTTL Conditionals DEBUG = 0 ; Include debugging messages VOLPRT = 0 ; Print VOLUME: xxxxxx on directory listings .SBTTL Local Macros .MACRO .COUT CALL DOPUTC .ENDM .MACRO .PFILE ARG MOV ARG,R0 CALL DOLINE .ENDM .MACRO ...... .ENDM .SBTTL External Macros .MCALL .PRINT, .SPFUN, .HERR, .SERR, .PURGE, .ENTER .MCALL .CLOSE, SOB, .READW, .WRITE, .WRITW, .WAIT .SBTTL Equates NewEra =: 560. ; BUP tape versions starting with RT V5.5 .SBTTL Local Data .NLIST BEX .PSECT MT2DAT,D .GLOBL ..ARPE ; Allowable records passed EOT on old tapes ARPCNT: .WORD 0 ; Allowable Records Past EOT Counter MT.BVN: .WORD 0 ; Magtape's BUP version, or zero for old. TEMP1: .WORD 0 ; non-stack temporary storage location TEMP2: .WORD 0 TAPSQN: .WORD 0 ; Tape's file sequence number TAPSES: .WORD 0 ; Tapes file section size (disk blocks) WCOUNT: .WORD 0 RBUFAD: .WORD 0 NBLOCK: .WORD 0 ; used to count equivalent 256-word NFSCAN: .WORD 0 ; no. of savesets scanned during DIR WBAD: .WORD 0 ; no. of bad writes SHOVOL: .WORD 0 ; vol num of last displayed "starting" message DSKINU: .BYTE 0 ; disk in use flag EOFFLG: .BYTE 0 XIFOPT: .BYTE 0 ; indicates /RESTORE/DEVICE/FILE LOPT: .BYTE 0 ; indicates /DIRECTORY LSOPT: .BYTE 0 ; indicates /DIRECTORY/SAVESET USE1ST: .BYTE 0 ; Use 1st saveset flag NSYMSG: .BYTE 0 ; "No .SYS action" message flag .EVEN ;-------- These four words must remain together --------------------- TAPSVN: .WORD 0 ; Tape's Volume Number TAPVER: .WORD 0 ; Tape's BUP Version Number TAPBLK: .WORD 0 ; Tape's Starting Output Block Number TAPDSZ: .WORD 0 ; Tape's "device size" value ;-------------------------------------------------------------------- HDRNAM: .BLKB 10. ; Temp storage of HDR1's name (without dot) SSNR50: .BLKW 4. ; RAD50 saveset-found name DATFLD: .BLKB 8. ; Temp storage of tape's date field .IF NE VOLPRT VLBLIN: .ASCII /Volume: / ; DIR's volume label line VLABEL: .BLKB 6. ; Tape's volume label .BYTE 15,12 ; CR, LF (skip line) .BYTE 0 ; Terminating NULL .ENDC ;VOLPRT .EVEN BLKMOD: .WORD 0 ; block number to read NXTBLK: .WORD 0 ; Next magtape image (256-word) block no. OFFBY: .WORD 0 ; (EXPECTED blk num) minus (GOT blk num) DBUBLK: .WORD 0 ; Disk BackUp Block SSTBLK: .WORD 0 ; Saveset block number (tape block counter) BP1: .WORD 0 ; Buffer pointers BP2: .WORD 0 NBS: .ASCIZ /?BUP-W-Not a BACKUP saveset /<200> WBNMSG: .ASCIZ /?BUP-E-Tape volume position error/ WBNM1: .ASCII /?BUP-W-Expected block /<200> WBNM2: .ASCII /; Tape volume begins with /<200> WBNM3: .ASCIZ /?BUP-W-Continuing RESTORE with mounted volume/ NOTRTV: .ASCII /?BUP-W-Output volume not initialized; Are you sure? /<200> MTDHED: .ASCIZ / Saveset Section Blocks Date/ ; name .BUP 1 65535/65535 13-Feb-87 .IF NE DEBUG NOEOD: .ASCIZ /(EOT Reached, but NOT END-OF-DATA)/ ZBUF: .ASCIZ /Attempt to write zero-words/ BBRDVM: .ASCIZ \Detected RL01/2 or RK06/7 device.\ CHKMSG: .ASCIZ /Checking name.../ MOVMSG: .ASCIZ /Moving name.../ WRNGMS: .ASCII /OUTBLK=/<200> FFOU: .ASCII /File found at /<200> FFOO: .ASCII /File size is /<200> JUSGOT: .ASCII /New volume starts at /<200> JUSGO2: .ASCII / of /<200> CALRD2: .ASCII /, NUMRD=/<200> CALRD3: .ASCII /, BLKMOD=/<200> TAPMSG: .ASCII /VOL1 says BUP Version /<200> .ENDC .EVEN .SBTTL TRES - Tape Restore and Directory ;+ ; These entries control restoration of files or device images from ; magtape to disk. There are also entries for obtaining magtape ; directories and directories of magtape savesets. ;- .PSECT MT2,I .ENABL LSB ; Entry for BACKUP/DIRECTORY ; and BACKUP/DIRECTORY/SAVESET TDIRO:: CALL CLROPT ; Reset option flags CLRB NEEDOP ; Assume TT output TSTB GIV.S ; /SAVESET specified? BMI 10$ ; Use RESTORE code INCB LOPT ; Set DIRECTORY option CLR NFTRAN ; Set number of savesets to zero CLR SAVINB ; Init total blocks CLR BLKVER ; and 2nd word of total blocks BR SETUP1 ; Continue... ...... 10$: INCB LSOPT ; Declare /DIRECTORY/SAVESET option BR SETUP1 ...... ; Entry for BACKUP/RESTORE ; BACKUP/RESTORE/FILE ; and BACKUP/RESTORE/DEVICE TRESO:: CALL CLROPT ; Reset option flags BR SETUP1 ; Continue ...... ; Entry for BACKUP/RESTORE/DEVICE/FILES TFRESO::CALL CLROPT ; Reset option flags INCB XIFOPT ; Set RESTORE/FILES option ; Common for all functions... SETUP1: MOV INCHAN,TAPCHA ; Let tape I/O be on Channel 0 MOV OUTCHA,DSKCHA ; and disk I/O be on Channel 1 MOV #1,VOLNUM ; First volume CALL SETRES ; Move device name to message area MOV INPDEV,SSNR50 ; Get device part of saveset name ; Fetch tape handler... MOV INFIL,DEVSPC ; Setup for fetch MOV NHDRAD,R1 ; Get fetch address CALL FETHAN ; Fetch tape handler MOV R0,NHDRAD ; Save next avail address ; Prompt for mount of first tape if not a /L function and /Y not specified TSTB GIV.L ; Directory? BMI RDYTAP ; If so, skip mount message/prompt RPROM: TSTB GIV.Y ; NOQUERY? BMI RDYTAP ; Yes. Skip message/prompt CALL MXPRMT ; Do RESTORE prompt/answer BNE RDYTAP ; YES. Go ahead. RETURN ; Quit now. ...... ; Open the tape channel RDYTAP: MOV #DEVSPC,R1 ; R1 -> device for NFS LOOKUP MOV #TAPCHA,R2 ; R2 -> channel CALL TLOOK ; Open tape channel ; If doing a listing, fetch list output handler and initialize printout code. TSTB GIV.L ; /L or /L/S option? BPL 20$ ; branch if not. CALL RDYLST ; init the printer support stuff BR 30$ ; then continue below. ; Doing a RESTORE (not a directory) - Fetch the output disk handler 20$: MOV OUTFIL,DEVSPC ; Prepare for fetch of disk handler MOV NHDRAD,R1 CALL FETHAN ; Allocate buffers, initialize variables 30$: MOV R0,BUFADD ; Save next available address CALL XMBUFR ; If XM, set up high-mem buffers CALL BUFERS ; Set up buffers CLR OUTBLK ; Set destination block number to zero CLR NXTBLK ; Initialize backup image block no. ; For /RESTORE, /RESTORE/FILE/DEVICE , or /DIRECTORY/SAVESET, open a ; temporary file on WF: or SY:. (Fetch was done in DISPCH in BUPCMD). ; These commands all allow wildcard specifications and an optional ; /SAVESET specification. MOV OPTACT,R0 ; Get option word BIC #^C,R0 ; keep only RESTORE[/DEV/FILE] BISB LSOPT,R0 ; and /DIRECTORY/SAVESET TST R0 ; (the whole word) BEQ 50$ ; Branch if none of the above. CALL OPNTMP ; Open a workfile... ; Determine which input saveset to use. If /SAVESET is not specified, ; use the default (first) saveset. TSTB GIV.S ; /SAVESET specified? BMI 50$ ; if so, position tape first. INCB USE1ST ; don't position tape; use 1st saveset ; Position the tape, read ANSI labels, check saveset names, etc. If doing ; a tape directory, CHKRES will scan the entire tape, and when it returns, ; we're done. If NOT doing a tape directory, the selected saveset is now ; in position for RESTORE or /DIRECTORY/SAVESET. 50$: CALL CHKRES ; Check/Scan/position tape BCC 60$ ; Branch if specified saveset found TSTB GIV.L ; EOT; doing a directory? BMI DONE ; If so, it's finished. CALL TPROM2 ; If not, insist on new volume. 60$: MOV #-1,SSTBLK ; First read will make it zero CALL CHKTOT ; more tape verification BCS DONE ; Not right tape volume? ; Figure out what we're doing, and then go do it. TSTB GIV.B ; Non-BUP tape allowed? BPL 70$ ; Branch if not. MOV #NewEra,MT.BVN ; Assume it's ANSI and an RT image 70$: MOVB XIFOPT,R0 ; Doing /RESTORE/DEVICE/FILE? BEQ 80$ ; branch if not. TSTB GIV.S ; /SAVESET specified? BMI 80$ ; branch if so. MOVB NISPEC,R0 ; get number of input specs SWAB R0 ; move to high byte, ADD #<3*400+'S>,R0 ; invent a /S entry in FSPEC MOV R0,SSSPEC ; Fake our way out of error msg 80$: BISB LSOPT,R0 ; Doing /L/S or /X/I/F? BNE 100$ ; branch if so. ; Neither /L/S nor /X/I/F was specified. That leaves /X, /X/I or /X/F. ; If /X/I or /X/F was specified, use the older simple, restore mode, ; where wildcards and multiple input specs are invalid. BIT #,OPTACT ; RESTORE/DEVICE or /RESTORE/FILE? BEQ 90$ ; If not, must be just /RESTORE CALLR TRESFI ; do /DEVICE or /FILE (non-saveset) ...... 90$: CALL XFORMS ; ~transform~ the command, INCB XIFOPT ; and do it /X/I/F-style. ; Set up for a saveset restore or directory operation... ; Allocate buffers and workspace for IGTDIR, for either /DIRECTORY/SAVESET ; or /RESTORE/DEVICE/FILE 100$: TSTB GIV.P ; /EXCLUDE in effect? BPL 105$ INC IG.DEV+4 ; set IGTDIR's RETURN_ALL flag 105$: MOV BUFADD,R0 ; Get allotted buffer address MOV R0,WKAREA ; use it for IGTDIR/IGTENT work area MOV R0,WKARED ADD #,R0 ; size in bytes MOV R0,IGDBUF ; directory buffer address ADD #2000,R0 ; and past that, MOV R0,BUFADD ; is the magtape buffer. ADD #,R0 ; how does the end compare with TST -(R0) ; (back off) CMP R0,TOPADD ; the REAL end? BLOS 110$ MOV #MEM,R1 ; <-F-insufficient memory> JMP FATAL ...... 110$: MOV #TMPCHA,IGDCHN ; Assign IGT* WF's channel CALL MAKTMP ; Otherwise, make temporary file. TSTB LSOPT ; Doing /DIRECTORY/SAVESET? BEQ FNDFIL ; Must be doing /RESTORE/DEVICE/FILE ; Get ready to display one saveset's directory. Get the saveset's ; name and birthdate, and store these where they are accessable to the ; BUPDIR overlay. MOV #SSNR50+2,R0 ; Point to saveset name RAD50 MOV #INFIL+2,R1 ; and to primary input spec area MOV (R0)+,(R1)+ ; move saveset name, MOV (R0)+,(R1)+ MOV (R0)+,(R1)+ ; move extension CALL GETDAT ; Decode tape saveset's date MOV DDATE,R0 ; Get saveset date in R0, JMP DOLSR ; Jump to /L/S code in BUP(DIR,DDI) ...... DONE: RETURN ...... .DSABL LSB ; Do /RESTORE/DEVICE/FILE ( = /RESTORE by itself) .ENABL LSB ; Call IGTDIR to initialize a wildcard directory search through the workfile. FNDFIL: MOV #IGTDIR,R0 ; Point to IGTDIR, MOV #IGDBLK,R5 ; and its arg block. CALL CALL$F ; Call IGTDIR to start search. TST R0 ; return code says what? BMI WFERR ; fatal exit on errors. CLR NFTRAN ; Init no. of files transferred. CLR NFSCAN ; Init no. of savesets scanned CLR BLKCOP ; Indicate new file needed. ; Loop through tape volumes as necessary. 20$: CALL FRCOPY ; Copy file blocks to files BCC DONE ; Done if carry clear INCB USE1ST ; use 1st file on subsequent volumes CALL NEWVOL ; Prompt for and ready new volume BR 20$ ; Go resume with it. ...... .DSABL LSB .SBTTL RDYLST - Prepare list output ;+ ; If the Directory List is going to a device other than TT, then ; fetch the handler, designate a buffer, and open the file. ; ; Return with the next available address for fetch or buffer in R0. ;- .ENABL LSB RDYLST: MOV NHDRAD,R0 ; Next available hdlr location CMPB DEV1,#DEV.TT ; Output to TT? BEQ 10$ ; If so, proceed. MOV OUTFIL,DEVSPC ; Put device where FETHAN expects MOV NHDRAD,R1 ; Get next available address, CALL FETHAN ; fetch the handler, MOV R0,DOBUF ; Set up buffer pointer ADD #1000,R0 ; Make room for 1-blk LIST buffer INCB NEEDOP ; Declare NEED LIST FILE OPEN 10$: RETURN ...... .DSABL LSB .SBTTL OPNTMP - Open temporary workfile ; Open temporary work file on WF or SY disk .ENABL LSB OPNTMP: .SERR .ENTER #EMTARE,TMPCHA,#TMPFIL,#<6+<31.*2>> ; Open temporary file BCS 20$ ; Branch on error .HERR RETURN ...... ; Error returns 10$: .PURGE TMPCHA ; Undo temp file 20$: .HERR WFERR: MOV #WR1,R1 ; I/O error on temp file MOV #TMPFIL,R3 JMP FATAL3 ...... ; Write blocks to the temporary file ; where R2 = buffer address, ; R3 = block number ; and R1 is used to hold a word count (not preserved) WRTTMP: MOV #TWNCT,R1 ; usually 8 blocks of words CMP R3,#63. ; writing last part of directory? BLO 30$ ASR R1 ; if so, do only 4 blocks 30$: .WRITW #EMTARE,TMPCHA,R2,R1,R3 BCS 10$ RETURN ...... ; Write 1st 68. blocks of saveset to the temporary workfile. ; This corresponds to the first 8 and 1/2 tape blocks. MAKTMP: MOV #9.,R4 ; loop for maximum 9 tape blocks CLR R3 ; start at block-0 MOV BUFADD,R2 ; R2 points to buffer 40$: CALL MTREDW ; read tape block TST R3 ; 1st time through loop? BNE 60$ ; branch if not. ; Check for valid RT-11 directory MOV R2,R1 ; Let R0 -> Seg buffer ADD #<6*1000>,R1 CALL SEGVAL ; Valid directory format? BCC 50$ ; Branch if so. MOV #SSNR50,R3 ; Saveset name in RAD50 pointer MOV #IND,R1 JMP FATAL3 ...... 50$: MOV <6*1000>(R2),R0 ; get no of segments in directory ASL R0 ; it's this many disk blocks ADD #6,R0 ; this many blocks of image needed. MOV R0,BLKMOD ; save it for checking below. INCB TMPOPN ; Mark TMP file open 60$: CALL WRTTMP ; write data to temp file ADD #TBLOCK,R3 ; bump no. of blocks represented. CMP R3,BLKMOD ; have we done enough? BHIS 70$ DEC R4 ; count down... BNE 40$ 70$: RETURN ...... .DSABL LSB .SBTTL TRESFI - RESTORE DEVICE or (OLD BUP) FILE ;+ ; /RESTORE/DEVICE or /RESTORE/FILE (Not /RESTORE/DEVICE/FILE) ; ; TRESFI copies the contents of a multi-volume magtape saveset directly ; to an RT-11 file or device. It assumes that the first tape is correctly ; positioned on the saveset, and that the saveset size has already been ; determined from the HDR labels. ;- .ENABL LSB TRESFI:: BITB #XI$OPT,OPTACT ; Device restore? BNE 30$ ; Yes, branch TSTB GIV.B ; /FOREIGN? BPL 10$ ; If so, MOV #-1,TOTLLN ; use largest space on disk 10$: MOV TOTLLN,FILSIZ ; This many blocks CALL FILALL ; Open output FILE. BCC 40$ ; Go copy if no errors 20$: RETURN ...... 30$: CALL DEVFIT ; Open output DEVICE, NFS CALL CHKBBR ; Test for BBR device 40$: MOV TOTLLN,BLKCOP ; Blocks to copy ; Loop for each input volume... 50$: CALL SIGSTA ; Signal start CALL RCOPY ; Copy blocks to disk output, BCC 20$ ; return when all done. TSTB GIV.B ; EOF on /FOREIGN? Treat as end-of- BPL 60$ ; skip if /FOREIGN not specified JMP TFRESD ; Go finish /FOREIGN restore. ...... 60$: INCB USE1ST ; use 1st file on subsequent volumes CALL NEWVOL ; mount new volume BR 50$ ; continue. ...... .DSABL LSB .SBTTL NEWVOL - New Input Volume ; This subroutine prompts the user for the next volume. ; It then checks, scans, and positions the volume to an appropriate ; backup saveset or end of tape. .ENABL LSB NEWVOL: INC VOLNUM ; Next volume TPROM2: CALL REWIND ; Rewind volume just finished with, CALL MXPRMT ; Do RESTORE prompt/answer BNE 10$ ; Yes, branch CALL QABOR ; No, do you really! BR TPROM2 ; Repeat ...... 10$: .WAIT TAPCHA ; Wait for rewind to complete CALL CHKRES ; Check if volume belongs BCS TPROM2 ; If not, repeat mount prompt CALL CHKTOT ; Check totals BCS TPROM2 ; If not equal, repeat prompt RETURN ...... ; Clear all module option flags CLROPT: CLRB LOPT ; Clear all options CLRB LSOPT CLRB XIFOPT CLRB USE1ST RETURN ...... .DSABL LSB .SBTTL BUFERS - Get buffer addresses, prepare for VERIFY ;+ ; The buffer allocation is done here for the verify area. ;- .ENABL LSB BUFERS: CALL CALBUF ; Calculate buffer addresses CLR R0 ; Assume not verifying ASR R5 ; R5 = number of spfuns MOV R5,NUMSPF ; Save no. of spfuns CALL GTSFAD ; Calculate buffer addr RETURN ...... .DSABL LSB .SBTTL CHKRES - Check for input tape validity ;+ ; The tape loaded is checked for the following things: (in that order) ; ; 1. Is it a backup volume ; 2. Is the file stored matches that of the command line (if one ; is specified) ; 3. Is the volume number match ; 4. If the tape was made by BUP V5.41 or later, the destination ; disk block number is checked ; ; In addition, if the command line did not specify a filename on a ; file operation then the filename found on the tape saveset section ; is used to check the subsequent tapes mounted. ; ; CALL CHKRES ;- .ENABL LSB CHKRES: TSTB GIV.M ; /NOREWIND specified? BMI 20$ ; If so, skip the rewind. 10$: CALL REWCHK ; Rewind magtape BCC 20$ JMP 370$ ; User changes mind 20$: MOV ..ARPE,ARPCNT ; Init ARPCNT (Allowable Records ; Passed EOT CouNTer) ; Loop here, reading labels, looking for tape marks. 30$: CLR TEMP1 ; Reset tape-mark indicator. 40$: CALL REDLBL ; Read label record BCC 80$ ; Branch if no error BIT #TS.EOF,R0 ; tapemark? BEQ 60$ TST TEMP1 ; was there a previous one? BEQ 50$ CALL BACKSP ; If so, back over both CALL BACKSP 45$: JMP BR3 ; say File Not Found 50$: INC TEMP1 ; account for tapemark BR 40$ 60$: BIT #TS.LNG,R0 ; LONG block? BEQ 70$ ; Branch if not. CALL FSPFIL ; Move ahead to tapemark BR 50$ 70$: BIT #TS.SHT,R0 ; SHORT block? BNE 80$ ; That's OK. Branch if so. BIT #TS.EOT,R0 ; EOT? BNE 80$ ; Ignore it. JMP BR1 ; some other error 80$: CMP @R1,#"VO ; VOL label? BNE 150$ ; No, branch ; VOL1 record read CALL V1INFO ; Save crucial VOL1 info... .IF NE DEBUG call lprint ; Print the VOL1 .ENDC ADD #DK.TAG,R1 ; R1 -> BUP I.D. CMP @R1,#"BU ; BUP tag indicates OLD BUP tape? BNE 30$ ; No. Go on to get HDR1 ; Or fall through to process OLD ; BUP tape's VOL1 record. ; Process Old BUP tape VOL1 record... ADD #3,R1 ; R1 -> filename in VOL1 record JSR R5,STRNCP ; Save the saveset name .WORD HDRNAM ; Destination .WORD LBLBUF+255 ;+DK.TAG+3 .WORD 9. CALL CVSSR5 ; Convert saveset name to RAD50 TSTB LOPT ; Doing directory? BNE 130$ ; branch down, save name, get HDR1 BIT #XF$OPT,OPTACT ; /X/F? BEQ 100$ ; If not, Don't do name check TST NONAME ; Input filename specified? BPL 110$ ; Check it if so. 100$: JMP 330$ ; Skip over saveset name match req. 110$: MOV #INNAM,R0 ; Get filename MOV #,R1 ; point to old BUP name in VOL1 MOV #9.,R3 ; Length of filename CALL STRNCM ; Compare strings BCC 45$ ; Error if no match JMP 380$ ; Match. ; OLD BUP TAPE DIRECTORY option only: 130$: CALL REDLBL ; Read old tape's HDR1 BCC 140$ JMP BR1 140$: CALL DCODAT ; Extract date string CALL DIRHDR ; print header, CALL PRNENT ; Print directory entry. 145$: JMP 360$ ; Finish. ; Not a VOL1 record. Check for EOxn record 150$: CMP @R1,#"EO BNE 190$ ; -------------------------- EOxx Processing ------------------------ .IF NE DEBUG call lprint ; Print the EOn .ENDC CMP 4(R1),#20040 ; double blank indicates old BNE 160$ JMP BR3 ; Old BUP tape - file not found. 160$: TSTB LOPT ; doing /DIRECTORY? BEQ 180$ ; Branch if not TST (R1)+ ; point to EO(Fn or Vn) CMP @R1,#"F2 ; EOF2 or EOV2? BEQ 170$ CMP @R1,#"V2 BNE 180$ ; Some other kind of EOxx label 170$: CALL GSTART ; Get new starting block number MOV R0,R1 SUB NBLOCK,R1 ; Get dif = end - start MOV R1,TAPSES ; Section Size CALL PRNENT ; Print list entry MOV PONLY,R0 ; Print only n savesets specified? BEQ 180$ ; No. Do them all if zero. CMP NFSCAN,R0 ; Yes. How we doin? BHIS 145$ ; Time to stop? 180$: JMP 30$ ; Go read next label record. ; Label is NOT a VOL1 or EOxn. Try HDRn record 190$: CMP @R1,#"HD ; Non-VOL1 record read BNE 180$ ; Not HDR either..get next record .IF NE DEBUG call lprint ; print the HDRx .ENDC CMP 2(R1),#"R1 ; HDR1? BNE 320$ ; ------------------------ HDR1 processing ------------------------- CALL DCODAT ; Decode date ; Expand new BUP packed saveset name in HDR1 to that required by RAD50 - ; i.e. remove dot, pad with blanks. 200$: .IF NE DEBUG .print #MOVMSG .ENDC MOV #HDRNAM,R0 ; Point to special name loc ADD #4,R1 ; Point to file ID in HDR1 MOV #6,R3 210$: CMPB @R1,#'. ; dot? BEQ 220$ MOVB (R1)+,(R0)+ ; move character DEC R3 BGT 210$ 220$: INC R1 ; point passed dot... 230$: CMP R0,#HDRNAM+6 BHIS 240$ MOVB #40,(R0)+ ; insert spaces BR 230$ ; until full 240$: MOV #HDRNAM+6,R0 ; and set destination ptr MOVB (R1)+,(R0)+ ; Move extension chars MOVB (R1)+,(R0)+ MOVB (R1)+,(R0)+ CALL CVSSR5 ; Convert saveset name to RAD50 MOV #LBLBUF,R1 ; Check for valid BUP tape CMPB 67.(R1),#'B ; DECRT11BUPxxx? BEQ 260$ TSTB GIV.B ; Non-BUP tape? BMI 260$ ; Ok. Give it a try. ; HDR1 indicates section is NOT a BUP section. ; Print a message and reject it. 250$: .PRINT #NBS ; Not a BUP saveset CLRB LBLBUF+14. ; plant NULL at end of name, .PRINT #LBLBUF+4 ; and print name as part of message. TSTB GIV.S ; Doing /DIRECT/SAVESET? BPL 270$ ; If not, continue on. CALL BACKSP ; Otherwise, back to HDR1 CALL BACKSP ; and tapemark or VOL1 SEC ; indicate DONE RETURN ; New BUP tape HDR1 - check saveset name 260$: .IF NE DEBUG .print #CHKMSG .ENDC MOV #HDRNAM,R1 ; Point to local HDR name buffer TSTB LOPT ; Doing directory? BNE 290$ ; If so, try HDR2 TST NONAME ; Input name supplied? BMI 290$ ; branch if not. TSTB USE1ST ; Override name comparison? BNE 290$ ; Branch if YES MOV #INNAM,R0 ; else match with this. MOV #9.,R3 ; require 9-char match CALL STRNCM ; Compare HDR1 name BCS 290$ ; a match! ; Advance tape to next saveset file 270$: CALL FSPFIL ; no match - find next file. CALL FSPFIL 280$: JMP 30$ ; go read label record ; Use the saveset file we've just found. 290$: TSTB GIV.B ; NON-BUP tape ok? BMI 292$ ; Don't check if so. MOV #LBLBUF+70.,R2 ; Point to implementation ID field MOV #3,R3 ; Expect 3 chars, CALL ASCBIN ; Decode BUP version number MOV R0,MT.BVN CMP R0,#544. ; Version 544 or above? BLT 250$ ; no - branch 292$: MOV #LBLBUF+27.,R2 ; Point to HDR1's file section no. MOV #4,R3 ; decode 4 chars CALL ASCBIN ; Convert them to binary MOV R0,TAPSVN ; Use this instead of volume no. MOV #LBLBUF+31.,R2 ; Point to HDR1's file sequence no. MOV #4,R3 ; decode 4 chars CALL ASCBIN ; Convert them to binary MOV R0,TAPSQN ; Use this for detecting ZEROED file TSTB LOPT ; doing directory? BEQ 300$ ; branch if not. TST NFSCAN ; No savesets listed yet? BNE 300$ CALL DIRHDR ; Print directory header. 300$: TST TAPSQN ; Is this the ZEROED.ZZZ entry? BNE 280$ ; If not, go read more labels BR 360$ ; Yes. quit. No files. ; ------------------------ HDR2 processing ------------------------- 320$: CMP 2(R1),#"R2 ; HDR2? BNE 280$ CLR R0 ; Assume Non-BUP... MOV #177777,TAPDSZ ; and maximum size possible TSTB GIV.B ; Non-BUP section ok? BMI 323$ ; skip this stuff MOV R1,R2 ; Point to file size ADD #19.,R2 MOV #5,R3 ; number of digits in value CALL ASCBIN MOV R0,TAPDSZ ; Get saveset size CALL GSTART ; Get starting block number 323$: MOV R0,NBLOCK ; Save it. MOV R0,TAPBLK .IF NE DEBUG .PRINT #JUSGOT MOV R2,-(SP) MOV R4,-(SP) MOV TAPBLK,R2 CALL DECIMA .PRINT #JUSGO2 MOV TAPDSZ,R2 CALL DECIMA .PRINT #CRLF MOV (SP)+,R4 MOV (SP)+,R2 .ENDC ; HDR2 is processed. Now figure out what to do. TSTB LOPT ; Doing directory? BEQ 330$ ; Branch if not. TSTB GIV.S ; YES. /SAVESET specified? BPL 270$ ; If NOT, continue down tape. BR 360$ ; quit now. ; (Note: OLD BUP tape HDR1 processing jumps here for RESTORE operations) 330$: BITB #XI$OPT,OPTACT ; /DEVICE operation? BNE 380$ ; Yes; skip next ; Restoring a FILE; ; If no input filespec was supplied, get the HDR1's label. TST NONAME ; Input filename specified? BPL 340$ ; Skip if so. JSR R5,STRNCP ; Yes. Copy SAVESET NAME to INNAM .WORD INNAM ; (previously copied from HDR1) .WORD HDRNAM .WORD 9. BIC #100000,NONAME ; Clear NONAME flag for next 340$: TSTB NONAME ; Output filename given? BPL 380$ ; Yes, branch ; Restoring a file, and no output file was given. ; Check for /RESTORE/DEVICE/FILE dev:savset/SAVESET,filnam.ext out: BIT #XF$OPT,OPTACT ; /X/F specified with no /I? BNE 350$ ; Ignore /S, force INNAM to OUTNAM TSTB GIV.S ; /S specified or implied? BMI 380$ ; branch if so 350$: JSR R5,STRNCP ; Copy INNAM to OUTNAM .WORD OUTNAM ; (dst) .WORD INNAM ; (src) .WORD 9. MOV #OUTFIL+2,R3 ; Convert output name to RAD50 MOV #OUTNAM,R1 CALL CNVRT3 BR 380$ ; Go do the copy. ; Finish tape directory 360$: CALL ENDMES ; Do final directory stuff. 370$: SEC ; Indicate error (or DIR done) RETURN ...... ; Handle various error conditions BR1: MOV #RE1,R1 BR ERRRYI ; <-E-Directory input error> ...... BR2: MOV #BAK,R1 ; <-E-Not a BACKUP volume> BR ERRRY ...... BR3: TSTB LOPT ; Doing directory? BNE 360$ ; if so, no error. MOV #LO1,R1 ; <-E-File not found > ERRRYI: .ERR #ERRARE,R1,LEVEL=ERROR,RETURN=YES,FILE=#INFIL BR 370$ ...... BR4: TSTB LOPT ; Doing directory? BNE 360$ MOV #VOL,R1 ; <-E-Wrong volume number> ERRRY: .ERR #ERRARE,R1,LEVEL=ERROR,RETURN=YES BR 370$ ...... 380$: TSTB GIV.B ; Non-BUP saveset ok? BMI 385$ ; skip the checks. CMP TAPSVN,VOLNUM ; Volume number match? BNE BR4 ; No, branch MOV #1,TEMP1 ; Assume skipping HDR1 record TST TAPVER ; Pre-V5.41 BUP tape? BEQ 470$ ; branch if old format. 385$: MOV TAPBLK,R0 ; get the saveset's 1st block number, TSTB XIFOPT ; Doing FILE restore from DEVICE? BEQ 390$ ; If not, branch. MOV NXTBLK,DBUBLK ; Disk backup block SUB NXTBLK,R0 ; Subtract the one we were on, BR 400$ ...... 390$: MOV OUTBLK,DBUBLK ; Store as Disk BackUp Block SUB OUTBLK,R0 400$: MOV R0,OFFBY ; Store difference. BEQ 460$ ; branch if so. .PRINT #WBNMSG ;<-E-Tape volume position error> MOV R2,-(SP) MOV R4,-(SP) .PRINT #WBNM1 ; display "EXPECTED/GOT" message MOV DBUBLK,R2 CALL DECIMA .PRINT #WBNM2 MOV TAPBLK,R2 CALL DECIMA .PRINT #CRLF MOV (SP)+,R4 MOV (SP)+,R2 ; The block number listed in the VOL1 record does not agree with ; our count in OUTBLK. Check to see whether the difference between ; these two numbers is reasonably small (<= 16.) If so, inform ; the user that the RESTORE will resume using the block number ; stored on the tape, which is most likely to be correct. MOV OFFBY,R0 BGE 410$ ; if difference was negative, NEG R0 ; make it positive. 410$: CMP R0,#16. ; Is it reasonable to recover? BHI 370$ ; No. off by too many blocks. MOV OFFBY,R0 TSTB XIFOPT ; FILE restore from DEVICE? BEQ 430$ ; If not, go handle regular restore SUB R0,BLKCOP ; Filecopy in progress: ADD R0,OUTBLK ; Fix these variables 420$: MOV TAPBLK,NXTBLK BR 440$ ...... 430$: SUB OUTBLK,R0 ; subtract the one we were on, SUB R0,BLKCOP ; adjust number of blocks to copy MOV TAPBLK,OUTBLK ; Fix OUTBLK 440$: .PRINT #WBNM3 ; Print RESUMING message ; New BUP tapes contain a tape mark and a HDR2 record after the HDR1 ; record, so set the record skip value to 3. The SPFUN will ; forward-space the tape accordingly. 460$: MOV #-1,TEMP1 ; increase skip range to beyond TM 470$: .SPFUN #EMTARE,TAPCHA,#SF.MFS,#0,TEMP1,#LKBLK ; Space FWD over HDR1 CLC ;Indicate no error RETURN ...... .DSABL LSB .SBTTL V1INFO - Get VOL1 information from tape label ; Get old-fashioned VOL1 info, even from newer BUP tapes. V1INFO: MOV R1,-(SP) MOV #LBLBUF+266,R1 MOV (R1)+,TAPSVN ; Get tape's volume number, MOV (R1)+,TAPVER ; BUP version number, MOV (R1)+,TAPBLK ; starting block number, MOV @R1,TAPDSZ ; and device size. MOV (R1)+,TAPSES ; File section size .IF NE VOLPRT JSR R5,STRNCP ; get volume label .WORD VLABEL .WORD LBLBUF+4 .WORD 6. .ENDC MOV #LBLBUF+34.,R2 ; Point to implementation ID field MOV #3,R3 ; Expect 3 chars, CALL ASCBIN ; Decode BUP version number MOV R0,MT.BVN MOV R0,TAPVER .IF NE DEBUG .PRINT #TAPMSG MOV TAPVER,R2 CALL DECIMA .PRINT #CRLF .ENDC MOV (SP)+,R1 RETURN ...... GSTART: MOV #LBLBUF+27.,R2 ; Assuming HDR2, get start blk MOV #5,R3 CALL ASCBIN ; Convert it RETURN ...... REDLBL: MOV #LBLBUF,R1 ; Read a tape label CALL READMT MOV #LBLBUF,R1 RETURN ...... .IF NE DEBUG lprint: clrb 80.(r1) .print r1 ; Print the label buffer return .ENDC ; Convert the HDR1 label to a RAD50 filespec for inclusion in error ; messages, etc. CVSSR5: MOV #,R3 ; Destination RAD50 address MOV #HDRNAM,R1 ; ASCII source address CALL CNVRT3 RETURN ...... ; Decode date field - store string away for later DCODAT: JSR R5,STRNCP ; Make copy of date field .WORD DATFLD ; store here .WORD LBLBUF+40. .WORD 8. RETURN ...... .SBTTL CHKTOT - Check if right restore set ;+ ; This routine checks that the total blocks backup to tape match, the ; total that the subsequent tapes have stored. It provides an extra ; check to certify that a volume belongs to a given set of backup volumes. ;- .ENABL LSB CHKTOT: CMP #1,VOLNUM ; First volume? BEQ 10$ ; Yes, branch CMP TAPDSZ,TOTLLN ; Amount of blocks match BNE 20$ ; No, branch 10$: MOV TAPDSZ,TOTLLN ; Store blocks total CLC ; Indicate success. RETURN ...... 20$: MOV #SET,R1 ; <-E-Volume does not belong to this set> JMP ERRRY ...... .DSABL LSB .SBTTL RCOPY - Restore one section of DEVICE or OLD FILE ;+ ; Transfer tape blocks to disk, either (part of) a file or device image. ;- .ENABL LSB RCOPY: MOV SPFBUF,R3 ; R3 -> adr of first buffer MOV BUFADD,R2 ; R2 -> adr of second buff CLRB EOFFLG ; clear EOF and CLRB DSKINU ; disk-in-use flags SAMTAP: MOV NUMSPF,R1 ; R1 = number of spfuns CMP RBLOCK,BLKCOP ; Chunk greater that blk left BLOS 40$ ; No, branch TST BLKCOP ; Any left? BLE REND ; If not, done. (signed chk ok) 10$: MOV RBLOCK,R4 ; Adjust R1 and RBLOCK 20$: SUB #TBLOCK,R4 ; for fewer final remaining CMP BLKCOP,R4 ; magtape blocks BGT 30$ DEC R1 BR 20$ 30$: MOV BLKCOP,RBLOCK ; actual no. of blocks yet to read ; Get ready for mag tape read operations 40$: MOV R2,TEMP1 ; Save magtape buf adrs CLR NBLOCK ; Copy Loop ... 50$: CALL MTREDW ; Read from magtape with Wait TSTB EOFFLG ; EOF or EOT? BNE 70$ ; branch if so. 60$: ADD #TBLOCK,NBLOCK ; count 256-wrd blocks read DEC R1 ; Finished with READ SPFUNS? BEQ 70$ ; Yes, branch ADD #TREC,R2 ; Adjust for next read BR 50$ ; do more READ SPFUNS... ...... 70$: TST NBLOCK ; Get out now if BEQ 110$ ; no data was read before EOF found CMP NBLOCK,BLKCOP ; Check for NBLOCK > BLKCOP BLOS 80$ ; which can happen on last go-round MOV BLKCOP,NBLOCK ; Limit disk transfer to BLKCOP blocks 80$: MOV R3,R2 ; swap buffer pointers MOV TEMP1,R3 ; Restore magtape buf address 90$: TST OUTBLK ; Write starts at block zero? BNE 100$ ; If not, skip BBR check BITB #XI$OPT,OPTACT ; DEVICE operation? BEQ 100$ ; branch if not CALL CHKHMB ; Check for hm blk on DM or DL 100$: CALL WWDISK ; start the disk write... SUB NBLOCK,BLKCOP ; Update blocks to read 110$: TSTB EOFFLG ; Was end-of-tape file reached? BEQ SAMTAP ; Keep restoring on this tape ; END_OF_SAVESET_SECTION (tapemark or PEOT) has been reached. SEC ; Indicate not finished... RETURN ; Get next volume. ...... ; ---------------------- FINISH LAST VOLUME ------------------------ ; Now, read the next record on tape; it should be an EOF (tapemark). ; (Actually, if the number of blocks written was an even multiple of ; eight, then BUP writes one unnecessary block. Check this situation.) ; Inform operator of completion. ; ------------------------------------------------------------------ REND: CLR TEMP1 ; Assume no extra blocks TST MT.BVN ; New tape? BNE 130$ ; if so, require exactness. 120$: BIT TOTLLN,#7 ; see if block size div by 8 BNE 130$ ; if so, INC TEMP1 ; allow one non-EOF 130$: CALL MTREDW ; Read from magtape with Wait TSTB EOFFLG ; tape mark? BNE 150$ ; if so get out. DEC TEMP1 ; otherwise, count down BGE 130$ ; if still positive keep looking 140$: TSTB GIV.B ; /FOREIGN? BMI 160$ ; be forgiving. .PRINT #WBNMSG ; Expected TM not found. BR 170$ ; (Tape volume position error) ...... ; Tape mark found 150$: TST MT.BVN ; New tape? BEQ 160$ ; if not, let it go. TST TEMP1 ; otherwise, check counter BNE 140$ ; If not exact, complain. ; Operation is complete TFRESD: 160$: CALL RESDON ; Display <-I-xxx operation complete> 170$: .WAIT DSKCHA ; Wait for disk operations to finish BIT #XI$OPT,OPTACT ; /DEVICE restore? BEQ 180$ CALL UPDDIR ; Update output's directory 180$: .CLOSE DSKCHA ; Make file permanent, close channel CLC ; Indicate finished RETURN ...... .DSABL LSB .SBTTL MTREDW - Read from Magtape with Wait ;+ ; Read one magtape block with an anticipated word count of TWNCT ; into a buffer pointed to by R2. Wait for the read to finish ; before returning to the caller. Check for read errors, ; END-OF-FILE, and END-OF-TAPE conditions. ;- .ENABL LSB MTREDW: CLR TPSTAT ; Wipe tape status word .SPFUN #EMTARE,TAPCHA,#SF.MRD,R2,#TWNCT,#LKBLK,#0 ;READ/WAIT CALL GMTSTA ; Get magtape status BCC 20$ ; Branch if no error BMI 10$ ; R0 with Bit-15 says hard error? CALL REOT ; End of file or tape? BCC 20$ ; branch if not. 5$: INCB EOFFLG ; Set EOF flag BR 30$ ...... ; There has been an error reading tape record. Tell user that a bad buffer ; has been copied and continue if there have not been too many bad buffers ; copied. 10$: TST MT.BVN ; Check tape's BUP version BNE 12$ ; if new, no excuses. CMP ARPCNT,..ARPE ; Old tape. EOT reached yet? BLT 5$ ; if so, pretend bad data was EOF 12$: MOV INFIL,DEVSPC ; with input device name, CALL RERR ; report READ error, then return. INC BADTOT ; count bad buffer CMP BADTOT,..MBAD ; is it too many bad buff? BLO 20$ ; no, branch MOV #TOO,R1 ;<-F-Too many bad blocks > FATI: MOV INPDEV,DEVSPC JMP FATALD ...... 20$: INC SSTBLK ; account for tape motion ADD #TBLOCK,NXTBLK ; pointing to this disk image block 30$: RETURN ...... .DSABL LSB .SBTTL WRTDSK - Write to disk (file) ;+ ; Write blocks to output disk or disk file ; ; R3 -> buffer address ; R4 -> wordcount ; OUTBLK has block number ; ; CALL WRTDSK ; ; VERIFY for RESTORE is contained herein. ;- .ENABL LSB ; This entry WAITS for previous write to complete before writing WTWRTD: CALL WAITWR ; Wait for previous write to finish BCC WRTDSK ; If errors, return without writing. RETURN ...... WRTDSK: CMPB VONLY,#WRDISK ; Is this a COMPARE-ONLY operation? BNE 20$ ; If so, skip disk write stuff. .IF NE DEBUG .PRINT #WRNGMS MOV R2,-(SP) MOV R4,-(SP) MOV OUTBLK,R2 CALL DECIMA MOV (SP)+,R4 MOV (SP)+,R2 .PRINT #CRLF .EndC; NE DEBUG .WRITE #EMTARE,DSKCHA,R3,R4,OUTBLK ; Initiate Write to disk BCC 10$ ; Immediate Write Errors are fatal. MOV #WR2,R1 ;<-F-Output error > MOV OUTFIL,DEVSPC JMP FATALD ; Fatal error with Output spec ...... ; If /VERIFY was specified, wait for the disk write to complete, then ; read it back and compare it with the magtape buffer 10$: MOVB #1,DSKINU ; set in-use flag TSTB GIV.V ; /VERIFY given? BPL 80$ ; no, branch and RETURN. CALL WAITWR ; wait for disk write 20$: CLRB DSKINU ; clear its flag MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV #-1,TEMP2 ; Init most-recent block no. ; (use buffer already pointed to by R2 - VERIFY mode does not use ; async writes with double buffering, so that buffer is now free) MOV R2,R1 ; Save other buffer address .READW #EMTARE,DSKCHA,R2,R4,OUTBLK ; Read what was written BCC 30$ ; branch if no error MOV OUTFIL,DEVSPC MOV R2,-(SP) MOV R1,-(SP) CALL RERR ; Report READ error, and return. MOV (SP)+,R1 BR 40$ ...... ; VERIFY loop 30$: CMP (R3)+,(R2)+ ; equivalent words ? BEQ 60$ ; yes, branch ; Mismatch in data... Inform the user. MOV R2,-(SP) ; Save the pointer... TST -(R2) ; account for (R2)+ above, 40$: SUB R1,R2 ; Subtract base buffer address ASR R2 ; Make it a word number SWAB R2 ; Isolate the block number BIC #177400,R2 ADD OUTBLK,R2 ; Now it's absolute. CMP R2,TEMP2 ; Is it the same as last time? BEQ 50$ ; Branch around error msg if so. MOV R4,-(SP) MOV R2,TEMP2 ; Save most-recent non-verifying block CALL RVERER ; Report verify error (BUPRES) MOV (SP)+,R4 50$: MOV (SP)+,R2 ; Restore pointer CMP VBAD,..MBAD ; Too many bad verifies ? BLO 60$ ; no, this word done though MOV #MIS,R1 ;<-F-Too many mismatches > JMP FATAL ...... 60$: SOB R4,30$ ; REPEAT 70$: MOV (SP)+,R4 ; restore regs and return MOV (SP)+,R3 MOV (SP)+,R2 80$: RETURN ...... ; WAIT and then WRITE to disk -- ; WRITE a full NBLOCK worth of words to the disk or disk file. WWDISK: CALL WAITWR ; Wait for any outstanding write MOV NBLOCK,R4 ; for this many blocks, SWAB R4 ; make word count, CALL WRTDSK ; Write it. ADD NBLOCK,OUTBLK ; Update OUTBLK. RETURN ...... ; WAIT for disk write to complete, check for errors WAITWR: TSTB DSKINU ; If disk not in use, BEQ 100$ ; don't wait. .WAIT DSKCHA ; Ok. wait for disk (hmm de hmmm...) BCC 90$ ; branch if no error MOV #WR2,R1 ; <-E-Output error > CALL ERRRO ; report error 90$: CLRB DSKINU ; clear disk-in-use flag 100$: RETURN ...... ; Report error, and return. RERR: MOV R3,-(SP) ; READ input error on device MOV #RE2,R1 ; -E-Input error BR 120$ ...... ERRRO: MOV R3,-(SP) ; report output error MOV #OUTFIL,R3 INC WBAD ; chalk one up CMP WBAD,..MBAD ; limit exceeded? BLOS 110$ ; branch if not. MOV #TOO,R1 ; -F-Too many bad blocks MOV @R3,DEVSPC JMP FATALD ...... 110$: BIT #XI$OPT,OPTACT ; /DEVICE operation? BEQ ERRRR ; branch if not. MOV @R3,DEVSPC ; display device name only 120$: MOV #DEVSPC,R3 ERRRR: .ERR #ERRARE,R1,LEVEL=ERROR,RETURN=YES,FILE=R3 MOV (SP)+,R3 RETURN ...... .DSABL LSB .SBTTL REOT - Check for END OF TAPE ;+ ; Check that the error was due to an END OF TAPE condition. ; If so return to the caller. ;- .ENABL LSB REOT: BIT #TS.EOF,R0 ; EOF found? BNE 20$ ; Branch if so. TST MT.BVN ; Is BUP tape from post-V5.41 era? BEQ 10$ ; Branch if not. BIT #TS.EOT,R0 ; EOT only? BNE 30$ ; yes. return with no error or carry BR 40$ ; otherwise, it's a weird error. ...... ; Old (pre V5.41) BUP multi-volume tapes have no EOF at the end of ; non-last volumes. Look for the EOT foil, and then allow up to ..ARPE ; records passed sensing the foil. 10$: CMP #2,LKBLK ; Was it end of tape (EOT) foil? BNE 40$ ; If not, it's an error. DEC ARPCNT ; Count allowable records passed EOT BGE 30$ ; While >= 0, pretend we don't see it. ; Otherwise, drop through. 20$: SEC ; Return "End-of-data" found RETURN ...... 30$: .IF NE DEBUG .PRINT #NOEOD .ENDC CLC ; Not end-of-data return RETURN ...... 40$: MOV #RE2,R1 ;<-F-Input error > JMP FATI ...... .DSABL LSB .SBTTL FRCOPY - Restore file from /DEVICE saveset ;+ ; Copy files from /DEVICE image on tape to disk file ; ; Use IGTDIR and IGTENT to retrieve file entries from the workfile ; copy of the tape's directory image. ; ; There is a magtape record currently cached in the 1st buffer, as ; a result of MAKTMP. Initiate buffer pointers in reverse to counteract ; the first buffer swap below. ;- .ENABL LSB FRCOPY: MOV BUFADD,R2 ; adr of 1st buffer MOV R2,BP2 ADD #TREC,R2 ; adr of 2nd buffer MOV R2,BP1 CLRB EOFFLG ; clear EOF TST BLKCOP ; Already doing file? BEQ 10$ ; No. Get next entry. CALL SHOSTA ; otherwise, report starting. TST OUTBLK ; anything found yet? BNE 50$ ; Yes. No fwdspace necessary. BR 45$ ; No. Might need forwardspace 1st. ...... 10$: MOV #IGTENT,R0 ; IGTENT entry address MOV #IGEBLK,R5 ; arg block address CALL CALL$F ; call IGTENT... TSTB GIV.P ; /EXCLUDE in effect? BPL 15$ CMP R0,#E.NOMA ; not a match? BEQ 20$ ; then use it. TST R0 BPL 10$ ; if matched, skip it. 15$: TST R0 ; look at return value -- BPL 20$ ; If positive, entry is good. CALL RESDON ; RESTORE DONE (in BUPRES) CLC RETURN ...... 20$: BIS R0,FNDBTS ; update file-found-bitmap MOV #DIRENT,R1 MOV E.LENG(R1),BLKCOP ; File length MOV BLKCOP,FILSIZ BEQ 10$ ; skip zero-length files BIT #400,R0 ; EXACT extention? BNE 30$ CMP E.TYPE(R1),#^RSYS ; if not, is extention .SYS? BNE 30$ ; branch if not. TSTB SYSOUT ; is output SY:? BEQ 30$ ; branch if not. MOVB GIV.E,R0 ; /SYSTEM specified? BISB VONLY,R0 ; /VERIFY:ONLY specified? BMI 30$ ; branch if so. ; This wildcard file is a .SYS file, output is SY:, and permission has ; not been granted. If a message hasn't already been printed, print it ; now. In any case, skip the file. TSTB NSYMSG ; "No .SYS action" yet? BNE 10$ ; if so, get next file entry. INCB NSYMSG ; Declare message is out. .ERR #ERRARE,#NSY,LEVEL=WARNING,RETURN=YES BR 10$ ...... 30$: TSTB NONAME ; Output filename supplied? BPL 40$ ; branch if so. MOV R1,R3 ; point to directory entry ADD #E.NAME,R3 ; point to name in entry MOV #,R4 ; and also to output spec .REPT 3 MOV (R3)+,(R4)+ ; let OUTFILNAM = DIRFILNAM .ENDR ; Create output file. 40$: CALL SHOSTA ; report starting. CALL FILALL ; make output file BCS 10$ ; if it fails, try next one. CLR OUTBLK ; Reset output block number CLRB DSKINU ; clear disk-in-use flag ; Forwardspace the tape to the next file as required. ; Check to see if the needed magtape record is already in buffer. ; If so, skip the read operation. 45$: MOV FILBLK,R0 ; The file's image disk block MOV R0,R1 ; Save a copy BIC #^C<7>,R1 ; MOD to get block within tape record MOV R1,BLKMOD ; save it. CLC ; .ASSUME TBLOCK EQ 8. ROR R0 ASR R0 ; Divide by 8 to get tape block no. ASR R0 SUB SSTBLK,R0 ; where are we compared with that? BEQ 60$ ; there already? DEC R0 ; will next read do it? BEQ 50$ ; branch if yes. MOV R0,R3 ; move forward this many records ADD R0,SSTBLK ; bump up our odometer ; .ASSUME TBLOCK EQ 8. ASL R0 ASL R0 ASL R0 ADD R0,NXTBLK ; account for tape blocks passed CALL FORWSN ; Forwardspace tape TST R3 ; Did F-space complete without EOF? BEQ 50$ ; branch if yes. INC R3 ; No. Account for tapemark. SUB R3,SSTBLK ; adjust for records not on this tape ; .ASSUME TBLOCK EQ 8. ASL R3 ASL R3 ASL R3 SUB R3,NXTBLK ; adjust for blocks not on this tape BR RFNEXT ; and request next tape. ............ ; Within the current file, loop for all tape blocks involved in the ; transfer. 50$: MOV BP1,R2 ; R2 -> adr of 1st buffer MOV BP2,R3 ; R3 -> adr of 2nd buffer CALL MTREDW ; Read next tape block via R2 TSTB EOFFLG ; Is it end-of-file? BNE RFNEXT ; If so, Get next ; After successful magtape read operations, swap the buffers. MOV R3,BP1 ; swap buffer pointers MOV R2,BP2 ; Determine exact word count and buffer addresses for disk write. 60$: MOV BP1,R2 ; R2 -> adr of 1st buffer MOV BP2,R3 ; R3 -> adr of 2nd buffer MOV #TBLOCK,R4 ; Assume 8 blocks SUB BLKMOD,R4 ; subtract any not needed at front CMP BLKCOP,R4 ; fewer yet needed? BHIS 70$ ; branch if not. MOV BLKCOP,R4 ; Otherwise, use this 70$: MOV R4,NBLOCK ; Actual no. of blocks to copy SWAB R4 ; make word count MOV BLKMOD,R0 ; Get start block within tape block BEQ 80$ ; If first, skip offset code SWAB R0 ; Make a wordcount of words to skip, ASL R0 ; make BYTEcount, ADD R0,R2 ; and adjust the buffer addresses ADD R0,R3 ; for partial block usage ; Write buffer to disk 80$: CALL WTWRTD ; Write to disk from (R3) CLR BLKMOD ; Always resume with 1st block MOV NBLOCK,R0 ; Number of blocks transferred. ADD R0,OUTBLK ; Adjust various counters SUB R0,BLKCOP ; Are there blocks yet to copy? BNE 50$ ; continue if so. ; File is finished. Close it up, then loop around for another. .WAIT DSKCHA ; wait for disk output to finish CLRB DSKINU ; clear in-use flag CMPB DEV1,#DEV.TT ; Output to TT? BEQ 85$ ; if so, skip .CLOSE .CLOSE DSKCHA ; close output file. 85$: CALL FINFIL ; Finish file (protect, set date) JMP 10$ ; Go try for another. ...... RFNEXT: SEC ; Indicate not finished RETURN ...... ; Display "Restore operation started" for this volume SHOSTA: CMP SHOVOL,VOLNUM ; did this one yet? BEQ 90$ CALL SIGSTA ; report start of volume MOV VOLNUM,SHOVOL 90$: RETURN ...... .DSABL LSB .SBTTL Directory for Magtape ; MONTAB contains 12 entries, one for each month, each containing the total ; number of days in the year through the end of that month. LEAPTB is ; a similar table with entries for leap years. .PSECT MT2DAT,D JAN = 31. FEB = JAN + 28. MAR = FEB + 31. APR = MAR + 30. MAY = APR + 31. JUN = MAY + 30. JUL = JUN + 31. AUG = JUL + 31. SEP = AUG + 30. OCT = SEP + 31. NOV = OCT + 30. NOEL = NOV + 31. MONTAB: .WORD 0 ;IF NO DATE SPECIFIED, MONTH = 0 .WORD JAN .WORD FEB .WORD MAR .WORD APR .WORD MAY .WORD JUN .WORD JUL .WORD AUG .WORD SEP .WORD OCT .WORD NOV .WORD NOEL LEAPTB: .WORD 0 ;IF NO DATE SPECIFIED, MONTH = 0 .WORD JAN .WORD FEB+1 .WORD MAR+1 .WORD APR+1 .WORD MAY+1 .WORD JUN+1 .WORD JUL+1 .WORD AUG+1 .WORD SEP+1 .WORD OCT+1 .WORD NOV+1 .WORD NOEL+1 FYEAR: .WORD 0 ; IFWILD arg block IFWBLK: .WORD 2 .WORD LBLBUF ; this file's name string .WORD ASCLST ; wildcard input match string LFILE =: 1. ; directory entry LSECT =: 15. ; SAVESET section column LBLOCK =: 27. ; items LDATE =: 40. .SBTTL PRNENT - Print tape directory entry .PSECT MT2,I ;+ ; Print directory entry ; ; Start by moving the saveset name from HDRNAM to LBLBUF, inserting ; a period character between the name and extention. Then, if ; an input spec was supplied, use IFWILD to determine whether ; there was a match. If not, skip the entry. ;- .ENABL LSB PRNENT: MOV #HDRNAM,R0 ; Point to saved ASCII name MOV #LBLBUF,R5 ; scratch buffer MOV #6,R2 ; no. of chars in name part 10$: MOVB (R0)+,(R5)+ ; move filename to LBLBUF DEC R2 BNE 10$ MOVB #'.,(R5)+ ; move a dot to LBLBUF MOVB (R0)+,(R5)+ ; move extention to LBLBUF MOVB (R0)+,(R5)+ MOVB (R0)+,(R5)+ CLRB @R5 ; plant a NULL TST NONAME ; was an input name specified? BMI 20$ ; do it if not. MOV #IFWILD,R0 MOV #IFWBLK,R5 CALL CALL$F ; let IFWILD decide TSTB GIV.P ; /EXCLUDE in effect? BPL 15$ ; branch if not. NEG R0 ; reverse criteria 15$: TST R0 ; look at its result... BLT 30$ ; skip entry if no match. 20$: ADD TAPSES,SAVINB ; Accumulate total usage ADC BLKVER ; 2nd word of total INC NFTRAN ; add 1 to no. of savesets CALL GETDAT ; Decode date info CALL PDENT ; print one-line entry 30$: INC NFSCAN ; add 1 to no. of savesets scanned RETURN .DSABL LSB .SBTTL GETDAT - Get saveset date from tape ; Decode the tape file's date. Old BUP tapes have an RT-11 binary date ; word stuck where the ANSI date is supposed to start. .ENABL LSB GETDAT: MOV #-72.,FYEAR MOV #,R1 ;R1 -> saved date string MOVB -(R1),R0 ;look at year chars BISB -(R1),R0 BEQ 40$ ;If zero, old tape, and date not set. MOV #'0,R0 ;prepare for checking MOV R1,R2 ; year field for zeros. CMPB -1(R2),R0 ; 21st century? BNE 10$ ; if ' ', then 20th century. ADD #100.,FYEAR BR 50$ ...... 10$: CMPB (R2)+,R0 ;year tens zero? BNE 20$ ; no. do day check CMPB (R2)+,R0 ;yes. year ones zero? BNE 30$ ; no. do day check ; Tape has ANSI date format, but date was not set. Fake old and not set. NODATE: CLR DDATE RETURN ...... ; The ANSI year field is non-zero, and not "00". If the day-of-year ; field is "000", then it must be an OLD BUP tape with the RT-11 date ; word jammed into the year digits position. If the day-of-year ; digits are not "000", then assume ANSI date. 20$: INC R2 30$: CMPB (R2)+,R0 ;day hundreds zero? BNE 50$ CMPB (R2)+,R0 ;day tens zero? BNE 50$ CMPB (R2)+,R0 ;day ones zero? BNE 50$ 40$: MOV @R1,DDATE ;Save date from old format RETURN ; Decode the ANSI date characters into binary values, and set DDATE 50$: MOV R1,R2 ; Point to year chars MOV #2,R3 ; number of digits in year CALL ASCBIN ADD FYEAR,R0 ; years since 1972 BLT NODATE ; invalid? 60$: CMPB R0,#32. ; is it in this age? BLT 70$ ; branch if yes. ADD #<40000-32.>,R0 ; move to next age BR 60$ ; and try again. 70$: MOV R0,FYEAR MOV #3,R3 ; number of digits in day CALL ASCBIN ; convert day characters MOV #MONTAB,R1 ; Point to first day table BIT FYEAR,#3 ; Leap year? BNE 80$ ; Branch if not MOV #LEAPTB,R1 ; Use leapyear table 80$: CLR R4 ; Initialize file's month counter CLR R3 90$: CMP R0,(R1) ; Compare julian day with month entry BLE 100$ ; This is the month? INC R4 ; Nope, go to the next one. MOV (R1)+,R3 ; point to next first-day entry BR 90$ 100$: SWAB R4 ; Move MONTH up 8 bits SUB R3,R0 ; Get day of the month ASL R0 ASL R0 ASL R0 ADD R0,R4 ; merge in day. ASL R4 ASL R4 ADD FYEAR,R4 ; merge in year. MOV R4,DDATE RETURN .DSABL LSB .SBTTL DIRHDR - Display tape directory ;+ ; These routines display a list of saveset sections on the mounted tape ; volume. The first opens the list file (if necessary), and prints a header. ; ; The second routine displays one file entry with its creation date. ; ; (Note: the saveset directories are not done here; they are done by jumping ; into the BUPDDI overlay.) ;- .ENABL LSB DIRHDR: TSTB NEEDOP ; Need list file opened? BEQ 5$ CALL DOOPEN ; Open the list file now CLRB NEEDOP 5$: CALL RTNICE ; Print the INTRO message .PFILE #CRLF ; Skip one line .IF NE VOLPRT .PFILE #VLBLIN ; Print volume label line .ENDC; VOLPRT .PFILE #MTDHED ; Print directory header .PFILE #CRLF1 ; skip one line RETURN ; Print tape directory entry - display the saveset section name, ; its size information, and the creation date. PDENT: MOV #1,LPOINT ; Init the location counter MOV #LFILE,R2 ; Location counter for SSNAME CALL PSPACE ; Put spaces CALL PRNAME ; Print filename ADD #10.,LPOINT ; Update location counter MOV #LSECT,R2 ; Location counter for message CALL PSPACE ; Put spaces MOV TAPSVN,R2 ; Get volume number CALL DECIMF ; Print it ADD R4,LPOINT ; Update location counter MOV #LBLOCK,R2 ; Location counter for message CALL PSPACE ; Put spaces MOV TAPSES,R2 ; Get size of file CALL DECIMF ; Print it ADD R4,LPOINT ; Update location counter MOV #'/,R0 ; print a slash .COUT INC LPOINT MOV TAPDSZ,R2 ; Get SAVESET size CALL DECIMF ; Print it ADD R4,LPOINT MOV #LDATE,R2 ; Location counter for message CALL PSPACE ; Put spaces MOV DDATE,R0 ; Get file date 10$: CALL DATE2 ; Print it 20$: .PFILE #CRLF1 ; do CRLF RETURN .DSABL LSB .SBTTL PRNAME - Print the filename ;+ ; The following routine prints the filename of the Backup file on ; the directory display. ;- .ENABL LSB PRNAME: MOV #10.,R2 ; do 10 characters MOV #LBLBUF,R4 ; R4 -> ascii filename 10$: MOVB (R4)+,R0 ; Get character .COUT ; Output the character DEC R2 ; Decrement count BNE 10$ ; Repeat if not zero RETURN .DSABL LSB .END