.TITLE BACKUP ... DBSMNG backup package .IDENT /110582/ .ENABL LC ; ; Written by Ray Di Marco ; 11-May-82 ; ; ; Version 110582 ; ; ;---------------------------------------------------------------------------- ; ; This is the main module for the database management BACKUP programs that ; allow the user to selectively backup and restore database records. The ; four programs in the backup package ; ; 1) BACKUT ... utility program to create backup file ; 2) BACKUP ... cusp to backup records to backup file ; 3) BACKUN ... cusp to restore records from backup file ; 4) BACKUF ... cusp to create SELECT command file ; ; are generated by assembling this module with a prefix file that defines ; the BCKCNF symbol to have a value of 1, 2 or 3 (ie 1=BACKUT, 2=BACKUP) ; and then linking the resulting object module with the database library ; and optionally the user's database template. The manner in which the ; package is used is as follows ; ; The BACKUT program is run to create and intialize a specially ; formatted backup file. This is done by the database manager. ; ; The BACKUP program can be run whenever desired to copy selected ; records into the backup file. The BACKUP takes as into a SELECT ; format file (as generated by the SELECT cusp) that determines ; which records are to be backed up. Note that each time the program ; is run it appends new backup data to that already existing in the ; backup file, and that a suitable message is output each time ; indicating the amount of room left in the backup file. Optionally ; BACKUF can be run to create a command file that can be given to ; SELECT to ensure that all records changed since the last backup ; are selected for backing up. ; ; The BACKUN program is run when database records have been destroyed ; and it is necessary to restore the database from a backup file. ; When run, BACKUN simply transfers all backup file data back into ; the database record from which it originally came from. ; ; The programs can be envoked as a CUSP from a menu program, and will accept ; all necessary commands from data passed via core common. Normally only the ; BACKUP program would be accessable via the menu, and BACKUT and BACKUN ; would be used only by the system manager. ; .SBTTL Documentation .IF EQ,-1 Upon activation, the programs will prompt the user for the following items of information. Note that not all three of the programs need all the items listed below, and that if a particular program is envoked as a CUSP from a menu, some of this data may be passed via core common. DB Template : This question is only asked if the user's database template was not linked in when the program was linked. In response to this question the user must specify the name of the file that contains the template (in .SAV) format for the user database. Backup File : In response to this question, the user must supply the name of the file that is used to hold the backup data. This is a specially formatted file, and is described in detail below. Select File : In response to this question, the user must supply the name of the SELECT FORMAT file that determines which records are to be processed; such a file is created by the SELECT cusp, which allows the user to test records for suitability for inclusion in a given operation. Format File : In response to this question, the user supplies the name of a file into which a series of commands which will cause SELECT to select all database records that have been created or editted since BACKUP was last run. The key to the operation of the backup package is a specially formatted file, called the BACKUP file. The BACKUT program must be run first to create such a file. BACKUT allows the user to specify the name that is to be given to the file, and the maximun number of records that may be archieved in it. The backup file consists of a one block header and a number of data blocks. Backup entries (consisting of a two word header and data from database records) are stored in the data blocks. Note that these backup entries are concatinated one after the other, without any wasted space in order to maximize disk utilization. The format of a backup file is as follows Block Byte Variable data function/usage number offset name type 0 0 Entsiz I*2 number bytes per backup entry 2 Entnum I*2 number backup entries used 40 DBSNME B*6 six letter database name 50 BCKDAT I*2 date of last backup 100 OWNER R*6 must be rad50 string BACKUP 104 Filsiz I*2 number of blocks in file 106 CHECK R*3 must be rad50 string WEN=Write Enable 110 BLK I*2 Block number for start of free space 112 BYT I*2 Offset in BLK to start of free space 1 0 ENT#1 First backup entry . . n m ENT#k last entry written to date BLK BYT free start of free data area The backup entries in turn consist of a two word header and the data from a database record. The first word is the number of the record from which the data was obtained, and the second the date upon which the backup was done. A typical scenario for the use of the backup package starts when the database manager decides that the data being stored in a database must be protected against hardware mulfunction or accidental erasure. This can only be done by using a combination of incremental and complete backup stratergies. A given intervals (dependant on the amount of new data being entered) a complete backup of the database is performed by copying the PAR, KEY and DAT files for the database onto a backup medium; naturaly a number of backup volumes should be used in cyclic order to protect against an undetected corruption working its way into the backup set. As a complete backup, particularly for a large database, can be time consuming, the quicker and easier to use incremental backup system should be used to backup data that is newly entered or changed between the complete backup times. To do this, the system manager must follow the steps outlined below BACKUT must be run to create a backup format file. If possible, this file should be placed on a seperate volume to that which holds to databse (to protect against a head crash etc), and should be large enough to hold all records that will be created or editted before the next total backup time. The BACKUP program can then be run at any time (say once a day or after busy editting session) to backup all newly created or editted records. Naturally while the manner via which BACKUP is envoked is application specific, it is best to include it as a MENU option if possible. The suggested method is to setup a MENU option that envokes SELECT to select all database records whose edit dates (ie [ed] field) are greater than a given date, and then to envoke BACKUP to backup these selected records. If this is done, incremental backup can then be carried out by users, without bothering the database manager. Note that BACKUP automatically displays how full the backup file is each time it is run, and that a suitable warning message telling the user to inform the database manager is output whenever the backup file becomes over 80% full. In the event of a database corruption, BACKUN may then be run by the system manager to update the last complete backup file set and thereby restore the database. Naturally, a new incremental backup file should be started whenever a complete backup is performed; the old file may either be archieved or deleted. The only point requiring special attention when setting up a incremental backup option in the menu is deciding how records will be selected for backup. Methods available are to allow the user to specify a date, and to backup all records that have an [ed] date later than that, or to use BACKUF to create a select command file that waill cause all records that were created or editted on or after the date of the last backup to be selected for backup. Below is provided an example MENU and SELECT command files that may be used to implement incremental backup via the user menu. ______________________________________________________________________________ Demo Menu for Backup Package 1 Backup all records that have been created or editted since last backup was done 2 Backup all records that have been created or editted today 3 Backup all records that have been created or editted since a user specified date $* $1 $@LB:BACKUF$$ ; chain to BCKUF $IBACKUP.DAT$$ ; name of backup file $ISELECT.CMD$$ ; name for SELECT command file $CLB:SELECT$$ ; chain to SELECT $IDBSTMP$$ ; name of database template $ISELECT.CMD$$ ; name of selection command file $ISELECT.DAT$$ ; file in which to store selections $I0$$ ; no maximum record lenght $CLB:BACKUP$$ ; envoke backup $IDBSTMP$$ ; name of database template $IBACKUP.DAT$$ ; name of backup file $ISELECT.DAT$$ ; file of selected records $CLB:MENU$$ ; pass control back to menu $IMENU.FRM$$ ; name of menu format file $! $2 $@LB:SELECT$$ ; chain to SELECT $IDBSTMP$$ ; name of database template $ISELECT.002$$ ; name of selection command file $ISELECT.DAT$$ ; file in which to store selections $I0$$ ; no maximum record lenght $CLB:BACKUP$$ ; envoke backup $IDBSTMP$$ ; name of database template $IBACKUP.DAT$$ ; name of backup file $ISELECT.DAT$$ ; file of selected records $CLB:MENU$$ ; pass control back to menu $IMENU.FRM$$ ; name of menu format file $! $3 $@LB:SELECT$$ ; chain to SELECT $IDBSTMP$$ ; name of database template $ISELECT.003$$ ; name of selection command file $ISELECT.DAT$$ ; file in which to store selections $I0$$ ; no maximum record lenght $CLB:BACKUP$$ ; envoke backup $IDBSTMP$$ ; name of database template $IBACKUP.DAT$$ ; name of backup file $ISELECT.DAT$$ ; file of selected records $CLB:MENU$$ ; pass control back to menu $IMENU.FRM$$ ; name of menu format file $! $* ------------------------------------------------------------------------------ The files SELECT.002 and SELECT.003 are as follows ; File SELECT.002 that causes all records with an edit date equivalent to the ; present system date to be selected $* $T [ed].EQ.D4$$ $L [ed] $$ $E ; file SELECT.003 that causes all records with an edit date equal to or ; greater than that specified by the user to be selected ; $)Enter date : $$ $?D1 $* $T [ed].GE.D1$$ $L [ed] $$ $E .ENDC .IF EQ,BCKCNF-1 ; ***** want BACKUT program ******* .SBTTL Declarations ; .PRINT ; The output module contains the code for BACKUT! ; .MCALL CNAF ; CNAF .MCALL FILSPT ; FILSPT .MCALL .EXIT ; error abort .MCALL .DATE ; returns RT-11 date ; FILSPT ; initilaize file IOer ; .GLOBL FORM$$ ; address template .GLOBL $$FORM ; pointer to template .GLOBL DBSLDR ; template loader .GLOBL CON.ST,CON.EX ; CONIO .GLOBL ASCNUM ; ASCNUM ; ; ; .PSECT CODE ; open code area ; ====== ==== .SBTTL Macro Definitions ; .MACRO PRINT STR=R0 .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDM PRINT ; .MACRO GTLIN BUF=R0,STR .IF NB,STR .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDC MOV BUF,R0 .GLOBL CON.LI CALL CON.LI .ENDM GTLIN ; .MACRO ASK QUEST,?A,?B,?C .GLOBL CON.LO,CON.LI MOV #'B,R0 CALL CON.LO MOV #BUF,R0 CALL CON.LI BR C B': .ASCII / //'QUEST'/<200> .EVEN C': .ENDM ASK ; .SBTTL Initialization ; ; If TEMPLATE not linked in with the program use DBSLDR to load the template. ; If the template was linked in, $$FORM. If have to load the template ; ourselves we must store the load address (returned in R0 by DBSLDR) in ; $$FORM as its needed later. ; START: CALL CON.ST ; ensure CONIO inited PRINT #7000$ ; identify self TST $$FORM ; template linked in? BNE 100$ ; yes -> skip ASK ; prompt for template MOV #BUF,R0 ; R0 -> name CALL DBSLDR ; load template MOV R0,$$FORM ; set up pointer 100$: CALL CREATE ; create backup file JMP CON.EX ; all done ; ; .NLIST BIN 7000$: .ASCIZ /Backut RDM110582/ .EVEN .LIST BIN ; ; .SBTTL Routine - "CREATE" ... Create a backup file ; ; We are here to create a backup file for the user. The name and size of the ; file are specified by the user. ; ; Start by ensuring that the File Descriptor Block is free, and that ; automatic file I/O error messages are suppressed. ; CREATE: PURGE #BCK ; ensure FDB free BIS #F.NERR,FDB.FL(R5) ; no automatic error messages ; ; As user for name of file and associate it with the FDB and then ; get number of entries to be held in file. ; ASK < Name for BACKUP file is: > NAME STRING=#BUF,EXTENS=#^RDAT,ERROR=2700$ 400$: ASK < Number entries in file: > MOV #BUF,R1 ; R1 -> input CALL ASCNUM ; get number TST R0 ; valide number? BLE 400$ ; no -> loop ; ; Setup H.DATE entry in header with date upon which created file. ; .DATE ; R0 = date in RT-11 format BIC #^C37777,R0 ; strip unwanted bits CLR R1 ; R1 = 0 ASHC #-5,R0 ; R1 = year count ADD R1,R0 ; R0 = date in internal format MOV R0,H.DATE ; setup date ; ; Setup H.ENTS, H.FILS and H.DBSN fields in backup header block. ; MOV $$FORM,R4 ; R4 -> template MOV 6(R4),H.ENTS ; allow for database record ADD #4,H.ENTS ; allow for header bytes ; MUL H.ENTS,R0 ; R01= number bytes needed DIV #1000,R0 ; R0 = number blocks needed TST R1 ; need bit of next block BEQ 1100$ ; no -> skip INC R0 ; yes -> ask for extra blk 1100$: INC R0 ; need extra block for header MOV R0,H.FILS ; set up file size ; ADD #40,R4 ; R4 -> DBSNME in template MOV #H.DBSN,R1 ; R1 -> DBSNME in backup file hdr MOV #6,R2 ; R2 = number bytes in name 1200$: MOVB (R4)+,(R1)+ ; copy time SOB R2,1200$ ; loop till all copied ; ; ; ; Write out header block and release FDB before exitting. ; ENTER SIZE=H.FILS,ERROR=2700$ ; create file WRITE BLOCK=#0,ERROR=2700$ ; output header MOV H.FILS,R1 ; R1 = number blocks DEC R1 ; R1 = last block WRITE BLOCK=R1,ERROR=2700$ ; output last block CLOSE ; close file RETURN ; exit ; ; Get here if encounter a file I/O error at any time. ; 2700$: PRINT #7000$ ; tell got an error STATUS ; show cause of error .EXIT ; abort .NLIST BIN 7000$: .ASCII /CREATE-fatal-backup file creation error!/<15><12><11><200> .EVEN .LIST BIN .SBTTL Variables are data structures ; .PSECT $SCTRH ; open scratch area ; ====== ====== ; BUF: .BLKB 100 ; general I/O buffer FDB BCK,CHANNEL=1,BUFFER=FILBUF,SIZE=400 ; generate a FDB FILBUF: H.ENTS: .WORD 0 ; number bytes/entry H.ENTN: .WORD 0 ; number of entries in use . = FILBUF+40 H.DBSN: .ASCII /XXXXXX/<0><0> ; database name H.DATE: .WORD 0 ; date of last backup . = FILBUF+100 H.OWNR: .RAD50 /BACKUP/ ; identifies backup file H.FILS: .WORD 0 ; number blocks in file H.WEN: .RAD50 /WEN/ ; indicates that is write enabled H.BLK: .WORD 1 ; next avialible block H.CHR: .WORD 0 ; next available byte in block .REPT 1000-<.-FILBUF> ; Pad out the rest of the header .... .BYTE 0 ; .... block with nice safe .... .ENDR ; .... NULLs ; ; .ENDC ; **************************************** .IF EQ,BCKCNF-2 ; ***** want BACKUP program ******* .SBTTL Declarations ; .PRINT ; The output module contains the code for BACKUP! ; ; .MCALL .PUSH,.POP ; Stacking .MCALL CNAF ; Binary -> Ascii .MCALL .EXIT ; Abort Exit .MCALL .DATE ; returns date in R0 ; .GLOBL $$FORM ; Index for DBS support routines .GLOBL FORM$$ ; Start of database format block .GLOBL DBSLDR ; Database loader ; .GLOBL SFLINT,SFLINP ; entries .GLOBL SFLNME,SFLPAR ; data structures .GLOBL FILINT,FIL.DR ; DBSSUP - 'FILEIO' .GLOBL CON.ST,CON.LI,CON.CO,CON.EX ; "CONIO" ; ; ; .PSECT CODE ; OPEN CODE SECTION ; ------ ---- ; .SBTTL Macro Definitions ; ; .MACRO PRINT STR=R0 .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDM PRINT ; ; .MACRO GTLIN BUF=R0,STR .IF NB,STR .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDC MOV BUF,R0 .GLOBL CON.LI CALL CON.LI .ENDM GTLIN ; ; .MACRO FATAL STR,?A,?B PRINT #'B .EXIT B': .ASCIZ |'STR'| .EVEN .ENDM FATAL ; .SBTTL INITIALIZATION SECTION ; ; Initialize TTY interface and ensure that have a database template loaded. ; This is also a good time to get the name of the files needed later.; ; START: CALL CON.ST ; initialize TTY interface PRINT #7000$ ; identify self TST $$FORM ; is template linked in? BNE 100$ ; yes -> skip GTLIN #TMPB1,#7010$ ; get template name MOV #TMPB1,R0 ; R0 -> name CALL DBSLDR ; load template MOV R0,$$FORM ; save load address in pointer 100$: GTLIN #BCKNME,#7100$ ; get name of 'BCK' file GTLIN #SFLNME,#7110$ ; get name of 'SFL' file ; ; Gain access to files needed in backup process. ; CALL BCKINT ; format description file CALL SFLINT ; initialize sort file CALL FILINT ; open data base ; ; Ensure that the BACKUP file is compatiable with the database being used. ; CALL CHECKR ; check that ok to continue ; ; See if user really wants us to carry out the backup. ; GTLIN #TMPB1,#7200$ ; querry time? CMPB TMPB1,#'Y ; response = Yes? BEQ BACKUP ; yes -> gain access to files JMP CON.EX ; exit time ; .NLIST BIN 7000$: .ASCIZ /Backup RDM110582/ 7010$: .ASCII / DB Template: /<200> 7100$: .ASCII / Backup File: /<200> 7110$: .ASCII / Select File: /<200> 7200$: .ASCII / Really backup database? /<200> .EVEN .LIST BIN ; .SBTTL Code - "BACKUP" ... backup all selected records ; ; This code loads in the selected records one at a time, writing out each one ; to the backup stream preceded by a two word header that identifies the ; record number and the date of the backup. ; ; ; Get system date and initialize counter for loop. ; BACKUP: .DATE ; R0 = date in RT-11 format BIC #^C37777,R0 ; strip unwanted bits CLR R1 ; R1 = 0 ASHC #-5,R0 ; R1 = year count ADD R1,R0 ; R0 = date in internal format MOV R0,...HDR+2 ; setup date for later MOV R0,BCKPAR+50 ; setup backup date in parblk CLR ENTNUM ; initialize entry number ; ; See if run out selected records or room in backup file. ; 100$: CMP ENTNUM,SFLPAR+2 ; done all entries BHIS 500$ ; yes -> exit CMP BCKPAR+2,ALWENT ; room for another backup? BHIS 600$ ; no -> abort INC ENTNUM ; doing next entry INC BCKPAR+2 ; used up another backup slot ; ; Output header and selected record to backup file. ; MOV SFLPAR,R1 ; R1 = entry size MOV #TMPB1,R0 ; R0 = buffer CALL SFLINP ; read in next entry MOV TMPB1,R0 ; R0 = number of record associated to MOV R0,...HDR ; setup RECNUM CALL FIL.DR ; read record into memory BCS 610$ ; error -> abort ; MOV #...HDR,R0 ; R0 -> [RECNUM] [DATE] MOV #4,R1 ; R1 = header size CALL BCKOUT ; output header MOV $$FORM,R0 ; R0 -> template MOV 6(R0),R1 ; R1 = record size MOV (R0),R0 ; R0 -> record data CALL BCKOUT ; output data BR 100$ ; time for next record ; ; ; Close out backup file and exit. ; 500$: CALL BCKEND ; close out backup file JMP CON.EX ; exit time ; 600$: FATAL 610$: FATAL .SBTTL Routine - "CHECKR" ... see if have valide BACKUP file ; ; ; This routine is called to ensure that the specified BACKUP file may be used ; to backup the specified database. The routine ensures that a) the database ; and backup file DBS NAMES match and that b) the size of the DBS record ; corresponds to the size of the backup file entry. The routine also outputs ; a message to indicate how full the backup file is, and as well will issue a ; warning at 80% full and a fatal message at 99% full marks. ; ; ; Use R4 and R5 as pointers to backup file header and database template. ; CHECKR: MOV $$FORM,R5 ; R5 -> template MOV #BCKPAR,R4 ; R4 -> backup file header block ; ; Ensure that the Database name, stored as 6 letters at offset 40 in ; backup file header and in template match. ; MOV R5,R0 ; R0 -> Template MOV R4,R1 ; R1 -> Backup file header ADD #40,R0 ; R0 -> Template DBS name ADD #40,R1 ; R1 -> Back file DBS name MOV #6,R2 ; R2 = number letters in name 400$: CMPB (R0)+,(R1)+ ; ensure that the backup... BNE 6000$ ; ... file and template ... SOB R2,400$ ; ... DBS names match ; ; Ensure that backup file entries are capable of holding a database ; record and the two header words. ; MOV 6(R5),R0 ; R0 = record size ADD #4,R0 ; allow for RECNUM and DATE CMP R0,(R4) ; entry size right? BNE 6100$ ; no -> flag error ; ; ; ; Ensure that second word in header block is correctly set up in that it ; holds number of backup entries in the file! ; MOV 110(R4),R2 ; R2 = number of last backup block used DEC R2 ; R2 = number of full backup blocks used MUL #1000,R2 ; R23= number of block-bytes used ADD 112(R4),R3 ; account for bytes used in last block ADC R2 ; R23= total number of backup bytes used DIV R0,R2 ; R23= number backup entries TST R3 ; sould be integral number of entries BNE 6300$ ; remainder -> corrupted CMP R2,2(R4) ; is NUMB ENTRIES figure right? BNE 6300$ ; no -> have corruption ; ; Set up ALWENT word to hold number of entries that can fit in the ; backup file. This is needed in backup loop. ; MOV 104(R4),R2 ; R2 = total number of blocks in file DEC R2 ; R2 = number blocks available for backup MUL #1000,R2 ; R23= number bytes available for backup DIV R0,R2 ; R23= number of entries can have MOV R2,ALWENT ; set up allowed number of entries ; ; Display percentage of file that has been used up. ; MOV 2(R4),R2 ; R2 = number entries used MUL #100.,R2 ; R23= used*100 DIV ALWENT,R2 ; R23= (used)*100/(total) CNAF SSD,STRING=#7010$; % used -> buffer PRINT #7000$ ; output amount used ; ; Check for 80% and 99% fullness levels. ; CMP R2,#80. ; over 80% full? BLOS 1000$ ; no -> skip CMP R2,#99. ; over 99% full BHI 6200$ ; yes -> abort PRINT #7100$ ; tell nearly full 1000$: RETURN ; exit, all ok ; 6000$: FATAL 6100$: FATAL 6200$: FATAL 6300$: FATAL ; .NLIST BIN 7000$: .ASCII / Backup file is / 7010$: .ASCIZ /XXX% full!/ 7100$: .ASCIZ / ******* PLEASE inform System Manager immediately!/ .EVEN .LIST BIN .SBTTL Variables ; ; .PSECT $SCRTH ; open scratch area ; ====== ====== ; $$FORM: .WORD FORM$$ ; Points to database template ENTNUM: .WORD 0 ; used as loop counter ALWENT: .WORD 0 ; number allowed entries ...HDR: .WORD 0,0 ; Entry Prefix Header TMPB1: .BLKB 100 ; used as tempory buffer ; .SBTTL Module BCKFIO .SBTTL ************* ; ; This module is used to send output to the BACKUP file. The entries are ; ; BCKINT called to intialize the output stream. The backup file ; is created with the default name of BACKUP.DAT on disc ; BKP. The caller may set up the BCKNME buffer with a ; better name if desired in .ASCIZ format. ; ; BCKOUP is called to transfer R1 bytes @R0 to the file. ; ; BCKEND is called to close out the output stream. ; ; Block 0 of the file is written out by BCKEND using the data in the ; BCKPAR buffer. The user is free to use some of this block to pass important ; parameters to other programs. All BCKOUP output is appended to the file ; starting at the byte dirrectly after the last output. Locations 110!8 to ; 117!8 in the header block are reserved for use by BCKFIO, and hold the ; the following data ; ; Block 0, byte 110!8 .RAD50 /BACKUP/; idicates is a backup file ; .WORD blocks ; number blocks in file ; .RAD50 /WEN/ ; indicates file is Write enabled ; .WORD BLK ; last block written out ; .WORD CHR ; last character written out ; ; It is suggested that the user allocate the first two words in the ; header as follows ; ; Block 0 .Word SIZE ; number bytes/entry ; .Word NUMB ; number of entries ; ; to allow the SORTER interfaces to be used to access the file. .SBTTL Declarations ; ; .MCALL .PUSH,.POP ; stacking .MCALL .EXIT ; error handling .MCALL FILSPT ; file support ; FILSPT ; set up file support ; .GLOBL BCKINT,BCKOUT,BCKEND .GLOBL BCKNME,BCKPAR ; ; .MACRO FATAL MES,?A,?B PRINT #'B STATUS .EXIT B': .ASCIZ /'MES'/<15><12><'I-'@><200> .EVEN .ENDM FATAL ; ; .PSECT CODE ; open code area ; ------ ---- .SBTTL Routine - "BCKINT" ... Initialize module ; ; This routine is called to initialize the BCKFIO module. It looks up the ; file and attachs it to a FDB, and then reads in the header block into the ; BCKPAR buffer, after which it positions the output stream so that further ; output is appended at the end of the file. The Backup File Format block, ; which starts at offset 100!8 into block 0, is checked to ensure it contains ; the following data ; ; .RAD50 /BACKUP/ ; identifies as backup format file ; .WORD Numblks ; size of file in blocks ; .RAD50 /WEN/ ; indicates write enabled ; .WORD LBLK,LCHR ; number of last block/chr written ; BCKINT: PURGE #FDBBCK ; ensure channel free BIS #F.NERR,FDB.FL(R5) ; disable error messages NAME STRING=#BCKNME,EXTENS=#^RDAT,ERROR=1000$ LOOKUP ERROR=1000$ ; open file ; READ BLOCK=#0,ERROR=1200$ ; Read in header block MOV #BCKPAR+100,R4 ; R4 -> format data CMP (R4)+,#^RBAC ; is this a BACKUP file? BNE 1100$ ; no -> abort CMP (R4)+,#^RKUP ; check secong RAD50 word BNE 1100$ ; not right -> skip CMP (R4)+,FDB.NB(R5) ; correct File Size? BNE 1100$ ; no -> abort CMP (R4)+,#^RWEN ; is file Write Enable? BNE 1110$ ; no -> abort READ BLOCK=BCKPAR+110,BUFFER=#BCKOBF,ERROR=1200$ ; restore buffer RETURN ; ALL DONE ; 1000$: FATAL 1100$: FATAL 1110$: FATAL 1200$: FATAL ; ; .SBTTL Routine - "BCKEND" ... Close out BCK stream ; ; ; This routine is called when the user is finished with the ; BCK file. It empties out the contents of the output buffer ; and closes out the file. The parameter buffer is also written ; out. ; BCKEND: .PUSH R5 ; save TST BCKPAR+112 ; any characters in output buffer? BEQ 100$ ; no -> 100$ WRITE #FDBBCK,BLOCK=BCKPAR+110,BUFFER=#BCKOBF,ERROR=1000$ 100$: WRITE #FDBBCK,BLOCK=#0,BUFFER=#BCKPAR,ERROR=1000$ PURGE #FDBBCK ; purge channel .POP R5 ; restore RETURN ; ALL DONE ; 1000$: FATAL ; .SBTTL Routine - "BCKOUT" ... output R1 bytes @R0 ; ; This routine is called to transfer R1 characters from the user ; buffer @R0 to the output stream. ; BCKOUT: .PUSH ; save MOV R0,R2 ; R2 -> buffer 10$: MOVB (R2)+,R0 ; get characater CALL BCKOUC ; output it SOB R1,10$ ; loop .POP ; restore RETURN ; done ; ; .SBTTL Primitive - "BCKOUC" ... output one byte to stream ; ; ; This routine will transfer the byte passed in R0 to the ; output stream. ; BCKOUC: .PUSH ; save MOV BCKPAR+112,R4 ; R4 = num chrs in buf MOVB R0,BCKOBF(R4) ; save byte INC R4 ; one more character in buf CMP R4,#1000 ; buffer full? BLO 100$ ; no -> skip WRITE #FDBBCK,BLOCK=BCKPAR+110,BUFFER=#BCKOBF,ERROR=1000$ INC BCKPAR+110 ; bump up block number CLR R4 ; reset char counter 100$: MOV R4,BCKPAR+112 ; save count .POP ; restore RETURN ; EXIT ; ; 1000$: FATAL ; .SBTTL Data structures and variables ; ; .PSECT $$$FDB ; OPEN FILES AREA ; ------ ------ ; FDB NAME=FDBBCK,CHANNEL=13.,BUFFER=BCKPAR,SIZE=400 ; BCKPAR: .BLKW 400 ; holds BLOCK 0 of file BCKOBF: ; start of output buffer BCKNME: .ASCIZ /BKP:BACKUP.DAT/ ; default file name .BLKB 1000-<.-BCKNME> ; pad out buffer ; ; ; .ENDC ; **************************************** .IF EQ,BCKCNF-3 ; ***** want BACKUN program ******* .SBTTL Declarations ; .PRINT ; The output module contains the code for BACKUN! ; ; .MCALL .PUSH,.POP ; Stacking .MCALL CNAF ; Binary -> Ascii .MCALL .EXIT ; Abort Exit ; ; .GLOBL $$FORM ; Index for DBS support routines .GLOBL FORM$$ ; Start of database format block .GLOBL DBSLDR ; Database loader .GLOBL SFLINT,SFLINP ; entries .GLOBL SFLNME,SFLPAR ; data structures .GLOBL FILINT,FIL.DW,KEY.OT ; DBSSUP - 'FILEIO' .GLOBL CON.ST,CON.LI,CON.CO,CON.EX ; "CONIO" ; ; ; .PSECT CODE ; OPEN CODE SECTION ; ------ ---- ; .SBTTL Macro Definitions ; ; .MACRO PRINT STR=R0 .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDM PRINT ; ; .MACRO GTLIN BUF=R0,STR .IF NB,STR .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDC MOV BUF,R0 .GLOBL CON.LI CALL CON.LI .ENDM GTLIN ; ; .MACRO FATAL STR,?A,?B PRINT #'B .EXIT B': .ASCIZ |'STR'| .EVEN .ENDM FATAL ; .SBTTL INITIALIZATION SECTION ; ; ; Initialize important parameters such as buffer size and name ; of files to be used. We use the CONIO module to do I/O, so ; must initialize this first. ; START: CALL CON.ST ; initialize TTY interface PRINT #7000$ ; identify self TST $$FORM ; is template linked in? BNE 100$ ; yes -> skip GTLIN #TMPB1,#7010$ ; get template name MOV #TMPB1,R0 ; R0 -> name CALL DBSLDR ; load template MOV R0,$$FORM ; save load address in pointer 100$: GTLIN #SFLNME,#7100$ ; get name of 'BCK' file GTLIN #TMPB1,#7200$ ; request confirmation CMPB TMPB1,#'Y ; got a 'Yes'? BEQ RSTORE ; yes -> go restore JMP CON.EX ; no -> exit time ; .NLIST BIN 7000$: .ASCIZ /Backun RDM110582/ 7010$: .ASCII / DB Template: /<200> 7100$: .ASCII / Backup File: /<200> 7200$: .ASCII / Really restore database? /<200> .EVEN .LIST BIN ; .SBTTL Routine - "RSTORE" ... restore records ; ; Gain access to needed files and initialize loop counter. ; RSTORE: CALL SFLINT ; access backup file CALL FILINT ; open data base CALL CHECKR ; check that ok to continue CLR ENTNUM ; initialize entry number ; ; Exit if all entries have been processed. ; 100$: CMP ENTNUM,SFLPAR+2 ; done all entries BHIS 500$ ; yes -> exit INC ENTNUM ; doing next entry ; ; Read in [RECNUM] and [SYSDAT] header words. ; MOV #...HDR,R0 ; R0 -> [RECNUM] [DATE] MOV #4,R1 ; R1 = header size CALL SFLINP ; input header ; ; Read in record data from backup file into record buffer. ; MOV $$FORM,R0 ; R0 -> template MOV 6(R0),R1 ; R1 = record size MOV (R0),R0 ; R0 -> record data CALL SFLINP ; input data ; ; Write out record and keys to the database. ; MOV ...HDR,R0 ; R0 = record number CALL FIL.DW ; output data CALL KEY.OT ; output keys BR 100$ ; time for next record ; 500$: JMP CON.EX ; exit time ; .SBTTL Routine - "CHECKR" ... see if have valide BACKUP file ; ; ; Use R4 and R5 as pointers to backup file header and database template. ; CHECKR: MOV $$FORM,R5 ; R5 -> template MOV #SFLPAR,R4 ; R4 -> backup file header block ; ; Ensure that the Database name, stored as 6 letters at offset 40 in ; backup file header and in template match. ; MOV R5,R0 ; R0 -> Template MOV R4,R1 ; R1 -> Backup file header ADD #40,R0 ; R0 -> Template DBS name ADD #40,R1 ; R1 -> Back file DBS name MOV #6,R2 ; R2 = number letters in name 400$: CMPB (R0)+,(R1)+ ; ensure that the backup... BNE 6000$ ; ... file and template ... SOB R2,400$ ; ... DBS names match ; ; Ensure that backup file entries are capable of holding a database ; record and the two header words. ; MOV 6(R5),R0 ; R0 = record size ADD #4,R0 ; allow for RECNUM and DATE CMP R0,(R4) ; entry size right? BNE 6100$ ; no -> flag error ; ; ; ; Ensure that second word in header block is correctly set up in that it ; holds number of backup entries in the file! ; MOV 110(R4),R2 ; R2 = number of last backup block used DEC R2 ; R2 = number of full backup blocks used MUL #1000,R2 ; R23= number of block-bytes used ADD 112(R4),R3 ; account for bytes used in last block ADC R2 ; R23= total number of backup bytes used DIV R0,R2 ; R23= number backup entries TST R3 ; sould be integral number of entries BNE 6300$ ; remainder -> corrupted CMP R2,2(R4) ; is NUMB ENTRIES figure right? BNE 6300$ ; no -> have corruption RETURN ; exit, all ok ; 6000$: FATAL 6100$: FATAL 6200$: FATAL 6300$: FATAL .SBTTL Variables ; ; .PSECT $SCRTH ; open scratch area ; ====== ====== ; $$FORM: .WORD FORM$$ ; pointer to template ENTNUM: .WORD 0 ; used as loop pointer ...HDR: .WORD 0,0 ; header block TMPB1: .BLKB 40 ; used as temp buffer .ENDC ; ***************************************** .IF EQ,BCKCNF-4 ; *************** want BACKUF ************* .SBTTL Declarations ; .PRINT ; The object module contains the code for the BACKUF program ; ; .MCALL CNAF ; CNAF ; ; .GLOBL SFLINT,SFLNME,SFLPAR ; SRTFIO .GLOBL RPTINT,RPTOUC,RPTEND,RPTNME ; RPTFIO .GLOBL CON.ST,CON.LI,CON.LO,CON.EX ; CONIO ; ; .PSECT CODE ; open code area ; ====== ==== ; ; .SBTTL Macro Definitions ; .MACRO PRINT STR=R0 .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDM PRINT ; .MACRO GTLIN BUF=R0,STR .IF NB,STR .GLOBL CON.LO MOV STR,R0 CALL CON.LO .ENDC MOV BUF,R0 .GLOBL CON.LI CALL CON.LI .ENDM GTLIN ; .MACRO ASK QUEST,BUF,?A,?B,?C .GLOBL CON.LO,CON.LI MOV #'B,R0 CALL CON.LO MOV BUF',R0 CALL CON.LI BR C B': .ASCII / //'QUEST'/<200> .EVEN C': .ENDM ASK ; .SBTTL BACKUF main code ; ; ; Initialize CONIO module and obtain name of files, then open files. ; START: CALL CON.ST ; initialize TTY interface PRINT #IDMES ; identify self ASK ,#SFLNME ; setup BACKUP file name ASK ,#RPTNME ; setup FORMAT file name CALL SFLINT ; access backup file CALL RPTINT ; create output file ; ; Convert the last backup date into ascii and output command. ; CALL DATASC ; setup format command MOV #BUFFER,R1 ; R1 -> format command MOV #777,R2 ; R2 = loop counter 1000$: MOVB (R1)+,R0 ; R0 = next character CALL RPTOUC ; output char SOB R2,1000$ ; loop till done ; ; Close output file and exit. ; CALL RPTEND ; close report file JMP CON.EX ; all done ; .NLIST BIN IDMES: .ASCIZ /Backuf RDM120582/ .EVEN .LIST BIN ; .SBTTL Routine - "DATASC" ... convert date to ascii ; ; ; When called, this routine converts the last backup date, store @ offset 50 ; in the backup file into an ascii string stored in the ..DATE buffer. ; DATASC: MOV SFLPAR+50,R3 ; R3 = last backup date MOV R3,R2 ; R2 = last backup date BIC #^C31.,R2 ; R2 = day of last backup CNAF DD,STRING=#..DATE ; day -> ascii INC R1 ; skip delimiter MOV R3,R2 ; R2 = last backup date ASH #-5,R2 ; want month count in LOBits BIC #^C15.,R2 ; R2 = month of last backup CNAF ; month -> ascii INC R1 ; skip delimiter MOV R3,R2 ; R2 = last backup date ASH #-11.,R2 ; want year count in LOBits BIC #^C31.,R2 ; R2 = day of last backup ADD #72.,R2 ; convert to base 1900 CNAF DD ; year -> ascii RETURN ; ; .SBTTL Data structures ; ; ; The BUFFER string is a command that can be passed to the SELECT cusp that ; will select all records with an edit date of ..DATE or later. The ..DATE ; date is setup by the DATASC routine with the date upon which the last backup ; was performed. ; ; ; BUFFER: .ASCII /$T[ed].GE.!/ ..DATE: .ASCII /XX-XX-XX$$/<12><15> .ASCII /$L[ed]$$/<12><15> .ASCII /$E/<12><15> .REPT 1000-<.-BUFFER> .BYTE 0 .ENDR ; .ENDC ; ************************************************* ; .END START