Trailing-Edge
-
PDP-10 Archives
-
tops20tools_v6_9-jan-86_dumper
-
tools/10backup/10backup.bas
There are 8 other files named 10backup.bas in the archive. Click here to see a list.
1 %title '10BACKUP Program To Read DECsystem 10 Backup Tapes'
%ident '10BACKUP v1.0'
!
!
!
!
! DEC-10 backup tapes contain fixed length 2720 byte records
! written in DEC-10 core dump format. This program is an attempt
! at understanding the format of these records.
!
! This program uses interchange mode (ignores Disk and UFD info)
! to read DEC-10 backup tapes. (and maybe TOPS-20 Dumper tapes.)
! Any bugs in the program must be considered 'par for course'
! as it has not yet been extensively tested. In fact the code
! for bad block recovery has probably never yet even executed.
! If you do find or fix any problems or have any suggestions then
! I would be grateful if you could let me know. My address is:-
! Paul Nankervis
! Computer Centre
! La Trobe University
! BUNDOORA, 3083
! AUSTRALIA
!
! This program is can read its tape input from an RMS file:-
!
! $ MOUNT/FOREIGN MTA0:/BLOCK=2720/RECORD=2720
! $ COPY MTA0: 10TAPE.DAT
! $ RUN 10BACKUP
! /FILE 10TAPE.DAT
! /DIR
! .....
! /REWIND
! /RESTORE
! /EXIT
! $
!
! Or the program can use QIO's to directly access the tape:-
!
! $ MOUNT/FOREIGN MSA0:
! $ RUN 10BACKUP
! /TAPE MSA0:
! /SSNAME 68SURVEY
! /DIR *.DAT,*.FOR
! .....
! /REWIND
! /RESTORE *.FOR
! /EXIT
! $
!
!
!
! The source modules that make up the 10BACKUP program are:-
!
! 10BACKUP.BAS the main line program.
! BIO.BAS contains tape and file IO routines.
! BUR.MAR is a set of macro utility routines.
! C36.MAR contains 36 bit conversion routines.
! BMS.MSG contains the error message definitions.
! 10BACKUP.RNH Runoff input to build the help library.
!
! The program can be compiled and linked in the following manner:-
!
! $ BASIC 10BACKUP
! $ BASIC BIO
! $ MACRO BUR
! $ MACRO C36
! $ MESSAGE BMS
! $ LINK/NOTRACE 10BACKUP,BIO,BUR,C36,BMS
! $ RUNOFF 10BACKUP.RNH
! $ LIBRARY/CREATE/HELP 10BACKUP 10BACKUP
!
!
!
!
! There are a couple of extensions that can be made to this program. These
! include:-
! a) Handle multi-volumes.
! b) Use VAX CLI command interface.
! c) Handle DATE-75 dates.
! d) Handle device formats other than TM10 (see module C36).
! e) Multibuffering of tape input (This program must be slow on a TU80).
! f) Write of backup tapes?
!
!
!
!
!
!
!
!
option type = explicit
!
!
! Declare error status codes:-
!
external long constant &
bms_unrecmd, bms_notape, bms_endofile, &
bms_notssblk, bms_unexpectype,bms_nofilend, &
bms_seqerr, bms_filenoeof, bms_datanofile, &
bms_eofnofile, bms_noname, bms_noattributes,&
bms_sixbitsize, bms_badrecsize, bms_checksum, &
bms_badheader, bms_badtype, ss$_normal, &
rms$_eof
!
!
! Declare external functions:-
!
external long function &
lib$get_input, bur_flag_set, bur_get_help, &
tape_init, tape_read, tape_skip_file, &
tape_rewind, tape_close, ots$cvt_ti_l
external string function &
bur_get_date, bur_get_sixbit, bur_get_ascii
!
!
!
! Set valid codes for record types (for g$type):-
!
declare integer constant &
t$lbl = 1%, &
t$beg = 2%, &
t$end = 3%, &
t$fil = 4%, &
t$ufd = 5%, &
t$eov = 6%, &
t$com = 7%, &
t$con = 8%, &
t$max = 8%
!
!
!
! Set up g$flag bit definitions:-
!
declare integer constant &
gf$eof = 0%, &
gf$rpt = 1%, &
gf$nch = 2%, &
gf$sof = 3%
!
!
!
! Set up overhead block types:-
!
declare integer constant &
o$name = 1%, &
o$file = 2%, &
o$dirt = 3%, &
o$sysn = 4%, &
o$ssnm = 5%
!
!
!
! Set up o$file block offsets:-
!
declare integer constant &
a$fhln = 1%, &
a$flgs = 2%, &
a$writ = 3%, &
a$alls = 4%, &
a$mode = 5%, &
a$leng = 6%, &
a$bsiz = 7%, &
a$vers = 8%
!
!
!
! Set up t$lbl varying word definitions:-
!
declare integer constant &
l$date = 0%, &
l$fmt = 1%, &
l$bver = 2%, &
l$mon = 3%, &
l$sver = 4%, &
l$apr = 5%, &
l$dev = 6%, &
l$mtch = 7%, &
l$rlnm = 8%, &
l$dstr = 9%
!
!
!
! Set up t$beg, t$con, and t$end varying word definitions:-
!
declare integer constant &
s$date = 0%, &
s$fmt = 1%, &
s$bver = 2%, &
s$mon = 3%, &
s$sver = 4%, &
s$apr = 5%, &
s$dev = 6%, &
s$mtch = 7%
!
!
! Map out the unpacked tape block:-
! (Each 36 bit word is stored in a quadword)
!
map (tape_block) string tape_block = 4352
map (tape_block) &
long g$type(1), &
long g$seq(1), &
long g$rtnm(1), &
long g$flag(1), &
string g$chk = 8%, &
long g$siz(1), &
long g$lnd(1), &
long g$future(3,1), &
long g$cust(1), &
long g$vary(19,1), &
long g$data(511,1)
!
!
! Map out the tape subroutine areas:-
!
map (tape_control) long tape_blocksize, long tape_status, &
word tape_iosb(3), word tape_chan, &
byte tape_mode, byte tape_marks
map (tape_buffer) string tape_buffer = 32767
!
!
! Map out file subroutine areas:-
!
map (file_control) long file_recsiz, byte file_open_flag
map (file_buffer) string file_buffer = 32763
!
!
! Declare overhead block functions:-
!
declare long function blk_locate
declare string function blk_get_text
declare &
long blk_typ, &
long blk_len
!
!
! Command loop variables:-
!
declare &
long exit_status, &
long cmd_status, &
long cmd_verb_end, &
string cmd_input, &
string cmd_verb, &
string cmd_parameters
!
!
! File selection variables:-
!
declare &
byte ss_loop_flag, &
byte fl_loop_flag, &
byte restore_flag, &
byte direct_flag, &
byte sl_restore_flag, &
byte sl_direct_flag, &
string sl_ssname, &
string sl_files, &
string sl_name, &
string sl_ext, &
long sl_sear, &
long sl_locat
!
!
! File/Save-set identification variables:-
!
declare &
string ssname, &
string fl_name, &
string fl_ext, &
long fl_size, &
string fl_date
!
!
! Read block variables:-
!
declare &
byte rd_loop_flag, &
long read_status, &
long read_save_status, &
long read_retries, &
long read_recseq, &
string read_chksum
!
!
! Name/Attribute block variables:-
!
declare &
long nm_blk, &
long nm_len, &
long fl_blk
!
!
! General variables:-
!
declare &
byte got_ss_flag, &
byte infile_flag, &
long sixbit_recsiz, &
long skip_count, &
long density(7)
!
!
! Set up density array:-
!
density(1) = 200%
density(2) = 556%
density(3) = 800%
density(4) = 1600%
density(5) = 6250%
1000 !
! Initialise everything:-
!
exit_status = ss$_normal! No errors yet.
tape_mode = -1% ! No tape device (yet).
sixbit_recsiz = 0% ! Use ascii restore mode.
sl_ssname = '' ! No particular save set.
!
!
! Now loop around executing commands:-
! (until we get an error reading one)
!
cmd_status = ss$_normal
while cmd_status and 1%
cmd_status = lib$get_input( cmd_input, "/" )
if cmd_status and 1% then
cmd_input = edit$(cmd_input,8%)
cmd_verb_end = instr(1%,cmd_input,' ')
cmd_verb_end = len(cmd_input) + 1% unless cmd_verb_end
cmd_verb = edit$(left(cmd_input,cmd_verb_end-1%),511%)
cmd_parameters = edit$(right(cmd_input,cmd_verb_end+1%),8%)
select cmd_verb
case 'DIR'
restore_flag = 0%
direct_flag = -1%
sl_files = edit$(cmd_parameters,511%)
gosub 3000
case 'RESTORE'
restore_flag = -1%
direct_flag = -1%
sl_files = edit$(cmd_parameters,511%)
gosub 3000
case 'TAPE'
cmd_status = tape_init(cmd_parameters,2%)
got_ss_flag = 0%
case 'FILE'
cmd_status = tape_init(cmd_parameters,1%)
got_ss_flag = 0%
case 'REWIND'
cmd_status = tape_rewind
got_ss_flag = 0%
case 'SKIP'
cmd_status = ots$cvt_ti_l( cmd_parameters, skip_count )
if cmd_status and 1% then
cmd_status = tape_skip_file( skip_count )
got_ss_flag = 0%
end if
case 'SSNAME'
sl_ssname = cmd_parameters
case 'HELP'
cmd_status = bur_get_help( cmd_parameters, &
"SYSPUB:10BACKUP.HLB", -1% )
case 'EXIT'
cmd_status = rms$_eof ! Set up exit status.
case 'SIXBIT'
cmd_status = ots$cvt_ti_l( cmd_parameters, sixbit_recsiz )
if cmd_status and 1% then
if sixbit_recsiz < 0% or sixbit_recsiz > 32763% then
cmd_status = bms_sixbitsize
sixbit_recsiz = 0% ! Use ASCII mode then.
end if
else
sixbit_recsiz = 0%
end if
case '' ! Ignore nothing.
case else ! What was that?
cmd_status = bms_unrecmd
end select ! Command is processed.
!
if (cmd_status and 1%) = 0% then ! Report errors.
if cmd_status <> rms$_eof then
call bur_signal( cmd_status by value )
if (exit_status and 1%) or &
(cmd_status and 7%) > (exit_status and 7%) then
exit_status = cmd_status
end if
cmd_status = ss$_normal ! Accept further commands.
end if
end if
end if
next
!
if cmd_status <> rms$_eof then ! Not eof? - then bomb.
call sys$exit(cmd_status by value) ! Command input error.
end if
!
if tape_mode = 1% or tape_mode = 2% then
call tape_close ! Finish with the tape.
end if
!
call sys$exit( exit_status by value ) ! Exit with worst status.
3000 !
!
!
! Read initial tape record, don't read when we already have a
! record - like when we found beginning of save set in a previous
! read. If the record is a label then go print it's info.
!
if tape_mode <> 1% and tape_mode <> 2% then
cmd_status = bms_notape ! No tape or file specified.
else
if got_ss_flag = 0% then ! Already have start of ss?
gosub 9000 ! Read first record then.
if read_status and 1% then
if g$type(0%) = t$lbl then
gosub 7500 ! Process t$lbl block.
else
got_ss_flag = -1% ! Assume block is ss start.
end if
end if
end if
if read_status and 1% then
gosub 3500 ! Process junk on tape.
end if
if read_status = bms_endofile then
cmd_status = ss$_normal ! Reached tape end - all OK.
else
cmd_status = read_status ! Pass back status value
end if
end if
!
return
3500 !
!
!
! Loop through all the save sets processing the ones which have
! a name matching the user specified name.
!
ss_loop_flag = 0%
until ss_loop_flag or (read_status and 1%) = 0%
if got_ss_flag = 0% then
gosub 9000 ! Get a save set block.
end if
if read_status and 1% then
if g$type(0%) = t$beg or g$type(0%) = t$con then
ssname = blk_get_text( o$ssnm, 0%, g$lnd(0%) )
if sl_ssname = '' then
gosub 4000 ! Process current save set.
else
if sl_ssname = ssname then
gosub 4000 ! Process this save set.
ss_loop_flag = -1% ! No more save sets.
else
call tape_skip_file( 1% )
got_ss_flag = 0% ! Skip to next save set.
end if
end if
else
call bur_signal( bms_notssblk by value )
end if ! Dunno what that block was.
end if
next
!
return
4000 !
!
!
! Process a save set. First dump the save set header then loop
! through the save set records handling the files it contains.
!
gosub 8000 ! Print save set info.
infile_flag = 0% ! Not yet in any file.
read_recseq = g$seq(0%) ! Set initial block sequence.
gosub 9000 ! Read first record.
got_ss_flag = 0% ! Not at start of save set now.
fl_loop_flag = 0% ! Reset loop control flag.
until fl_loop_flag or (read_status and 1%) = 0%
select g$type(0%)
case t$fil
gosub 5000 ! Check sequence number.
if read_status and 1% then
gosub 6000 ! Handle t$fil block.
gosub 9000 ! Read next block.
end if
case t$end
gosub 5000 ! Check sequence number.
if read_status and 1% then
gosub 8000 ! Handle t$end block.
end if
fl_loop_flag = -1% ! End of save set.
case t$ufd, t$com
gosub 5000 ! Check sequence number.
gosub 9000 ! Read next block.
case t$beg, t$con
got_ss_flag = -1% ! Remember we already have ss start.
fl_loop_flag = -1%
case else
call bur_signal( bms_unexpectype by value)
end select ! Who was that masked man?
next
!
if infile_flag then ! Still in file at end of save set?
if sl_restore_flag then
call file_close ! Tidy up by closing file.
end if
if read_status and 1% then ! Report error unless already have error.
call bur_signal( bms_nofilend by value )
end if
end if
!
return
5000 !
!
!
! Increment & check sequence number. If wrong sequence number
! in a save set record then something has gone wrong.
!
read_recseq = read_recseq + 1% ! Increment sequence number.
if g$seq(0%) <> read_recseq then
read_status = bms_seqerr ! Oops - can't have that.
end if
!
return
6000 !
!
!
! Handle a t$fil record. If block contains start of file then set up
! the file. Next check for any file data and finally check for end of
! file.
!
! Check for start of file.
if bur_flag_set( g$flag(0%), gf$sof by value ) then
if infile_flag then ! New file - check if expected.
call bur_signal( bms_filenoeof by value )
if sl_restore_flag then
call file_close ! Tidy up and close current file.
end if
end if
infile_flag = -1% ! We are in a new file.
gosub 7000 ! Go find file name - attributes etc.
if sl_restore_flag then ! Open output file if restoring.
call file_init( left$(fl_name,9%)+'.'+left$(fl_ext,3%) )
end if
end if
!
! Check for file data.
if g$siz(0%) > 0% then ! If data in block use it.
if infile_flag then
if sl_restore_flag then ! Write data to file.
if sixbit_recsiz <= 0% then
call bur_write_ascii( g$siz(0%), &
g$data(g$lnd(0%),0%) by ref, &
file_recsiz, file_buffer by desc )
else
call bur_write_sixbit( g$siz(0%), &
g$data(g$lnd(0%),0%) by ref, &
file_recsiz, file_buffer by desc, &
sixbit_recsiz )
end if
end if
else ! Data but no file?
call bur_signal( bms_datanofile by value )
end if
end if
!
! Check for end of file.
if bur_flag_set( g$flag(0%), gf$eof by value ) then
if infile_flag then ! File end - check we have a file.
if sl_restore_flag then
call file_close
end if
else
call bur_signal( bms_eofnofile by value )
end if ! File end but no file?
infile_flag = 0%
end if
!
return
7000 !
!
!
! Have got a t$fil record containing start of file:-
! Extract file name and attributes from block and
! see if file is to be selected.
!
nm_blk = blk_locate( o$name, 0%, g$lnd(0%) )
if nm_blk >= 0% then ! Find name block and get name.
nm_len = nm_blk + blk_len
fl_name = blk_get_text( 2%, nm_blk+1%, nm_len )
fl_ext = blk_get_text( 3%, nm_blk+1%, nm_len )
else
fl_name = '' ! Oops, no name block?
fl_ext = ''
call bur_signal( bms_noname by value )
end if
!
!
! Now see if the file is on our list of files to select:-
!
if sl_files = '' then ! Select particular files?
sl_restore_flag = restore_flag
sl_direct_flag = direct_flag ! This file is selected.
else
sl_restore_flag = 0% ! Assume we won't select file.
sl_direct_flag = 0%
sl_sear = 1% ! Start search at start.
until sl_sear > len(sl_files)
sl_locat = pos(sl_files,',',sl_sear)
sl_locat = len(sl_files)+1% unless sl_locat
sl_name = seg$(sl_files,sl_sear,sl_locat-1%)
sl_sear = pos(sl_name,'.',1%)
if sl_sear then ! If extension then extract it.
sl_ext = right$(sl_name,sl_sear+1%)
sl_name = left$(sl_name,sl_sear-1%)
else
sl_ext = '' ! No extension.
end if
sl_sear = sl_locat + 1% ! Rememeber where we got to.
if sl_name = '*' or sl_name = fl_name then
if sl_ext = '*' or sl_ext = fl_ext then
sl_restore_flag = restore_flag
sl_direct_flag = direct_flag
sl_sear = len(sl_files) + 1%
end if ! Does file match list?
end if
next ! Have decided about the file.
end if
!
!
! If file is selected for directory info then get attributes
! and print them:-
!
if sl_direct_flag then ! If directory we want attributes.
fl_blk = blk_locate( o$file, 0%, g$lnd(0%) )
if fl_blk >= 0% then ! Find attribute block and get atributes.
if g$data(fl_blk+a$mode,0%) > 1% then ! .IOASL
fl_size = ( g$data(fl_blk+a$leng,0%) + 127% ) / 128%
else
fl_size = ( g$data(fl_blk+a$leng,0%) + 639% ) / 640%
end if
fl_date = bur_get_date( g$data(fl_blk+a$writ,0%) )
else
fl_size = 0% ! Oops, no attribute block.
fl_date = ''
call bur_signal( bms_noattributes by value )
end if ! Print directory information.
print using "'LLLLLLLL.'LLLLL######### 'LLLLLLLLLLLLLLLLLLL", &
fl_name, fl_ext, fl_size, fl_date
end if
!
return
7500 !
!
!
! Got a t$lbl record. Boring. Print info if we are doing
! a directory.
!
if direct_flag then ! Report on label block.
print "Start of tape: "; bur_get_sixbit( 1%, g$vary(l$rlnm,0%) ); &
" Written at: "; bur_get_date( g$vary(l$date,0%) )
print "Device: "; bur_get_sixbit( 1%, g$vary(l$dev,0%) ); &
" Density:"; density(g$vary(l$mtch,0%) and 7%);
if g$vary(l$mtch,0%) and 16% then
print " 7-track"
else
print " 9-track"
end if
print
end if
!
return
8000 !
!
!
! Got a t$beg, t$con or t$end record. If doing a directory
! then print information.
!
if direct_flag then ! Report save set info.
print
select g$type(0%)
case t$beg
print
print "Start";
case t$con
print
print "Continuation";
case t$end
print "End";
end select
print ' of Save Set: '; ssname; &
' Written at: '; bur_get_date( g$vary(s$date,0%) )
print 'Under System: '; blk_get_text( o$sysn, 0%, g$lnd(0%) ); &
' On: '; bur_get_sixbit( 1%, g$vary(s$dev,0%) )
print "Density:"; density(g$vary(s$mtch,0%) and 7%); " Tape:";
if g$vary(s$mtch,0%) and 16% then
print " 7-track"
else
print " 9-track"
end if
print
end if
!
return
9000 !
!
!
! Read tape blocks until we get a goodun:-
! (or give up)
! This means if we get an error we should keep reading until
! we get a good block which must have its repeat block flag set.
!
rd_loop_flag = 0%
until rd_loop_flag ! Read tape ignoring repeat blocks.
gosub 9600 ! (we have read blocks OK so far)
if read_status and 1% then
if bur_flag_set( g$flag(0%), gf$rpt by value ) = 0% then
rd_loop_flag = -1% ! Not a repeat - exit.
end if
else
rd_loop_flag = -1% ! Oops, exit with error.
end if ! (now we expect a repeat block)
next
!
! Check for error.
if (read_status and 1%) = 0% then ! Have to try error recovery.
if read_status <> bms_endofile then ! End of tape is OK.
read_save_status = read_status ! Will report original error status
read_retries = 0% ! if we cannot recover.
until (read_status and 1%) or &
read_status = bms_endofile or read_retries > 4%
gosub 9600
read_retries = read_retries + 1%
next
if read_status and 1% then ! Must have repeat block after error.
if bur_flag_set( g$flag(0%), gf$rpt by value ) = 0% then
read_status = read_save_status
end if ! Report original error on failure.
end if
end if
end if
!
return
9600 !
!
!
! Get a tape block. If it has the write length we unpack it into
! quadword format and check that it seems to be OK. ie it has the
! correct checksum, its type is in range etc. If we read a tape
! mark, (good zero byte record) then ignore it and get another
! block (our higher level processing doesn't need tape marks).
!
read_status = ss$_normal ! Prepare to skip tape marks.
tape_blocksize = 0%
until (read_status and 1%) = 0% or tape_blocksize <> 0%
read_status = tape_read ! Read in a block.
if read_status and 1% then ! If OK then check it out.
if tape_blocksize = 2720% then
call c36_unpack( 544% by value, tape_buffer by ref, tape_block by ref )
if g$type(0%) >= 0% and g$type(0%) <= t$max then
if g$lnd(0%) >= 0% and g$siz(0%) >= 0% and &
g$lnd(0%)+g$siz(0%) <= 512% then
if bur_flag_set( g$flag(0%), gf$nch by value ) = 0% then
read_chksum = g$chk
g$chk = string$(8%,0%)
call c36_chksum( 544% by value, tape_block by ref, g$chk by ref )
if g$chk <> read_chksum then
read_status = bms_checksum
end if
end if
else
read_status = bms_badheader
end if ! g$lnd or g$siz is bad.
else
read_status = bms_badtype
end if ! g$type is bad.
else
if tape_blocksize <> 0% then
read_status = bms_badrecsize
end if ! Tape block size is bad.
end if
end if
next ! Loop until not a tape mark.
!
return
9800 !
!
!
! Function to get ascii text from a particular overhead block:-
! Locate the overhead block and pass its contents back as an
! ascii string.
!
def string blk_get_text( long blk_sear, long blk_beg, long blk_end )
blk_beg = blk_locate( blk_sear, blk_beg, blk_end )
if blk_beg >= 0% then ! Get text from block.
blk_get_text = bur_get_ascii( blk_len-1%, g$data(blk_beg+1%,0%) )
else
blk_get_text = '' ! Could not find block.
end if
!
end def
9900 !
!
!
! Function to locate a particular overhead block:-
! Overhead blocks contain overhead information written into
! the data area of the block. eg an o$name block.
!
def long blk_locate( long blk_sear, long blk_beg, long blk_end )
blk_locate = -1% ! Assume we won't find the block.
until blk_beg >= blk_end ! Loop until we give up.
call c36_hfwd( g$data(blk_beg,0%), blk_typ, blk_len )
if blk_typ = blk_sear then
blk_locate = blk_beg ! Found the block, say where.
blk_beg = blk_end ! Give up the search
else
if blk_len > 0% then
blk_beg = blk_beg + blk_len
else ! Step to next block.
blk_beg = blk_end
end if ! If the block is found note that we
end if ! implicitly return blk_len as the
next ! blocks length.
!
end def
9999 end