;BACKUP1/ASM - Backup utility module SUBTTL '' ; SMALL EQU 0 FMT EQU 0 LF EQU 10 CR EQU 13 LOCK EQU 60H TKCAP EQU 0CCH PSWD EQU 0CEH DAT EQU 0D8H AUTO EQU 0E0H FCNT1 EQU 1111H FCNT2 EQU 1555H PASSWORD EQU 42E0H ; *GET SVCMAC:3 ;SVC Macro equivalents *GET COPYCOM:3 ;Copyright message ; ORG 2600H ; IF @MOD2 BOOTST$ DB 03H ENDIF IF @MOD4 BOOTST$ DB 9DH ;Boot step rate ptr ENDIF ; ; Data area ; FTFLG$ DB 0 SPCFLD$ DC 11,' ' MFLG$ DB 0 NEWPRM$ DW 0 OLDPRM$ DW 0 MODPRM$ DW 0 QPARM$ DW 0 BUFFER$ DW 0 FCB1$ DS 32 FCB2$ DS 32 FCB3$ DS 32 LILBUF$ EQU FCB3$ DATFLD$ DS 8 FMPAKD$ DS 2 TOPAKD$ DS 2 CLSFLG$ DS 1 ; IF @MOD2 ; SUBTTL '' ; *GET BACKUP42 ENDIF ; ; ; Normal exit - no errors ; EXIT1 LD HL,BUCAO$ ;"Backup complete... PUSH HL ;Save msg ptr CALL EXIT5 ;Ck if prompt for sys disk POP HL @@DSPLY JR EXIT ; ; Error exit ; DIRERR LD A,17 ;Init "Dir read error DB 1 ;Ignore next inst EXIT2 LD A,20H ;Init illegal drive # EXIT3 PUSH AF LD C,CR ;Terminate pending line @@DSP CALL EXIT5 ;Get system disk if needed POP AF LD L,A ;Error code to HL LD H,0 OR 0C0H ;Set short,return LD C,A ;Error to C @@ERROR ; for error dsply JR ERREXIT ; ; Abort exit ; BREAK EQU $ ABRTBU LD HL,ABRTBU$ ;"Backup aborted EXIT4 PUSH HL ;Save msg ptr CALL EXIT5 ;Get system disk if needed POP HL @@LOGOT ;Display the message LD HL,-1 ;Set error return code ERREXIT LD (RETCOD),HL EXIT EQU $ SPSAV LD SP,$-$ ;P/u the stack pointer LD HL,0 ;Set the return code RETCOD EQU $-2 @@CKBRKC ;Check and clear break @@EXIT ;Can't return from BACKUP ; ; Get system disk if needed & zero memory used ; EXIT5 EQU $ XPARM$ LD DE,0 ;P/u prompt zero drive INC E ;Ck for entry JR NZ,EXIT5A XOR A LD (SXORD+1),A CALL SYSDRV$ ;Force prompt for SYSTEM JR EXIT5B EXIT5A LD A,(SXORD+1) ; else if not entered, OR A ; ck if source & dest CALL Z,NDSYS$ ; are same - we may need EXIT5B LD DE,(BUFFER$) ; a prompt LD A,D ;Ck if we did a backup OR E RET Z ;Ret if buf adr never set LD HL,0 ; else calculate how LD B,L ; many bytes in RAM @@HIGH$ ; to zero XOR A SBC HL,DE ;Get length to zero LD B,H LD C,L ; into BC LD H,D ;Pt HL to start of buffer LD L,E INC DE LD (HL),0 ;Init 1st to zero DEC BC ; & propogate it LDIR RET ; ; Prompt for system disk ; NDSYS$ LD A,(SRCDRV$+1) ;On exit, if S=D <> 0 OR A ; then no need to prompt RET NZ SYSDRV$ LD A,0 ;P/u drive 0 indicator OR 20H ;Set bit 5 for sys test PUSH HL LD HL,PMTSYS$ ;"insert system... PUSH AF ;Save drive # LD A,(CURDSK+1) ;Save cur disk LD (TDSK),A POP AF CALL CURDSK ;get wanted disk LD A,(CURDSK+1) AND 7 ;Mask all but drive LD C,A ;Drive # to C @@GTDCT ;Get the DCT this drive LD A,(IY+4) ;Get ckdrv bit PUSH AF AND 7FH ;Mask ckdrv, force on LD (IY+4),A PUSH IY @@CKDRV POP IY ;Get back DCT POP BC ;Old info to B PUSH AF ;Save ready status LD A,B ;Old ckdrv status AND 80H OR (IY+4) LD (IY+4),A ;Restore ckdrv status POP AF ;Get ready status POP HL ;Set for return RET Z ;Back if disk in LD A,0 TDSK EQU $-1 LD (CURDSK+1),A ;Reset for proper disk JR SYSDRV$ ;Redo ; ; Prompt source disk ; SRCDRV$ LD A,0 ;Source drive OR 80H ;Set bit 7 on source PUSH HL LD HL,PMTSRC$ ;"Insert source CALL CURDSK ;Prompt for source if needed POP HL RET ; ; Prompt source disk if needed to swap ; PMTSRC LD A,(CURDSK+1) ;P/u current drive BIT 7,A ;Is source the one? JR NZ,SRCDRV$ ;Jump if it is CALL SRCDRV$ ; else prompt for it LD A,(SXORD+1) OR A RET NZ ;Ret if source <> dest CALL RESTOR ;Restore to cyl 0 PUSH BC PUSH DE ;Save registers PUSH HL LD HL,BUF3$ ;Use this for I/O buffer LD DE,0 ;Read the BOOT CALL RDSEC POP HL POP DE ;Restore the registers POP BC JP NZ,EXIT3 ;Quit on read error LD A,(BUF3$) ;P/u 1st byte of BOOT OR A ;If source, s/b 0 JR NZ,PSRC3 ;Jump if not this disk PUSH BC PUSH DE PUSH HL LD D,(IY+9) ;P/u dir cyl LD E,0 ;Pt to GAT sector LD HL,BUF3$ CALL RDSEC ;Read the GAT CP 6 JP NZ,DIRERR LD HL,BUF1$+PSWD ;Ck for match with orig LD DE,BUF3$+PSWD ; source disk LD B,10 ;Set match count PSRC1 LD A,(DE) CP (HL) JR NZ,DIFSRC ;Wrong disk if no match INC DE ;Bump pointers INC HL DJNZ PSRC1 ;Loop for 10 compares POP HL ;Was a match, POP DE ; restore and return POP BC RET DIFSRC @@DSPLY DIFSRC$ ;"wake up... POP HL ;Clean the stack POP DE POP BC PSRC3 XOR A ;Show not current disk LD (CURDSK+1),A JR PMTSRC ;Loop to re-prompt ; ; Destination disk selection ; DSTDRV$ LD A,0 ;Dest drive OR 40H ;Set dest diskette code PUSH HL LD HL,PMTDST$ ;"insert dest... CALL CURDSK POP HL RET ; ; Prompt destination if needed ; PMTDST LD A,(CURDSK+1) ;P/u current disk/drive & BIT 6,A ; ck if destination disk JR NZ,DSTDRV$ ;Jump if it is CALL DSTDRV$ ; else request swap LD A,(SXORD+1) OR A RET NZ ;Ret if source <> dest CALL RESTOR ; else restore to cyl 0 PUSH BC PUSH DE PUSH HL LD HL,BUF3$ ;Use this for I/O buffer LD DE,0 ;Pt to BOOT sector CALL RDSEC ; & read the BOOT POP HL POP DE POP BC JP NZ,EXIT3 ;Quit on read error LD A,(BUF3$) ;P/u 1st byte of BOOT CP 76H ;Dest s/b a HALT PMTDST1 RET Z PUSH HL PUSH DE @@DSPLY DIFDST$ ;"not same dest... POP DE POP HL XOR A LD (CURDSK+1),A ;Show no current diskette JR PMTDST ; and prompt again ; ; Force a prompt of the target disk ; FRCPMT LD A,C ;P/u target drive LD (CURDSK+1),A ; with code bit JR FLASH ; ; Routine to check if flashing prompt is needed ; CURDSK CP 0 ;P/u current disk JR Z,FLSH6 ;Match with wanted disk? LD (CURDSK+1),A ;No, update current SXORD LD A,0FFH ;0=src & dst drive same OR A JR NZ,FLSH6 ;Jump if source <> dest ; ; Routine to flash the prompt ; FLASH PUSH BC PUSH DE PUSH HL @@FLAGS ;IY => flag table base LD C,CR ;Write a new line @@DSP LD C,15 ;Cursor off @@DSP FLASH0 @@CKBRKC ;Check and clear break CALL RESKFLG ;Reset Pause,Enter,Break LD BC,16893 ;Delay for 1/4 sec @@PAUSE LD A,(IY+'K'-'A') AND 4!1 ;Wait for no ENTER!BRK JR NZ,FLASH0 CALL RESKFLG ;Reset in case BREAK FLS1 @@DSPLY ;Display the message LD BC,FCNT2 CALL FLS2 ;Blink start LD C,29 ;Cursor to BOL @@DSP LD C,1EH ;Cursor erase to EOL @@DSP LD BC,FCNT1 ;Wait delay count CALL FLS2 ;Wait & ck Enter or Break JR FLS1 ;Loop until Enter FLS2 @@CKBRKC ;Check for break JP NZ,BREAK ; and abort if so LD A,(IY+'K'-'A') ;P/u KFLAG settings BIT 2,A ;Enter pressed? JR NZ,FLS4 ;Go if so DEC BC ;Count down LD A,B OR C JR NZ,FLS2 ; and loop if more time RET FLS4 POP AF ;Pop return address FLS5 @@KBD ;Clear type ahead buffer JR Z,FLS5 ;Loop til no key down LD C,0DH ;Dsply a new line @@DSP LD C,14 ;Cursor on @@DSP CALL RESKFLG ;Reset Break,Enter,Pause POP HL POP DE ;Restore registers POP BC FLSH6 LD A,(CURDSK+1) ;P/u drive # AND 7 ;Strip off code bits LD C,A ;Drive # to C to @@GTDCT ; get DCT vector IF @MOD4 CALL RSELCT ;Get drive status in A ENDIF IF @MOD2 CALL SELECT ENDIF RLCA RLCA RET RESKFLG LD A,(IY+'K'-'A') ;Reset 3-bit field AND 0F8H LD (IY+'K'-'A'),A RET ; ; Drive disk I/O call setups ; TSTDRV PUSH BC XOR A ;Test for drive JR DIO1 SELECT PUSH BC LD A,1 ;Select new drive JR DIO1 RESTOR PUSH BC LD A,4 ;Restore JR DIO1 RSELCT PUSH BC LD A,7 ;Reselect JR DIO1 WRSEC PUSH BC LD A,13 ;Write sector JR DIO1 WRSYS PUSH BC LD A,14 ;Write protected JR DIO1 RDSEC PUSH BC LD A,9 ;Read sector JR DIO1 ; IF @MOD2 FMTCYL PUSH BC ;Save LD A,15 ;I/O command JR DIO1 ;Continue ENDIF ; VERSEC PUSH BC LD A,10 ;Verify sector DIO1 ADD A,40 ;Adjust for SVC LD B,A ;Save tempy LD A,(CURDSK+1) ;Get drive number AND 7 ;Strip diskette type bit LD C,A ;Load up drive register LD A,B ;Get back SVC # IF @MOD4 DI ;Interrupts off ENDIF RST 40 IF @MOD4 EI ;Interrupts on ENDIF POP BC RET ; ; Check for correct disk ; CKSWDD PUSH DE ;Save DE,BC PUSH BC LD A,(SRCDRV$+1) ;Get drive LD HL,CURDSK+1 LD C,(HL) ;Get current drive LD (HL),A ;Make curdsk our dsk LD HL,(BUFFER$) ;I/O buffer LD DE,2 ;Trk 0, sect 2 PROTSEC EQU $-2 CALL RDSEC ;Read SIS sector JR NZ,EX2 ;Quit on read error LD L,0C6H ;Set buffer posn LD A,$-$ ;Get original id byte SVCTR EQU $-1 CP (HL) ;Is it the same disk? JR NZ,EX1 ;NZ=error exit INC A JR Z,EX1 DEC A ;If id byte 0, JR Z,EX1 ; no modifying needed DEC A ; else dec remaining JR NZ,$+3 ;If now 0, make FFH DEC A LD (HL),A ;Store the new id IF @MOD2 LD L,0 ;Reset buffer ENDIF IF @MOD4 LD L,D ;Reset buffer ENDIF CALL WRSEC ;Put it back, ck error later EX1 LD A,C LD (CURDSK+1),A ;Restor orig drv # POP BC POP DE EX2 LD HL,CANTBU$ ;Go if was write error RET Z JP EXIT4 ; ; ; Message area ; DSTWP$ DB LF,'Destination disk is write ' DB 'protected',CR OLD2NEW$ DB 'Can''t move SYS files from 6.2' DB ' or earlier versions to 6.3.x',CR BADMPW$ DB 'Invalid master password',CR PMTSYS$ DB 29,30,'Insert SYSTEM disk ',3 PMTSRC$ DB 29,30,'Insert SOURCE disk ',3 PMTDST$ DB 29,30,'Insert DESTINATION disk ' DB '',3 DIFSRC$ DB 29,30,'* A L E R T * That',27H DB 's not the same source disk ',CR DIFDST$ DB 29,30,'* A L E R T * That',27H DB 's not the same destination disk ',CR CCMOD$ DB 'Source disk is write protected; ' DB 'MOD flags not updated',CR BUCAO$ DB LF,'Backup complete',CR ABRTBU$ DB LF,'Command aborted',14,CR CANTBU$ DB 'Can''t Backup - source disk write protected',LF PROT$ DB 'Disk contains protected files ',CR NEWDT DB 0 DVTEST1 DB 0 DVTEST2 DB 0 BUCORE$ DEFL $ ORG $<-8+1<+8 BUF1$ DS 256 BUF2$ DS 256 BUF3$ DS 256 PAGE OFF ; ; ; Backup entry point ; ; BACKUP @@CKBRKC JR Z,BACKUPA ;Go ahead if no break LD HL,-1 ; else abort RET ; BACKUPA LD (SPSAV+1),SP ;Save current SP PUSH HL ;Save cmdbuf @@BREAK 0 ;Remove any BREAK vector @@DSPLY HELLO$ ;Welcome @@FLAGS ;IY => flag table PUSH IY POP DE LD HL,'Y'-'A' ;Get year type locn ADD HL,DE LD (YFLAG1),HL ;Save for ckdrv CALL RESKFLG ;Reset KFLAG bits BIT 1,(IY+'C'-'A') ;Check on CMNDR active LD HL,LDOS$ JP NZ,EXIT4 ; and exit if so POP HL BCK1 LD A,(HL) ;Bypass cmdline spaces INC HL CP ' ' JR Z,BCK1 ; ; Scan for source partial spec ; LD DE,SPCFLD$ ;Pt to filespec field LD B,8 ;Init for file name CP '-' ;Exclude matches? JR NZ,BCK2 ;If '-', set flag LD (MFLG$),A LD A,(HL) ;Get next char INC HL BCK2 CALL PRSPEC ;Parse possible filename CP '.' ;Valid ext. char JR Z,BCK2A CP '/' ;File ext? JR NZ,BCK3 BCK2A LD DE,SPCFLD$+8 ;Reposn buffer ptr LD B,3 ;Init for 3 chars LD A,(HL) INC HL ;Bypass the / CALL PRSPEC ;Parse extension ; ; Determine source & destination drives ; BCK3 CP ':' ;Drive number coming? JR Z,BCK4 ;Go if so CP '('+1 ;If legal, is some term. JR C,BCK3A ;Go if ok LD A,19 ;"Illegal file name JP EXIT3 ;Quit BCK3A DEC HL ;Save possible parms PUSH HL @@DSPLY SRCNUM$ ;No drives enter, so LD HL,LILBUF$ ; prompt for them LD BC,1<8 ;1 char response @@KEYIN JP C,ABRTBU ;Quit on Break LD A,(HL) ;Get response. Restore POP HL ; command buffer. Ignore DB 0DAH ; next 2 inst with JP C, BCK4 LD A,(HL) ;P/u source drive # INC HL ;Bump to separator SUB '0' ;Adj to binary CP 8 ;Error if not in JP NC,EXIT2 ; the range <0-7> LD (SRCDRV$+1),A ;Stuff source drive BCK5 LD A,(HL) ;P/u char or separator INC HL ;Bump ptr CP ':' ;Find dest drive? JR Z,BCK6 ;Get drive # if : CP 30H ; let prepositions thru JR NC,BCK5 CP 20H ;Or a space separator JR Z,BCK5 DEC HL ;Save possible parms PUSH HL @@DSPLY DSTNUM$ ;Prompt for dest drive LD HL,LILBUF$ ;Use for keyin buffer LD BC,1<8 ;1 char only @@KEYIN JP C,ABRTBU ;Quit on Break LD A,(HL) ;Get response. Restore POP HL ; buffer. Ignore next 2 DB 0DAH ; inst with JP C,nn BCK6 LD A,(HL) ;P/u dest drive # INC HL ;Bump line ptr SUB '0' ;Adjust to binary CP 8 ;Error if not in the JP NC,EXIT2 ; range <0-7> LD (DSTDRV$+1),A ;Stuff dest drive ; LD DE,PRMTBL$ ;P/u parm table ptr PUSH DE ;Also in IX to check POP IX ; responses @@PARAM ;Get parms if any LD HL,PRMERR$ ;Init "parm error JR NZ,$EX4 ;Quit on parm error LD A,(IX+DATRSP) ;Date can only be STR AND VAL!SW ;This must be string $EX4 JP NZ,EXIT4 ;Quit if not ; ; Check on Source = Destination ; LD A,(SRCDRV$+1) ;P/u source drive LD HL,DSTDRV$+1 XOR (HL) ;Match against dest LD (SXORD+1),A ;0 if S=D, <>0 if S<>D JR NZ,DATPRM ;Bypass if source <> dest @@FLAGS ;Else test if proc BIT 5,(IY+'S'-'A') LD HL,NOINDO$ ;"can't do single... JP NZ,EXIT4 ;Abort if from ; ; Check on date entries ; DATPRM LD HL,0 ;P/u date="from-to" LD A,H OR L JR Z,CKCLAS ;Bypass if not entered LD A,(HL) ;Check for "-to" CP '-' JR Z,CKTO ;Go if no From used LD A,80H ;Set From bit LD (FTFLG$),A ;Note From entered CALL PAKDAT ;Pack the date entry LD (FMPAKD$),BC ;Save From packed date LD A,(HL) ;Ck if more in date parm CP '"' ;End of string? JR Z,FRCDAT ;Go if so CP '-' ;Check for "-to" JR NZ,CKCLAS ;Done if not CKTO INC HL ;Bypass the '-' LD A,(HL) ;Ck for end of parm CP '"' JR Z,CKCLAS ;Go if done CALL PAKDAT ;Pack To date FRCDAT LD A,(FTFLG$) ;P/u From/To flag and OR 1 ; set To bit LD (FTFLG$),A LD (TOPAKD$),BC ;Save To packed date ; ; Check on parms to force CLASS backup ; CKCLAS LD B,0 ;Init class flag SYSPRM LD DE,0 ;SYS parm used? LD A,D OR E JR Z,INVPRM ;Go if not SET 6,B ;Set 6 if SYS INVPRM LD DE,0 ;INV parm used? LD A,D OR E JR Z,CKCLA1 ;Go if not SET 3,B ;Set 3 if INV CKCLA1 LD A,B LD (CLSFLG$),A ;Store by class flag LD A,(SPCFLD$) ;Get 1st char of possible SUB ' ' ; file name LD B,A ;Save test result and LD A,(SPCFLD$+8) ; check if extension used SUB ' ' ;Ck for ext OR B ;A <> 0 if partspec LD B,A ;Hold in reg B ; ; Merge all "CLASS" parms together ; LD A,(IX+SYSRSP) ;System files OR (IX+INVRSP) ;Invisible files OR (IX+MODRSP) ;Mod flag files OR (IX+NEWRSP) ;Files not on dest OR (IX+OLDRSP) ;Files on dest OR (IX+QRSP) ;Query forces by class LD C,A ;Hold value AND VAL!STR ;Above parms only SWITCH LD HL,PRMERR$ ;Init "parm error JP NZ,EXIT4 ;Quit if not switches only OR C OR B ;Merge with partspec OR (IX+DATRSP) ;D=" mm/dd/yy-mm/dd/yy" ; ; Advise backup by class if any class parameter ; LD (CLSTST+1),A ;Set for all flags JR Z,GETDAT ;Z=may be mirror image @@LOGOT CLASS$ ; else log by class msg ; ; Recover today's date ; GETDAT LD HL,DATFLD$ ;Date storage buffer @@DATE ;Get date LD A,(DE) ;Check if date in system OR A JR NZ,GETGM ;Go if it is LD HL,NODAT$ @@LOGOT ;Show "no date" if none GETGM PUSH DE ;Save date$ PUSH HL ; and date buffer LD DE,RES$ ;See if SYS modules resident @@GTMOD ; in case needed later JR NZ,GETDAT1 ;Skip if none res'ed LD (RESLOC+1),DE ;Store the module loc ; ; Get SYS2 loaded for password hash ; GETDAT1 POP HL POP DE CALL GETSYS2 ;Get sys2 and move date ; ; Check on (X) parm for source/dest swap ; LD A,(SRCDRV$+1) ;If source is not 0, OR A ; then let PMTSRC handle JR NZ,SRCDFT OR 80H ;Set to SRC code LD C,A ;Save if needed LD A,(XPARM$+1) ;Source is drive 0, INC A ; if (X), then swap PUSH AF LD HL,PMTSRC$ CALL Z,FRCPMT ;Force prompt on (X) POP AF SRCDFT CALL NZ,SRCDRV$ ;Prompt for source CALL RESTOR ;Get set to see if a CALL CKDRV ; source disk mounted JR Z,GOTSRC ;Z=ok PUSH AF LD HL,PMTSRC$ ;Else prompt "Insert... CALL FRCPMT POP AF JR SRCDFT ; and then check again ; ; Get source disk attributes ; GOTSRC LD A,(IY+3) ;P/u 5" or 8" from AND 20H ; DCT+3, bit 5 LD (TST5_8+1),A ; and save for later CALL TSTDRV ;Ck for active DCT JP NZ,EXIT3 ; and quit if not LD HL,BUF3$ ;Disk buffer ; IF @MOD2 CALL GETPSEC ;Get prot sector JP NZ,EXIT3 ;Go on error CP 6 ;Directory? JP NZ,DIRERR ;Nope, go! ENDIF LD DE,0 ;Set to track/sector 0/0 CALL RDSEC ;Read boot JP NZ,EXIT3 ;Quit on read error LD A,(BUF3$+2) ;P/u dir track LD (IY+9),A ; & stuff in table IF @MOD2 LD DE,(PROTSEC) ;Get info sector ENDIF IF @MOD4 INC E ;Point to SYSINFO sector INC E ENDIF LD H,BUF1$<-8 ;Use this disk buffer CALL RDSEC ;Read the info sector JP NZ,EXIT3 ;Quit on read error LD A,(BUF1$+0C6H) ;Get & save id byte LD (SVCTR),A INC A JR Z,CKGAT ; ; Check write protect status ; DEC A ;Need to check? JR Z,CKGAT ;Go if not CALL RESTOR ;Start the drive CALL RSELCT ;Ck if WP OR (IY+3) ;Merge in soft WP RLCA ;Push WP to CF JR NC,CKGAT ;Bypass if not WP CANTBU LD HL,CANTBU$ JP EXIT4 ; CKGAT LD D,(IY+9) ;Directory track, LD E,0 ; sector 0 LD HL,BUF1$ CALL RDSEC ;Read GAT CP 6 ;Ensure directory cyl JP NZ,DIRERR ;Quit on any other error LD A,(BUF1$+0CDH) ;GAT type byte AND 8 ;Mask all but date type LD (DVTEST1),A ;Save for date dsply LD (DVTEST2),A ;Save for unpack routine LD (SRCTYP),A ;Save for cp to dest disk CALL TSTMPW ;Get password if needed ; ; Check if destination formatted & not protected ; LD A,(DSTDRV$+1) ;If dest is not 0, OR A ; then let DSTDRV handle JR NZ,DSTDFT OR 40H ;Set DST code LD C,A ;Save if needed LD A,(XPARM$+1) ;Dest is drive 0 INC A ;If (X), then swap PUSH AF LD HL,PMTDST$ CALL Z,FRCPMT ;Force prompt on (X) POP AF DSTDFT CALL NZ,DSTDRV$ ;Get dest drive CALL RESTOR ;Restore destination CALL RSELCT ;Test it JR NZ,PMTDD ;Might be signal from ;HD driver RLCA OR (IY+3) ;Merge in soft WP BIT 7,A ; Check on WP status LD HL,DSTWP$ ;Dest write prot... JP NZ,EXIT4 ;Jp if write protected CALL CKDRV ;Ck for disk, read GAT JR NZ,PMTDD ;Redo if not there LD A,(CKDRBUF+0CDH);GAT type byte AND 8 ;Mask all but date type RRCA LD L,A ;Save result LD A,$-$ SRCTYP EQU $-1 ;Source type OR L ;Merge the two LD (NEWDT),A ;If result=4, old to new CP 4 ;Is old to new? JR NZ,SRCTYP1 ;Go if not old to new LD A,(SYSPRM+1) ;If sys move, cant be OR A ;Old to new LD HL,OLD2NEW$ JP NZ,EXIT4 SRCTYP1 BIT 3,(IY+3) ;Hard drive? JP NZ,RECON ;Go if hard JR GOTDST ; else continue tests ; PMTDD PUSH AF ;Kludge a force of LD HL,PMTDST$ CALL FRCPMT POP AF JR DSTDFT ; the destination prompt ; ; Check 5" vs 8" for forced reconstruction ; GOTDST LD A,(IY+3) AND 20H ;See if 5/8 mismatch TST5_8 XOR 0 ;P/u source size JP NZ,RECON ;Go if different LD DE,0 CALL VERSEC ;Verify boot sector readable JR Z,CKDST ;Jump if ok ; ; Destination not formatted, abort ; LD HL,NOFMT$ ;Init "Not formatted JP EXIT4 ;Display and abort ; ; Check destination attributes ; CKDST LD HL,BUF3$ LD DE,0 ;SET for track/sector 0/0 CALL RDSEC ;Read dest boot JP NZ,EXIT3 LD A,(BUF3$+2) ;P/u its dir track LD D,A ;Set up in D LD HL,BUF2$ LD E,L ; and 0 in E CALL RDSEC ;Read dest GAT CP 6 ;Ensure a dir cyl JP NZ,DIRERR ;Quit on any other error LD HL,(BUF1$+TKCAP) ;P/u source capacity LD DE,(BUF2$+TKCAP) ;P/u dest capacity LD A,(SVCTR) ;If id byte was FF INC A JR Z,SHOPROT ; then force recon DEC A ;If id was not 0 JR NZ,TSTCAP ; then test sizes BIT 4,H ;If types differ JR Z,TSTCAP ; force reconstruct ; SHOPROT @@LOGOT PROT$ ;Show reconstruct invoked JR RECON ;Skip next tests ; TSTCAP LD A,H ;Den/sides match? XOR D ;Force Reconstruct if AND 60H ; density & sides JR NZ,RECON ; differ LD A,L ;Test # of cyls SUB E JR Z,BYCLAS ;Jump if same ; ; Cylinder count differs - question Mirror ; LD A,(CLSTST+1) ;But don't question if OR A ; Class parms already JP NZ,CLSTST ; entered CALL MIRROR ;Attempt mirror? BYCLAS JP Z,CLSTST ;Jump if mirror to be tried RECON @@LOGOT RECON$ ;"backup re-con... JP MVBYCLS ;Go do file backup ; ; Different # of tracks - Prompt for mirror ; MIRROR @@DSPLY MIRROR$ ;"Attempt mirror... LD HL,LILBUF$+1 ;Keyin buffer QM1 LD BC,3<8 ;3 chars max @@KEYIN JP C,ABRTBU ;Quit on break LD A,(HL) RES 5,A ;Convert to UC CP 'Y' ;Ret Z if Yes RET ; ; Get & check Disk master password ; TSTMPW LD HL,(BUF1$+PSWD) ;P/u src MPW LD DE,PASSWORD ;If "PASSWORD", XOR A ; don't prompt SBC HL,DE RET Z LD DE,$-$ ;P/u User entry MPWPRM EQU $-2 LD HL,PMTMPW$ ;Init "Enter MPW CALL GETMPW ;Get the user's response EX DE,HL LD HL,(BUF1$+PSWD) XOR A SBC HL,DE ;Entry match? RET Z ;Ret if MPW match LD HL,BADMPW$ ; else init "bad MPW... JP EXIT4 ;Don't do the backup ; ; Routine to parse partial filespecs & cvrt to UC ; PRSPEC CP '*' JR NZ,PS4 LD A,'$' ;Wild card char PS5 LD (DE),A ;Store it DJNZ PS5 LD A,(HL) ;P/u terminator INC HL RET PS4 CP '$' ;Wild character? JR Z,PS1 ;Always a match CP 'A' ;Filename entered? JR NC,PS1 CP '9'+1 ;Ck on 0-9 RET NC CP '0' RET C PS1 CP 'a' ;Cvrt to UC if needed JR C,$+4 RES 5,A ;Convert to upper case LD (DE),A ;Save in partspec buffer INC DE ;Bump buffer LD A,(HL) ;Get next char and INC HL ; bump string ptr DJNZ PRSPEC RET ; ; Pack user date string ; PAKDAT LD A,(HL) LD C,'/' ;Init separator CALL PARSDAT ;Parse entry JR NZ,BADFMT ;Jump on format error EX DE,HL IF @BLD631 LD A,(HL) ;<631>Is this year a leap year? CP 0CH ;<631> JR NC,LPBLW ;<631> ADD A,64H ;<631> LD (HL),A ;<631> LPBLW: AND 3 ;<631> ELSE LD A,(LILBUF$) ;Is year a leap year? AND 3 ENDIF LD HL,MAXDAYS+1 ;Set Feb to have 29 days JR NZ,$+3 ; if so INC (HL) LD A,(LILBUF$+2) ;P/u month DEC A ;Range check CP 12 JR NC,BADFMT ;Go if 0 or >12 DEC HL ;Point to Jan entry ADD A,L ;Index the month LD L,A LD A,H ADC A,0 LD H,A LD A,(LILBUF$+1) ;P/u day entry DEC A ;Reduce for test (0->FF) CP (HL) JR NC,BADFMT ;Go if too large (or 0) LD HL,LILBUF$+2 ;Pt to month LD B,(HL) LD C,0 SRL B ;Split month between RR C ; B and C DEC HL LD A,(HL) ;Get the day RLCA ;Move to bits 2-6 RLCA OR C ;Merge w/month LD C,A DEC HL ;Pt to year LD A,(HL) SUB 80 ;Make only offset JR NC,GDATE ;Ok if not < 1980 XOR A ; else use 1980 GDATE RLCA ;Move to bits 3-7 RLCA RLCA OR B ; & merge with month LD B,A EX DE,HL RET BADFMT LD HL,BADFMT$ JP EXIT4 ; ; Routine to parse DATE/TIME entry ; PARSDAT LD DE,LILBUF$+2 ;Point to buf end LD B,3 ;Process 3 fields PRSD1 PUSH DE ;Save pointer CALL PRSD2 ;Get a digit pair POP DE ;Recover pointer RET NZ ;Ret if bad digit pair LD (DE),A ; else stuff the value IF @BLD631 DEC B ;<631>Loop countdown RET Z ;<631> DEC DE ;<631>Backup the pointer ELSE DEC DE ;Backup the pointer DEC B ;Loop countdown RET Z ENDIF LD A,(HL) ;Ck for valid separator INC HL ;Bump pointer CP C ;Separator char required JR Z,PRSD1 ;Loop if match RET ;Else ret bad (NZ) ; ; Routine to parse a digit pair ; PRSD2 CALL PRS4 ;Get a digit JR NC,PRSD3 ;Jump if bad digit LD E,A ;Multiply by ten RLCA RLCA ADD A,E RLCA LD E,A CALL PRS4 ;Get another digit JR NC,PRSD3 ;Jump on bad digit ADD A,E ;Accumulate new digit LD E,A ;Save 2-digit value XOR A ;Clear flags LD A,E ;Xfer field value RET PRSD3 OR A ;Set NZ RET PRS4 LD A,(HL) ;P/u a digit & INC HL ;Convert to binary SUB 30H CP 10 ;Set CF if good RET ; ; Save PC for later use ; CORE$ DEFL $<-8+1<8 ;Set to next page ORG BACKUP ;Set for MIRROR exec MIRBU EQU CORE$ LORG MIRBU ;Load origin ; SUBTTL '' PAGE OFF ; *GET BACKUP2:3 ; DC 64,0 ;PATCH space ; MIRSIZ EQU $<-8+1<8-BACKUP ; ; ; Adjust PC & load address for CLASS ; ORG BACKUP ; CLSBU EQU CORE$+MIRSIZ LORG CLSBU ; SUBTTL '' PAGE OFF ; *GET BACKUP3:3 ; SUBTTL '' PAGE OFF ; CLSSIZ EQU $-BACKUP ; ; Establish PC for rest of BACKUP initialization ; ORG CORE$+MIRSIZ+CLSSIZ LORG $ ;No offset here ; ; Shift in Mirror or By-file module ; CLSTST LD A,0 ;Non-zero if any option OR A JP NZ,MVBYCLS ;Bypass if special LD HL,MIRBU ;Move in standard code LD DE,BACKUP LD BC,MIRSIZ LDIR JR SETBFR ; MVBYCLS LD A,(SXORD+1) ;Restrict by class OR A ; if a single drive JR NZ,MVBYC1 LD HL,CLS1DB$ ;Can't by class on 1 drv MOVNOT @@DSPLY ;Display the error JP ABRTBU ; and abort the backup ; MVBYC1 LD A,(XPARM$+1) ;By class backup requires OR A ; either non (X) or residency JR Z,MVBYC2 ; of SYS 2, 3, 10, and 12 RESLOC LD DE,$-$ ;Store location (RES$) LD A,E OR D ;Check if there LD HL,RESREQ$ ;Init "Must be resident JR Z,MOVNOT ;Error if not in use PUSH DE ;OK, it's in use, POP IX ; are all modules LD A,(IX+2*2+5) ; present and accounted OR A ;SYS2 resident? JR Z,MOVNOT LD A,(IX+3*2+5) ;Is SYS3 resident? OR A JR Z,MOVNOT LD A,(IX+10*2+5) ;Is SYS10 resident? OR A JR Z,MOVNOT LD A,(IX+12*2+5) ;Is SYS12 resident? OR A JP Z,MOVNOT MVBYC2 LD HL,CLSBU ;Move in special code LD DE,BACKUP LD BC,CLSSIZ LDIR SETBFR DEC DE ;Set the buffer INC D ; one page above the code LD E,0 LD (BUFFER$),DE ; and save starting posn JP BACKUP ; ; Routine to get password ; GETMPW CALL GMPW1 LD A,0E4H ;Get SYS2 for hash RST 28H ; GETSYS2 LD A,84H ;Load SYS2, no function RST 28H ; GMPW1 LD A,D ;Pswd entered as parm? OR E JR Z,GMPW3 ;Prompt if not LD HL,BUF3$ PUSH HL LD B,8 GMPW2 LD A,(DE) ;P/u pswd character CP CR ;At end of line? JR Z,GMPW4 ;Space out if yes CP ',' ;Comma separator? JR Z,GMPW4 CP '"' ;Closing quote? JR Z,GMPW4 INC DE LD (HL),A ;Xfer the character INC HL DJNZ GMPW2 JR GMPW5 ; ; Not entered as parm, grab from keyboard ; GMPW3 @@DSPLY ;Display request LD BC,8<8 ;Max 8 chars input LD HL,BUF3$ ;Point to buffer PUSH HL @@KEYIN ;Grab password JP C,ABRTBU ;Abort on BREAK EX DE,HL ;Buf start to DE LD H,0 ;Buf length to HL LD L,B ADD HL,DE ;Pt to 1st unused pos LD A,8 ;Calculate spaces needed SUB B JR Z,GMPW5 ;Don't put any if 8 input LD B,A ;Set space counter GMPW4 LD (HL),' ' INC HL DJNZ GMPW4 GMPW5 POP HL ;Rcvr pointer to buf PUSH HL LD B,8 ;Loop thru field GMPW6 LD A,(HL) CP 'a' JR C,GMPW7 CP 'z'+1 JR NC,GMPW7 RES 5,(HL) ;Lc -> UC GMPW7 INC HL DJNZ GMPW6 POP DE ;Rcvr pointer to start RET ; ; Check a drive for availability ; CKDRV LD A,(CURDSK+1) ;P/u drive spec LD C,A ;Place in C LD A,(IY+0) ;P/u drive vector CP 0C3H ;Ck for enabled JP NZ,CKDR5 ;Bypass if disabled PUSH HL PUSH DE LD A,(IY+6) ;Make sure the current CP (IY+5) ; cylinder count is in range JP NC,CKDRV1 ;Go if in range CALL RESTOR ;Restore drive JP NZ,CKDR7A ;Go if error ; CKDRV1 LD D,(IY+5) ;P/u current track LD E,0 ;Set for sector 0 @@SEEK ;Set track info to FDC JP NZ,CKDR7A ;Go if error CALL RSELCT ;Wait until not busy JR NZ,CKDR7A ;Not there - ret NZ BIT 3,(IY+3) ;If hard drive, bypass JR NZ,CKDR2B ; GAT data update BIT 4,(IY+4) ;If "ALIEN" by pass JR NZ,CKDR2B ; test of index pulses IF @MOD4 LD A,09 ;Set MSB of count down DI ENDIF IF @MOD2 LD A,20 ENDIF INTRON LD (CDCNT+1),A ;Store in 'LD H' instruction LD HL,0020H ;Set up count (short) ; ; Test for diskette in drive & rotating ; CKDR1 CALL INDEX ;Test index pulse JR NZ,CKDR1 ;Jump on index CDCNT LD H,00H ;CKDRV counter (long) ;Count set from above CKDR2 CALL INDEX ;Test index pulse JR Z,CKDR2 ;Jump on no index IF @MOD4 EI ;OK for INTs now ENDIF LD HL,0020H ;Index off wait (short) CKDR2A CALL INDEX JR NZ,CKDR2A ;Jump on index ; ; Diskette is rotating ; CKDR2B PUSH AF ;Save FDC status LD D,(IY+9) LD HL,CKDRBUF ;Point to HIT buffer LD E,L ;Sector 0 for GAT @@RDSSC ;Read the GAT JR NZ,CKDR7 ;Jump on error ; ; Update YFLAG$ for year type ; LD DE,(CKDRBUF+0CCH) ;Gat type byte LD A,C ;Drive # to A RLCA ;Rotate it into posn RLCA ;For SET x,(hl) RLCA ; opcode OR 0C4H ;For SET opcode BIT 3,D ;Is disk new type? JR NZ,FIXBIT ;Go if so XOR 40H ;Else make RES opcode FIXBIT LD (BIT1),A ;Save opcode LD HL,$-$ ;Pt to year type flag YFLAG1 EQU $-2 ;YFLAG$ locn DB 0CBH ;Either SET or RES BIT1 DB 0 BIT 3,(IY+3) ;If rigid drive, JR NZ,CKDR3 ; bypass the rest LD A,22H ;Add offset ADD A,E LD (IY+6),A ;Max track # to DCT RES 5,(IY+4) ;Set to side 0 BIT 5,D ;Test double sided JR Z,CKDR3 ;Jump if only single SET 5,(IY+4) ;Set for side 2 CKDR3 POP AF ;Recover FDC status CKDR3A RLCA ;Shift write prot to 7 OR (IY+3) ;Merge Soft WP bit AND 80H ;Strip all but 7 ADD A,A ;Write prot to carry flg ; CKDR4 EQU $ EI POP DE POP HL CKDR5 RET INDEX LD A,H ;Count down tries OR L JR Z,CKDR7 ;Error if counted out DEC HL ;Dec the count CALL RSELCT ;Check for index pulse BIT 1,A ;Test index RET ;Back with condition CKDR7 POP AF CKDR7A LD A,8 ;Set Device not avail OR A ;Set NZ ret JR CKDR4 ;Leave ; ; Data area ; PRMTBL$ VAL EQU 80H SW EQU 40H STR EQU 20H SGL EQU 10H DB 'S'!80H DB SW!STR!3,'MPW',0 MPWRSP EQU $-PRMTBL$-1 DW MPWPRM DB SW!STR!SGL!3,'SYS',0 SYSRSP EQU $-PRMTBL$-1 DW SYSPRM+1 DB SW!SGL!3,'INV',0 INVRSP EQU $-PRMTBL$-1 DW INVPRM+1 DB SW!SGL!3,'MOD',0 MODRSP EQU $-PRMTBL$-1 DW MODPRM$ DB SW!SGL!5,'QUERY',0 QRSP EQU $-PRMTBL$-1 DW QPARM$ DB SW!1,'X',0 XRSP EQU $-PRMTBL$-1 DW XPARM$+1 DB STR!SGL!4,'DATE',0 DATRSP EQU $-PRMTBL$-1 DW DATPRM+1 DB SW!SGL!3,'NEW',0 NEWRSP EQU $-PRMTBL$-1 DW NEWPRM$ DB SW!SGL!3,'OLD',0 OLDRSP EQU $-PRMTBL$-1 DW OLDPRM$ NOP ; NOINDO$ DB 'Single drive backup invalid during' DB ' processing',CR NOFMT$ DB 'Destination disk not formatted' DB ' - Backup aborted',CR HELLO$ DB 'BACKUP' *GET CLIENT:3 LDOS$ DB 'Command executes only from DOS Ready',CR PRMERR$ DB 'Parameter error',CR SRCNUM$ DB 'Source drive number ? ',3 DSTNUM$ DB 'Destination drive number ? ',3 NODAT$ DB 'No date established',CR CLASS$ DB 'Backup by class invoked',CR CLS1DB$ DB LF,'Single drive BACKUP invalid by files',CR IF .NOT.SMALL RES$ DB 'SYSRES' ;Terminate with LF RESREQ$ DB LF,'This backup requires residency ' DB 'of SYS''s: 2, 3, 10 & 12.',CR ENDIF IF SMALL RESREQ$ DB 'Backup by class requires the us' DB 'e of a SYSTEM diskette! ',CR ENDIF RECON$ DB 'Backup-reconstruct invoked',CR MIRROR$ DB 'Cylinder count differs - ' DB 'Attempt mirror-image backup ? ',3 PMTMPW$ DB 'Master password ? ',3 MAXDAYS DB 31,28,31,30,31,30,31,31,30,31,30,31 BADFMT$ DB 'Bad date format',CR CKDRBUF EQU $<-8+1<8 DS 256 LAST EQU $