Google
 

Trailing-Edge - PDP-10 Archives - LCG_Integration_Tools_Clearinghouse_T20_v7_30Apr86 - tools/dumperc_2/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
 * [Some Bugs fixed by David Wilson, Open University, Dec. 1985]
 * [Long file name support by Paul Hare, Open University, 29-Jan-85]
 */

#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 LENFILENAME 39	/* Maximum number of characters allowed in file name */
#define LENFILETYPE 39	/* Maximum number of characters allowed in file type */

#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")) == NULL ) {
    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")) == NULL ) {
                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 LENFILENAME characters of the
 * directory name; alpha-numeric plus periods.  If a period is encountered
 * end of first directory name and can have another LENFILENAME chars.  Then copy the
 * first LENFILENAME chars. of the file name; alpha-numeric only (ie. no quoted (^V)
 * characters).  Copy the first LENFILETYPE 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 LENFILENAME chs of dir   */
    if( j < LENFILENAME && 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 LENFILENAME chs. of file name */
    if( j < LENFILENAME && isalnum(*p) )
      *r++ = *p;
  *r++ = *p++;				/* Copy "."		     */

  for( j = 0; *p != '.'; j++, p++ )		/* First LENFILETYPE chs of file type  */
    if( j < LENFILETYPE && 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;
  rsa[0] = 0;				/* [DBW] related name not used */
  rsalen = strlen(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);
  if ( status & 1 ) esa[nam_blk.nam$b_esl] = 0; /* [DBW] mark end of string */
  return(status);
}