Trailing-Edge
-
PDP-10 Archives
-
tops20tools_v6_9-jan-86_dumper
-
tools/dumperc/dumper.c
There are 4 other files named dumper.c in the archive. Click here to see a list.
/*
* More or less portable version of DUMPER written for 32 bit
* machines. DUMPER is a DEC-10/20 tape reader/writer
* (This program doesn't write tapes.) used for
* backing up files and exchanging tapes with other 10/20 sites.
* This version was written on a VAX-11/780 in VAX11C.
* DUMPER.C is the only file needed to build the program.
*
* Usage:
* DUMPER tape [logfile] [-p] [-rdestination] [-sselector]
* Where:
* tape Name of the tape drive on which tape is mounted.
* -p Print file names.
* -R Destination area of the form dev:[dir], dev: or logical:.
* -s File name selection pattern for retrieval, default "*".
* Any part of the selector may be wild carded.
*
* Example run:
* $ DUMPER:==$disk:[dir]DUMPER.EXE ! Setup symbol on VAX
* $ mount mfa0:/foriegn/blocksize=25900/record=2590
* $! mount the tape. note the blocksize and recordsize parameters.
* $! recodrsize must always be 2590. Blocksize must be set to the
* $! number of records per block as specified by the dump command on
* $! the 10/20 system.
* $ dumper mfa0: tapelog.txt -p
* $! put listing of files on tape in tapelog.txt
* $ dumper mfa0: -p -rdra1:[cpm] "-s*<CPM>*"
* $! Retrieve all files in the "CPM" directory
* $ dumper mfa0: -p -rdra1:
* $! retrieve all files from tape. note: the program doesn't create
* $! directories you must do this ahead of time.
*
* Written by:
* Pieter Bowman
* James Ray Westmoreland
* Salt Lake City, Utah
*/
#include <stdio.h>
#include <ctype.h>
#define VERSION "V1.3"
typedef unsigned char BYTE;
/* definitions for tape info. */
/* Format for DEC-20 word encoded on standard DUMPER */
/* tape. (This is called CORE-DUMP.) */
/* 1 1 2 2 3 3 3 */
/* 0 7 8 5 6 3 4 1 2 5 */
/* |--------|--------|--------|--------|----| */
/* | | | | | | */
/* |--------|--------|--------|--------|----| */
#define CHKSUM 0 /* | Checksum for the record | */
#define ACCESS 1 /* | Access for the record (not used) | */
#define TAPNO 2 /* | SSNO (3 - 17) TPNO (18 - 35) | */
#define PAGNO 3 /* | FILNO (2 - 17) PGNO (18 - 35) | */
#define TYP 4 /* | -TYP record type | */
#define SEQ 5 /* | Sequence number | */
/* record type definitions */
#define DATA 0 /* File page */
#define TPHD 1 /* Tape header */
#define FLHD 2 /* File header (FDB info) */
#define FLTR 3 /* File trailer */
#define TPTR 4 /* Tape trailer (only on continued tapes) */
#define USR 5 /* Directory info (DDB) */
#define CTPH 6 /* Continued tape header */
#define FILL 7 /* Filler record */
#define FDB 134 /* Decimal word number in tape record */
/* NOTE: This is word, not byte number. */
#define NBYTES 2590 /* 518 36 bit words core dump format */
BYTE taperec[NBYTES];
FILE *ofil, /* Output file descriptor pointer */
*rfp;
int rfd; /* Restore file descriptor */
int tape; /* tape file number (returned from open) */
char *rfile, /* Pointer to partial file spec for restore */
*selectfile[10] = {
"*"}; /* Default select all files */
/* Switchs from command line */
int sfn, /* Number of files selected (Max. 10) */
prnt, /* Print file names when found */
restore, /* Restoring a file */
donearg, /* Finished current command line argument */
ascfil; /* restored file is ascii */
char rfnam[100], /* Restore file name */
fname[140], /* File name from tape */
ssname[80], /* Save set name from tape */
sstime[16]; /* Save set time from tape (after conversion) */
int bytesize, /* Byte size of current file */
bytes, /* Number of bytes (size bytesize) in file */
bytes_written=0,/* Number of bytes written to output file. */
pages, /* Number of pages (512 words) in file */
rstrcrrnt; /* Restore current file */
int ssno, /* Save set number from tape */
tpno, /* Tape number from tape */
flno, /* File number from tape */
pgno, /* Page number in file from tape */
seq, /* sequence number from tape */
oldseq, /* old seq. number last record */
rectyp; /* Record type */
main(argc, argv)
int argc;
char *argv[];
{
char *p;
char *infile = 0, /* Pointer to input file name (eg. MTA0:) */
*outfile = 0; /* & output file name (output file names...) */
int sw, flg, i, ii, fndfl; /* Misc. stuff */
fprintf(stderr,"TOPS-10/20 DUMPER-tape reader program version %s\n\n\n",VERSION);
if( argc < 2 ) {
fprintf(stderr,
"Usage: dumper tape {log} {-s(file)} {-p} {-r(file)}\n");
fprintf(stderr, "-s = select files to restore\n");
fprintf(stderr, "-p = print filenames from tape to log file\n");
fprintf(stderr, "-r = restore files & partial filename for restore\n");
fprintf(stderr, "Note: no spaces allowed between switch and file\n");
exit(1);
}
else
infile = argv[1];
if( argc > 2 )
if( argv[2][0] != '-' )
outfile = argv[2];
prnt = restore = FALSE;
sfn = 0;
for(i = 2; i < argc; i++) {
donearg = FALSE;
if(argv[i][0] == '-' ) for( ii = 1; argv[i][ii] && !donearg; ii++)
switch(argv[i][ii]) {
case 's':
case 'S':
if(sfn < 10){
selectfile[sfn++] = &argv[i][ii+1];
p = &argv[i][ii+1];
while(*p){
if(isalpha(*p)) *p = toupper(*p);
p++;
}
}
else
fprintf(stderr,"Too many select file patterns.\n");
donearg = TRUE;
break;
case 'p':
case 'P':
prnt = TRUE;
donearg = TRUE;
break;
case 'r':
case 'R':
if(!restore){
restore = TRUE;
rfile = &argv[i][ii+1];
}
else
fprintf(stderr,"Restore file area already specified.\n");
donearg = TRUE;
break;
default:
fprintf(stderr, "?Unrecognized switch \"%s\"\n",
argv[i]);
exit(1);
}
}
sfn += sfn ? 0 : 1; /* Have at least default */
if( (tape = open(infile, 0)) <= 0 ) {
fprintf(stderr, "Can't open %s\n", infile);
exit(1);
}
if( outfile==0 ) ofil = stdout;
else if( (ofil = fdopen(creat(outfile,0,"mrs=0","rfm=var","rat=cr"),"w")) <= 0 ) {
fprintf(stderr, "Can't open %s\n", outfile);
exit(1);
}
flg = TRUE;
rstrcrrnt = FALSE;
while( flg ) {
if( !rdrec() ) {
flg = FALSE;
continue;
}
switch( rectyp ) {
case DATA:
if( rstrcrrnt )
wrtrec();
break;
case TPHD:
fprintf(ofil, "DUMPER Tape %d, Volid %s, %s, %s\n\n",
tpno, infile, ssname, sstime);
fflush( ofil );
if( ofil != stdout )
printf("DUMPER Tape %d, Volid %s, %s, %s\n\n",
tpno, infile, ssname, sstime);
break;
case FLHD:
getfname();
getfsize();
fndfl = FALSE;
for(i = 0; i < sfn; i++)
if( !wild(selectfile[i], fname) )
fndfl = TRUE;
if( fndfl ) {
if( prnt )
fprintf(ofil, "%s\t%d %d(%d)\n", fname, pages,
bytes, bytesize);
if(bytesize == 36){
bytesize = 7;
bytes *= 5;
}
if(bytesize == 7) ascfil = TRUE;
if( (rstrcrrnt=restore) ) {
if( (bytesize==7 || bytesize==8)) {
makfilnam();
fprintf(ofil, "\t(as) %s", rfnam);
fflush( ofil );
if(ascfil){
if( (rfp = fdopen(creat(rfnam,0,"mrs=0","rfm=var","rat=cr"),"w")) < 0) {
fprintf(stderr, "Can't open '%s'\n", rfnam);
rstrcrrnt = FALSE;
}
}
else {
if( (rfd = creat(rfnam,0,"mrs=0","rfm=var")) < 0) {
fprintf(stderr, "Can't open '%s'\n", rfnam);
rstrcrrnt = FALSE;
}
}
}
else {
fprintf(ofil, "\tIllegal byte size.\n");
rstrcrrnt = FALSE;
}
}
}
break;
case FLTR:
if( rstrcrrnt ) {
rstrcrrnt = FALSE;
fprintf(ofil, "\t[Ok]\n");
if(ascfil){
fclose( rfp );
ascfil = FALSE;
}
else {
close( rfd );
}
bytes_written = 0;
}
break;
case TPTR:
break;
case USR:
break;
case CTPH:
break;
case FILL:
break;
default:
printf("Unknown record type %d\n", i);
break;
}
}
close(tape);
if( ofil != stdout ) fclose(ofil);
}
long int getbits(wrd, s, f)
int wrd, s, f;
{
register int j, sbyte, fbyte;
register long int i;
if( f-s > 31 ) {
fprintf(stderr, "getbits: Can't use more than 32 bits of the 36.\n");
exit(1);
}
i = 0;
sbyte = s/8;
fbyte = f/8;
for( j = sbyte; j <= fbyte; j++ )
i = (i << (j>3?4:8)) | taperec[wrd*5+j];
i >>= 7 - (f>31 ? f+4 : f) % 8;
i &= ~((unsigned long) 0) >> (31+s-f);
return( i );
}
getfname()
{
cvtasz( 06, fname, sizeof fname );
}
/* Convert from 5 7bit bytes packed in 36 bits to 5 8 bit bytes */
/* with (ASCIZ) zero (nul) termination. */
cvtasz( wrd, s, ml)
int wrd;
char *s;
int ml;
{
int b;
b = 0;
while( (*s++ = getbits( wrd+b/5, b%5*7, b%5*7+6 )) && b < ml )
b++;
}
/* Get file sizes */
getfsize()
{
bytesize = (int) getbits(FDB+011, 6, 11);
bytes = (int) getbits(FDB+012, 4, 35);
pages = (int) getbits(FDB+011, 18, 35);
}
rdrec()
{
int status;
status = read(tape, taperec, NBYTES);
if( status <= 0 )
return( FALSE );
ssno = getbits(TAPNO, 3, 17);
tpno = getbits(TAPNO, 18, 35);
flno = getbits(PAGNO, 2, 17);
pgno = getbits(PAGNO, 18, 35);
rectyp = -getbits(TYP, 4, 35);
seq = getbits(SEQ, 4, 35);
if( seq <= oldseq ) {
fprintf(stderr, "?Sequence error at record %d, continuing.\n", seq);
}
oldseq = seq;
return( TRUE );
}
wrtrec()
{
static int bcnt=0;
static char recbuf[512];
char c;
int i, j;
for(i = 6; i < 518; i++)
for(j = 0; j < 36-bytesize; j+=bytesize){
c = (BYTE)getbits(i, j, j+bytesize-1);
if(ascfil){
if(c != 015) fputc(c, rfp);
}
else {
recbuf[bcnt] = c;
if(bcnt > 508 || bytes_written >= bytes){
write(rfd, &recbuf, (bcnt<509)?bcnt:bcnt+1);
bcnt = -1;
if(bytes_written >= bytes){
bcnt = 0;
return;
}
}
bcnt++;
}
if(bytes_written >= bytes) return;
bytes_written++;
}
}
/*
* Take a 20ish filename and make it a Vaxish filename. First copy the
* structure verbatim (useless). Next copy the first 9 characters of the
* directory name; alpha-numeric plus periods. If a period is encountered
* end of first directory name and can have another 9 chars. Then copy the
* first 9 chars. of the file name; alpha-numeric only (ie. no quoted (^V)
* characters). Copy the first 3 characters of the file extension (type);
* "alnum". Lastly copy the generation number; can be as high as 262143.
*/
makfilnam()
{
char rsa[100], str[100], *strchr(), *p, *r;
int rflen, fnlen, rfnlen, rsalen, i, j;
p = fname;
r = str;
while( (*r++ = *p++) != '<' ) /* Copy structure */
;
for( j = 0; *p != '>'; j++, p++ ) /* Copy first 9 chs of dir */
if( j < 9 && isalnum(*p) )
*r++ = *p;
else
if( *p == '.' ) { /* If period we have a subdir*/
*r++ = *p; /* Move the "." */
j = 0; /* So start count over */
}
*r++ = *p++; /* Copy ">" */
for( j = 0; *p != '.'; j++, p++ ) /* First 9 chs. of file name */
if( j < 9 && isalnum(*p) )
*r++ = *p;
*r++ = *p++; /* Copy "." */
for( j = 0; *p != '.'; j++, p++ ) /* First 3 chs of file type */
if( j < 3 && isalnum(*p) )
*r++ = *p;
*r++ = *p++; /* Copy "." */
while( (*r++ = *p++) != ';' ) /* Copy until first ";" */
;
*(--r) = '\0'; /* Replace ";" with null */
rflen = strlen(rfile);
fnlen = strlen(str);
rfnlen = sizeof rfnam;
rsalen = sizeof rsa;
for(i = 0; i < rfnlen; i++) /* Clear restore file name string */
rfnam[i] = '\0';
parse(rfile, rflen, str, fnlen, rfnam, rfnlen, rsa, rsalen);
}
/*
* wild: Compare two strings:
* The first of which can contain the characters
* "*" (match any number of characters, zero or more)
* and "%" (match any single character), this is the
* wild string (ws).
* The second is a plain text string, which is
* compared to the first.
*
* This is the same sort of routine as used by
* many operating systems for wild-carded file searching.
*
* This implimentation written in "C" on a VAX-11/780
* uses a recursive algorithim to accomplish the task.
* Therefore for strings of any length the stack must be
* fairly large to avoid stack overflow problems.
*
* Author: Pieter Bowman 1 Aug 84
*/
wild( ws, s )
char *ws, *s;
{
switch( *ws ) {
case '*':
if( !wild( ws+1, s+1 ) )
return( 0 );
if( *s )
return( wild( ws, s+1 ) );
break;
default : /* Note: this "if" falls through to use */
/* the same code as the "%" wild card. */
if( *ws != *s )
break;
case '%':
if( *ws && *s )
return( wild( ws+1, s+1 ) );
break;
}
return( *ws - *s );
}
/*
* Program to accept wild card characters in input (partial) file
* specification and display full file specification.
*/
#include fab
#include nam
parse(fna, fns, dna, dns, esa, ess, rsa, rss)
char *fna, *dna, *esa, *rsa;
int fns, dns, ess, rss;
{
static struct FAB fab_blk;
static struct NAM nam_blk;
int status;
fab_blk = cc$rms_fab;
nam_blk = cc$rms_nam;
fab_blk.fab$l_fop = FAB$M_NAM;
fab_blk.fab$l_nam = &nam_blk;
fab_blk.fab$l_fna = fna;
fab_blk.fab$b_fns = fns;
fab_blk.fab$l_dna = dna;
fab_blk.fab$b_dns = dns;
nam_blk.nam$l_esa = esa;
nam_blk.nam$b_ess = ess;
nam_blk.nam$l_rsa = rsa;
nam_blk.nam$b_rss = rss;
status = SYS$PARSE(&fab_blk,0,0);
return(status);
}