[comp.sys.hp] Need Help Reading 9-Track Tapes written on a VAX.

scpinker@pikes.Colorado.EDU (Scott C. Pinkerton) (08/24/90)

Hello, I have recently received a 9-Track tape from some people working on a
VAX.  I am using an HP9000/375 running HP-UX 7.0, with a HP7980XC.  I've tried
a few simple approaches to read the data (ascii) off of the tape - with little
success.  I have tried frecover, tar, and cpio to read the tape but no luck
so far.  The tape included a data sheet with the following info:

Save set:		GCU.SAV
Written by:		BASCHMITT
UIC:			[000135,000001]
Date:			6-AUG-1990 08:41:49.32
Command:		BACKUP/REWIND/LOG/IGNORE=LABEL filenames $7$MUA0:GCU.SAV
Operating System:	VAX/VMS Version V5.3
BACKUP Version:		V5.3
CPU ID register:	05903B14
Node name:		_FLA2B::
Written on:		_$7$MUA0:
Block Size:		8192
Group Size:		10
Buffer count:		16

Total of 2 files, 638 blocks
End of save set


Does this provide enough info to allow some knowledgable sole to help read this
data ??  How are other people trading data between VAXes on 9-Track.  If there
is a better command to use on the VAX which allows easier reading on the HP
side that's ok too.  Does the VAX have an equivalent tar command ??

Thanks for any help!

scott pinkerton
scpinker@pikes.colorado.edu

milburn@me10.lbl.gov (John Milburn) (08/24/90)

In article <4180@pikes.Colorado.EDU> scpinker@pikes.Colorado.EDU (Scott C. Pinkerton) writes:
>Hello, I have recently received a 9-Track tape from some people working on a
>VAX.  I am using an HP9000/375 running HP-UX 7.0, with a HP7980XC.  I've tried
>a few simple approaches to read the data (ascii) off of the tape - with little
>success.  I have tried frecover, tar, and cpio to read the tape but no luck
>so far.  The tape included a data sheet with the following info:

[info deleted]

>Does this provide enough info to allow some knowledgable sole to help read
this >data ??  How are other people trading data between VAXes on 9-Track.
If there >is a better command to use on the VAX which allows easier reading
on the HP >side that's ok too.  Does the VAX have an equivalent tar command
??

The tape was made using VMS' BACKUP utility.  You have pretty much no
hope of reading this with your hpux machine, as it contains all kinds
of VMS specific file information.  Since the data you wish to read is
ascii, the sender needs to find some VMS utility to write an ascii
tape.  There is a utility called "twrite" on our VMS systems, which
allows one to write either EBCDIC or ascii tapes.  If you need to
investigate this further, I can ask our VMS folks about how this
utility can be obtained.


-jem
-- 
JEMilburn@lbl.gov  ...!ucbvax!lbl.gov!JEMilburn

mark@comp.vuw.ac.nz (Mark Davies) (08/24/90)

In article <4180@pikes.Colorado.EDU> scpinker@pikes.Colorado.EDU (Scott C. Pinkerton) writes:
>Hello, I have recently received a 9-Track tape from some people working on a
>VAX.  I am using an HP9000/375 running HP-UX 7.0, with a HP7980XC.  I've tried
>a few simple approaches to read the data (ascii) off of the tape - with little
>success.  I have tried frecover, tar, and cpio to read the tape but no luck
>so far.  The tape included a data sheet with the following info:

>Save set:		GCU.SAV
>Command:		BACKUP/REWIND/LOG/IGNORE=LABEL filenames $7$MUA0:GCU.SAV
>Operating System:	VAX/VMS Version V5.3

>Does this provide enough info to allow some knowledgable sole to help read this
>data ?? 

Yes.  The tape is written in VMS backup format.  A program to read this
format was posted to one of the sources groups a few years back.  You could
try uunet or some other archive site for it.  If you have problems locating
a copy get back to me and I'll dig around and try to find what we did with
our copy.  I've never actually built it on an HP-UX system but I wouldn't
anticipate any problems.

> How are other people trading data between VAXes on 9-Track.  If there
>is a better command to use on the VAX which allows easier reading on the HP
>side that's ok too.  Does the VAX have an equivalent tar command ??

There are several tar programs available for VMS but I don't know any
details.  Sorry, its been several years since we've had to ship files
between VMS and UNIX boxes other than over the network.

cheers
mark

mat@emcard.UUCP (W Mat Waites) (08/25/90)

In article <4180@pikes.Colorado.EDU> scpinker@pikes.Colorado.EDU (Scott C. Pinkerton) writes:
>Hello, I have recently received a 9-Track tape from some people working on a
>VAX.  I am using an HP9000/375 running HP-UX 7.0, with a HP7980XC.  I've tried
>a few simple approaches to read the data (ascii) off of the tape - with little
>success.  I have tried frecover, tar, and cpio to read the tape but no luck
>so far.
...
>Does this provide enough info to allow some knowledgable sole to help read this
>data ??  How are other people trading data between VAXes on 9-Track.  If there
>is a better command to use on the VAX which allows easier reading on the HP
>side that's ok too.  Does the VAX have an equivalent tar command ??
>scott pinkerton
>scpinker@pikes.colorado.edu


Here is a package called vmstape. We have successfully used it to load
VMS "backup" tapes.

Sorry if this is too long a posting, but I thought others might be
interested.

We're using it on a 9000/835.

Enjoy,

Mat

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  READ_ME
#	  field.c
#	  header3.c
#	  skiptm.c
#	  vmstape.c
#	  vt_append.c
#	  vt_extract.c
#	  vt_list.c
#	  vt_write.c
#	  vmstape.h
#	  vmstape.1
#
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
XCFILES	=	field.c	header3.c	skiptm.c	vmstape.c	vt_append.c \
X	vt_extract.c	vt_list.c	vt_write.c
X
XOBJECTS =	field.o	header3.o	skiptm.o	vmstape.o	vt_append.o \
X	vt_extract.o	vt_list.o	vt_write.o
X
XCMD	= vmstape
XDESTIN	= /usr/local/bin
XCFLAGS	= -O $(DEFS)
XDEFS	= -DNEWDIR
X# to compile for ver 4.2 BSD  OR any version that CANNOT emulate 
X#		the 4.2 directory structure with the files ndir.h and libndir.a:
X#	define in DEFS '-Dnewdir'.
X#	do not define '-lndir' in LIBS.
X# to compile for any version of unix WITH the 4.2 directory EMULATION package:
X# 	do not define  '-Dnewdir' in DEFS.
X#	define '-lndir' in LIBS.
XLIBS	= 
XOWNER	= 
XMODE	= 0755
X
X$(CMD)	: $(OBJECTS) /lib/libc.a 
X	ld /lib/crt0.o $(OBJECTS) -o $(CMD) $(LIBS) -lc
X
X#	ld /lib/crt0.o $(OBJECTS) -o $(CMD) $(LIBS) -lc -lg
X
Xinstall	: $(DESTIN)/$(CMD)
X
X$(DESTIN)/$(CMD) : $(CMD)
X	cp $(CMD) $(DESTIN)/$(CMD)
X	strip $(DESTIN)/$(CMD)
X	chmod $(MODE) $(DESTIN)/$(CMD)
X
Xdepend	:
X	@makedepend $(CFILES)
X
Xclean	:
X	-rm $(OBJECTS) $(CMD) 
X
Xprint	:
X	print -h $(CFILES) 
X
Xlint	:
X	lint -h $(CFILES) $(DEFS)
X
X# DO NOT DELETE THIS LINE -- make depends on it
X
Xheader3.o	: vmstape.h
X
Xskiptm.o	: /usr/include/sys/types.h /usr/include/sys/mtio.h \
X	 vmstape.h /usr/include/sys/ioctl.h
X
Xvmstape.o	: /usr/include/stdio.h vmstape.h
X
Xvt_append.o	: /usr/include/stdio.h /usr/include/sys/types.h \
X	 /usr/include/sys/stat.h /usr/include/sys/mtio.h vmstape.h \
X	/usr/include/sys/ioctl.h
X
Xvt_extract.o	: /usr/include/stdio.h /usr/include/ctype.h \
X	 /usr/include/sys/types.h /usr/include/sys/stat.h vmstape.h
X
Xvt_list.o	: vmstape.h
X
Xvt_write.o	: /usr/include/stdio.h /usr/include/sys/types.h \
X	 /usr/include/sys/stat.h /usr/include/sys/dir.h vmstape.h
SHAR_EOF
chmod 0664 Makefile || echo "restore of Makefile fails"
echo "x - extracting READ_ME (Text)"
sed 's/^X//' << 'SHAR_EOF' > READ_ME &&
XBy default, the makefile will compile the vmstape assuming
X	the new 4.2 directory structure emulation by libndir.a and ndir.h.
X
XIf these files do not exist, the makefile must be changed (as noted in the file)
X	 to add and remove definitions for the variables DEFS and LIBS.
X
X
XAuthors: Glen Dudek and Steve Kaufer
X  	 Harvard University Science Center
SHAR_EOF
chmod 0664 READ_ME || echo "restore of READ_ME fails"
echo "x - extracting field.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > field.c &&
X#define	SIZE	80
X
Xchar    *
Xfield(p, begin, end)
X	char    *p;
X	int     begin;
X	int     end;
X{
X	register        int     i;
X	register        int     j;
X	static          char    buffer[SIZE];
X
X	j = 0;
X	for(i = begin ; i <= end ; i++)
X		buffer[j++] = p[i];
X	buffer[j] = '\0';
X
X	if( j >= SIZE )
X		printf("field: buffer overflow.  j = %d\n", j);
X
X	return(buffer);
X}
SHAR_EOF
chmod 0664 field.c || echo "restore of field.c fails"
echo "x - extracting header3.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > header3.c &&
X#include "vmstape.h"
X
X/* these functions really simulate r_record, but with these names
X * make reading the code easier
X */
X
X/* is there a Header 3 area on the tape?
X */
X
Xheader3()
X{
X	char	buf[RECSIZE];
X
X	if( read(magtape, buf, RECSIZE) != 0 )
X		return(1);
X	return(0);
X}
X
Xtrailer3()
X{
X	char	buf[RECSIZE];
X
X	if( read(magtape, buf, RECSIZE) != 0 )
X		return(1);
X	return(0);
X}
SHAR_EOF
chmod 0664 header3.c || echo "restore of header3.c fails"
echo "x - extracting skiptm.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > skiptm.c &&
X#include <sys/types.h>
X#include <sys/mtio.h>
X#include <sys/ioctl.h>
X#include "vmstape.h"
X
Xskiptm(n)
X	int	n;
X{
X	struct	mtop	m;
X
X	m.mt_count	= n;
X	m.mt_op		= MTFSF;
X
X	ioctl(magtape, MTIOCTOP, &m);
X}
Xw_tapemark()
X{
X	struct	mtop	m;
X
X	m.mt_count	= 1;
X	m.mt_op		= MTWEOF;
X
X	ioctl(magtape, MTIOCTOP, &m);
X}
SHAR_EOF
chmod 0664 skiptm.c || echo "restore of skiptm.c fails"
echo "x - extracting vmstape.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > vmstape.c &&
X#include	<stdio.h>
X#include        "vmstape.h"
X
X/* NOTE -- FILES MUST BE TEXTUAL (NOT CONTAINING A NULL BYTE) */
X
X/* arguments to open system call
X */
X#define	READ	0
X#define	WRITE	1
X#define RDWT	2
X
X#define	CREATE	1
X#define	LIST	2
X#define	EXTRACT 3
X#define APPEND  4
X
Xint open_file();
X
Xmain(argc, argv)
X	int     argc;
X	char    **argv;
X{
X	register        char    *p;
X			int     function;
X			int     func_count;
X			int     mode;
X			char	device[100];
X
X	if(argc < 2) {
X		fprintf(stderr, "Usage (H = HELP): vmstape [crtxvfdbFRVH] [ filename ]\n");
X		exit(FAILURE);
X		}
X
X	strcpy(device, MAGTAPE);
X	strcpy(vol_label, VOL_LABEL);
X	blocksz = BLOCKSZ ; /* default */
X	fixreclen = FIXRECLEN; /* default */
X	func_count = 0;
X	for(p = argv[1]; *p != '\0' ; p++)
X		switch(*p) {
X			case 'H':
X				fprintf(stdout,"Help option specified. All others ignored.\n");
X				fprintf(stdout,"OPTIONS: c = create tape\n");
X				fprintf(stdout,"         r = append to tape\n");
X				fprintf(stdout,"         t = list tape\n");
X				fprintf(stdout,"         x = extract from tape specified file name\n");
X				fprintf(stdout,"         v = verbose messages\n");
X				fprintf(stdout,"         f = specify new device\n");
X				fprintf(stdout,"         d = if appending, make new section\n");
X				fprintf(stdout,"         b = specify new blocksize.(default:2048b/block.)\n");
X				fprintf(stdout,"         F = write fixed length records (non text files).\n");
X				fprintf(stdout,"         R = specify new fixed record length.(default:128b/rec.)\n");
X				fprintf(stdout,"         V = specify new volume label\n");
X				fprintf(stdout,"         H = see this help screen\n");
X				exit(FAILURE);
X			case 'R':
X		    		fixreclen = atoi(argv[2]);
X				if (fixreclen > MAXFIXRECLEN) 
X				{
X				  fprintf(stderr,"ERROR:Fixed record length cannot be greater than %d\n",MAXFIXRECLEN);
X				  exit(FAILURE);
X				}
X			        argv++;argc--;
X				/* Fall through to writing fixed length recs */;
X		    	case 'F':
X				fixed_length_flag = 1;
X				break;
X			case 'b':
X		    		blocksz = atoi(argv[2]);
X				if (blocksz > MAXBLOCKSZ) 
X				{
X				  fprintf(stderr,"ERROR:Blocksz cannot be greater than %d\n",MAXBLOCKSZ);
X				  exit(FAILURE);
X				}
X			        argv++;argc--;
X				break;
X			case 'c':
X				function = CREATE;
X				func_count++;
X				mode = WRITE;
X				break;
X
X			case 't':
X				function = LIST;
X				func_count++;
X				mode = READ;
X				break;
X
X			case 'x':
X				function = EXTRACT;
X				func_count++;
X				mode = READ;
X				break;
X
X			case 'r':
X				function = APPEND;
X				func_count++;
X				mode = RDWT;
X				break;
X
X		    	case 'd':
X			/* appending , but starting the file offset count
X			all over again so that a VMS dir command will split
X			the tape directory into sections. */
X				section_flag = 1;
X				break;
X			case 'f':
X				strcpy(device, argv[2]);
X				argv++ ; argc-- ; 
X				break;
X
X#ifdef OLD
X/* could use these for writing tapes.
X */
X			case 'B':
X				binflag = TRUE;
X				break;
X
X			case 'R':
X				rawflag = TRUE;
X				break;
X#endif
X
X			case 'V':
X				strcpy(vol_label, argv[2]);
X				argv++ ; argc--;
X				break;
X
X			case 'v':
X				verbose = TRUE;
X				break;
X
X			
X			default:
X				printf("Unknown key: %c\n", *p);
X				exit(FAILURE);
X		}
X
X	if (blocksz % fixreclen ) {
X		fprintf(stderr,"ERROR:The blocksize must be a multiple of the fixed record length.\n");
X		exit (FAILURE);
X		}
X	if(func_count == 0) {
X		fprintf(stderr,"No function specified\n");
X		exit(FAILURE);
X		}
X	if(func_count > 1) {
X		fprintf(stderr,"Too many functions specified\n");
X		exit(FAILURE);
X		}
X#ifdef OLD
X	magtape = open(device, mode);
X	if(magtape < 0) {
X		fprintf(stderr, "Cannot open %s\n", device);
X		exit(FAILURE);
X		}
X#endif
X	switch(function) {
X		case CREATE:
X			vt_create(&argv[2], device, mode);
X			break;
X
X		case LIST:
X			vt_list(device, mode);
X			break;
X
X		case EXTRACT:
X			vt_extract(&argv[2], device, mode);
X			break;
X
X		case APPEND:
X			vt_append(&argv[2], device, mode);
X			 break;
X
X		default:
X			printf("This can never happen!\n");
X			break;
X		}
X
X	close(magtape);
X	exit(SUCCESS);
X}
X
Xmake_pad_record()
X{
Xint i;
Xfor (i=0;i<MAXFIXRECLEN;i++) pad_record[i] = '^';
X}
X
Xint open_file (device, mode)
X
Xchar device[];
Xint mode;
X
X{
X	int descrip;
X
X	descrip = open(device, mode);
X	if(descrip < 0) {
X		fprintf(stderr, "Cannot open %s\n", device);
X		exit(FAILURE);
X	}
X	return (descrip);
X}
SHAR_EOF
chmod 0664 vmstape.c || echo "restore of vmstape.c fails"
echo "x - extracting vt_append.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > vt_append.c &&
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/mtio.h>
X#include <sys/ioctl.h>
X#include "vmstape.h"
X
Xint open_file();
X
Xvt_append(argv, device, mode)
X
Xchar **argv, *device;
Xint mode;
X
X{
X	char buf[RECSIZE];
X	int  i,offset;
X	int  nblocks;
X
X	if ( !(*argv) ) {
X		printf("r: no arguments??\n");
X		return;
X	}
X
X	/* open tape file */
X
X	magtape = open_file (device, mode);
X
X	/* read the volume label */
X	r_record(buf);
X
X 	offset = 1;
X	while (r_record(buf)) 
X	 {
X		++offset;	/* counting files */
X		skiptm(3);
X	 }
X
X	if (section_flag) offset = 1; /* if we want to make sections ... */
X	/* back up one tape mark */
X	backtm(); 
X
X	for(i = 0 ; argv[i] ; i++) {
X		if(verbose)
X			printf("r %s\n", argv[i]);
X		if( subdir(argv[i]) ) 
X			continue;
X		if( size0(argv[i]) )
X			continue;
X		if ( isdir(argv[i]) ) {
X		    printf("'%s' is a directory...writing all files within\n", argv[i]);
X		    w_dir(argv[i],  &offset);
X		}
X		else {
X			w_file(argv[i], offset);
X			++offset;
X		}
X	   }
X	w_tapemark();
X}
X
Xbacktm()
X{
X	int i;
X	struct mtop 	m;
X
X	m.mt_count	= 1;
X	m.mt_op		= MTBSF;
X
X	i = ioctl(magtape, MTIOCTOP, &m);
X}
SHAR_EOF
chmod 0664 vt_append.c || echo "restore of vt_append.c fails"
echo "x - extracting vt_extract.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > vt_extract.c &&
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "vmstape.h"
X
Xstatic	int	nomore = 0;
Xint open_file();
X
Xvt_extract(files, device, mode)
X
Xchar	**files, *device;
Xint mode;
X
X{
X	register        int     blocksize;
X			int     nblocks;
X			int	i;
X			char    buf[RECSIZE];
X			char    filename[RECSIZE];
X			char	recformat;
X			char	formc;
X	/* open tape file */
X
X	magtape = open_file (device, mode);
X
X	/* get volume label */
X	r_record(buf);
X
X	while( r_record(buf) ){
X		rawflag	= 0;
X		binflag	= 0;
X
X		strcpy(filename, field(buf, H1_FNAME));
X		strip(filename);
X		r_record(buf);
X		blocksize = atoi(field(buf, H2_BSZ));
X
X		/* set flags for extraction of the file.
X		 *
X		 * variable length crlf form control --> no flags set
X		 *	this is your normal text file on VMS
X		 *
X		 *	|length|record|  --> |record|'\n'
X		 *
X		 * fixed length --> binflag set
X		 *	file records extracted as is.  no interpretation
X		 *	done on blocks of file.  (ie, file is full of records
X		 *	and no information about record length).  This type
X		 *	of file is an array of records which have no control
X		 *	(record length) info).
X		 *
X		 *	|record|  --> |record|
X		 *
X		 * variable length no form control --> raw flag set
X		 *
X		 *	|length|record|  --> |length|record|
X		 */
X		recformat = *field(buf, H2_FMT);
X		fixreclen = atoi(field(buf, H2_RECLEN));
X		if( recformat == 'F' )	/* is fixed length */
X			binflag	= 1;
X		else {
X			if( recformat != 'D' ){
X				printf("UNKNOWN RECORD FORMAT <%c>\n",
X					recformat);
X				exit(FAILURE);
X				}
X			/* if recformat == 'D', then
X			 * is variable length.  set no flags */
X			}
X
X		formc	= *field(buf, H2_FORMC);
X		if( formc == 'M')
X			rawflag	= 1;	/* stuff record onto disk with
X					 * its control area defining its
X					 * length.
X					 */
X		else {
X			if( formc != ' '){
X				printf("UNKNOWN FORM CONTROL <%c>\n",
X					formc);
X				exit(FAILURE);
X				}
X			/* is the default whith crlf
X			 * stuff done at the end of each record.
X			 */
X			}
X
X		if( header3() )
X			r_tapemark();
X
X		if( isarg(filename, files) )
X			r_data(blocksize, filename, files);
X		else{
X			/* skip tape mark at end of data area and
X			 * after Trailers.
X			 */
X			skiptm(2);
X			continue;
X			}
X
X		if( nomore )	/* got all files wanted */
X			break;
X
X		/* grap Trailer areas and tape mark separating files
X		 */
X		r_record(buf);
X		r_record(buf);
X		if( trailer3() )
X			r_tapemark();
X	}
X
X	for( i=0; files[i]; i++)
X		if (files[i] != (char *)(-1))
X		    printf("'%s' not found on tape\n", files[i]);
X
X}
X
Xr_data(blksize,  filename, argv)
Xregister        int     blksize;
X		char    *filename;
X		char    **argv;
X{
X	register        int     i;
X			FILE    *outfile;
X			char	*pathname;
X
X	if(blksize > MAXBLOCKSZ) {
X		fprintf("BUFFER SIZE EXCEEDED\n");
X		exit(FAILURE);
X		}
X
X	if(exists(filename)) {
X		fprintf(stderr, "x: %s already exists.  Not extracted.\n",
X			filename);
X		while( read(magtape, databuf, blksize) > 0)
X			continue;
X		return;
X	}
X
X	outfile = fopen(filename, "w");
X	if(outfile == NULL) {
X		fprintf(stderr, "x: cannot create %s\n", filename);
X		while( read(magtape, databuf, blksize) > 0)
X			continue;
X		return;
X	}
X
X	if (verbose) printf("Extracting %s\n", filename);
X
X	while( (i = read(magtape, databuf, blksize)) > 0 )
X		ext(databuf, i, outfile);
X
X	fclose(outfile);
X}
X
Xexists(filename)
X	char    *filename;
X{
X	struct	stat	statbuf;
X
X	if( stat(filename, &statbuf) < 0 )
X		return(FALSE);
X
X	return(TRUE);
X}
X
Xext(p, blksize, outfile)
Xregister        char    *p;
X		int     blksize;
Xregister        FILE    *outfile;
X{
X	register        int     i;
X	register        int     seen;
X			int     thisline;
X			char    nbuf[5];
X			char	outbuf[MAXFIXRECLEN];
X			int	filler = 1;	
X
X/* if binflag, then global fixreclen is set to record size */
X	if(binflag) {
X	   while (blksize>0) {
X		for(i = 0 ; i < fixreclen ; i++) {
X			outbuf[i] = *p;
X			if (*p++ != FILLCHAR) filler = 0;
X			}
X		if (filler) return;  
X		filler = 1;
X		for(i = 0;i<fixreclen;i++) {	
X			putc(outbuf[i], outfile);
X			}
X		blksize -= fixreclen;
X		}
X	   }
X	else
X		for(seen = 0 ; seen < blksize ; ) {
X			for(i = 0 ; i < 4 ; i++)
X				nbuf[i] = *p++;
X			nbuf[4] = '\0';
X			seen += 4;
X			if(!isdigit(nbuf[0]))
X				break;
X			thisline = atoi(nbuf) - 4;
X
X			if(rawflag)
X				putw(thisline, outfile);
X
X			for(i = 0 ; i < thisline ; i++)
X				fputc(*p++, outfile);
X
X			seen += thisline;
X
X			if(!rawflag)
X				putc('\n', outfile);
X			}
X}
X
Xr_record(p)
X	char    *p;
X{
X	int     n_read;
X
X	n_read = read(magtape, p, RECSIZE);
X	return(n_read);
X}
X
Xisarg(str, argv)
X		char    *str;
X		char    **argv;
X{
X	int     i;
X	int	count;	/* of number left */
X	int	retval;
X
X	/* argv vector is null terminated.
X	 * if no files listed, then extract all
X	 */
X	if( !(*argv) )
X		return(1);
X
X	count	= 0;
X	retval	= 0;
X
X	for(i = 0 ; argv[i] ; i++){
X		if( argv[i] == ((char *)(-1)) )
X			continue;
X		if( streq(str, argv[i]) ) {
X			argv[i] = ((char *)(-1));
X			retval	= 1;
X			}
X		count++;
X		}
X
X	if( (!count) && (!retval) )
X		nomore	= 1;	/* all done */
X	return(retval);
X}
X
Xstrip(p)
Xregister        char    *p;
X{
X	if(*p == '\0')
X		return;
X	while(*p != '\0')
X		p++;
X	p--;
X	while(*p == ' ')
X		p--;
X	*++p = '\0';
X}
X
Xr_tapemark()
X{
X	if(read(magtape, databuf, MAXBLOCKSZ) != 0) {
X		fprintf(stderr, "MISSING TAPE MARK??\n");
X		exit(FAILURE);
X		}
X}
SHAR_EOF
chmod 0664 vt_extract.c || echo "restore of vt_extract.c fails"
echo "x - extracting vt_list.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > vt_list.c &&
X#include "vmstape.h"
X
Xint open_file();
X
Xvt_list(device, mode)
X
Xchar *device;
Xint mode;
X
X{
X	register        int     blocksize;
X	register        int     recformat;
X	register        int     formcntrl;
X			int     nblocks;
X			char    buf[RECSIZE];
X			char    filename[RECSIZE];
X			char	format[40];
X			char	formc[40];
X			int	n_read;
X			int	reclen;
X	/* open tape file */
X
X	magtape = open_file (device, mode);
X
X	/* get volume label */
X
X	r_record(buf);
X	printf("\nVolume Label: %s\n\n", field(buf, VLABEL));
X	if( verbose )
X		printf("%-20s%-15s %5s %6s %7s %7s\n",
X			"filename", "record format", "bsize",
X			"reclen", "formc", "nblocks"
X			);
X	else
X		printf("%-20s\n",
X			"filename"
X			);
X
X	while( r_record(buf) ){
X
X		strcpy(filename, field(buf, H1_FNAME));
X		strip(filename);
X
X		r_record(buf);
X		blocksize = atoi(field(buf, H2_BSZ));
X		if( blocksize > MAXBLOCKSZ ){
X			printf("blocksize %d too large for program !\n",
X				blocksize);
X			exit(-1);
X			}
X
X		recformat = *field(buf, H2_FMT);
X		if( recformat == 'D' )
X			strcpy(format,"var length");
X		else if( recformat == 'F' )
X			strcpy(format,"fixed length");
X		else
X			strcpy(format,"unknown");
X
X		reclen	= atoi(field(buf, H2_RECLEN));
X		if( recformat == 'D' )
X			reclen -= 4;	/* 4 = size of control area
X					 * of for variable length records
X					 *
X					 * the control area defines the length
X					 * of the record, including the control
X					 * area.
X					 */
X
X		formcntrl = *field(buf, H2_FORMC);
X		if( formcntrl == 'A' )
X			strcpy(formc, "fortran");
X		else if( formcntrl == 'M' )
X			strcpy(formc, "none");
X		else if( formcntrl == ' ' )
X			strcpy(formc, "crlf"); /* to be put between records */
X		else
X			strcpy(formc,"unknown");
X
X
X		if( header3() )
X			r_tapemark();
X
X		if( verbose )
X			printf("%-20s%-15s %-5d %-6d %7s ",
X				filename, format, blocksize, reclen, formc);
X		else
X			printf("%-20s\n",
X				filename);
X		nblocks = 0;
X		while( read(magtape, databuf, blocksize) > 0 )
X			nblocks++;
X
X/*
X		if (recformat == 'F') nblocks = (nblocks % (blocksize/reclen))
X						? nblocks/(blocksize/reclen)+1
X						: nblocks/(blocksize/reclen);
X*/
X				/* Because when we were reading in 
X				blocksize chunks of data, we
X				were only getting reclen size peices. */
X
X		if( verbose )
X			printf("%-7d\n", nblocks);
X
X		/* the condition that causes the exit from the while loop
X		 * reads in the tape mark after the data area
X		 */
X		r_record(buf);
X		r_record(buf);
X		if( trailer3() )
X			r_tapemark();
X	}
X}
SHAR_EOF
chmod 0664 vt_list.c || echo "restore of vt_list.c fails"
echo "x - extracting vt_write.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > vt_write.c &&
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X /* for either the old directory struct or new, but not emulation*/
X
X#include <sys/dir.h>
X
X#include "vmstape.h"
X
Xstruct dirlis {
X	char *names;	/* newline sep'd list of files */
X	int n;		/* number of files there */
X};
X
Xstruct carray {
X	char *block;	/* block w/text stored in it */
X	char **array;	/* block of pointers into above */
X	int num;	/* number of 'valid' pointers */
X};
X
Xint open_file();
X
X/* makerec assumes normal textual files
X *	note the check for zero byte means such is not valid to have
X *	in textual files.  All material following the zero byte is
X *	lost.
X *
X *	fgets has filled in the variable "in" with an asciz string
X *	and so the variable "in" is null-terminated.
X */
X
Xmakerec(in, out, max)
X	char    *in;
X	char    *out;
X{
X	register        char    *p;
X	register	int	count;
X
X	count	= 0;
X	for(p = in ; *p != '\n' ; p++){
X		count++;
X		if( count + 4> max ){  /* we need the 4 to have control info*/
X			printf("GASP!  More than %d characters in the file not seperated by a newline.\nGASP!  File Incomplete.\n",max-4);
X			return 0; /* error condition */
X			}
X		if( !(*p) )
X			break;
X		}
X
X	*p = '\0';
X	sprintf(out, "%04d%s", strlen(in) + 4, in);
X}
X
Xbflush(seen)
Xregister        int     seen;
X{
X	if(seen == 0)
X		return;
X	for( ; seen < blocksz ; seen++)
X		databuf[seen] = FILLCHAR;
X	if(write(magtape, databuf, blocksz) != blocksz) {
X		fprintf(stderr, "FATAL WRITE ERROR\n");
X		exit(FAILURE);
X		}
X	databuf[0] = '\0';              /* for strcat() */
X}
X
Xflush_blk(buf,charcount)
Xchar *buf;
Xlong charcount;
X{
X	int i;
X	if (charcount)
X		for (i = charcount;i<blocksz;i++) buf[i] = FILLCHAR;
X	if (write(magtape,buf,blocksz) != blocksz)
X	 {
X		fprintf(stderr,"FATAL WRITE ERROR\n");
X		exit (FAILURE);
X	 }
X}
X
Xvt_create(argv, device, mode)
X
Xchar    **argv, *device;
Xint mode;
X
X{
X	int     i;
X	int	offset;	/* offset for filenumbers if any arguments */
X			/* are directory names instead of just files */
X
X	if( !(*argv) ){
X		printf("c: no args?\n");
X		return;
X		};
X
X	/* open tape file */
X
X	magtape = open_file (device, mode);
X
X	w_label();	 /* volume label */
X
X	offset = 1; /* first file sequence number */
X
X	for(i = 0 ; argv[i] ; i++) {
X		if(verbose)
X			printf("c %s\n", argv[i]);
X		if( subdir(argv[i]) ) 
X			continue;
X		if( size0(argv[i]) )
X			continue;
X		if ( isdir(argv[i]) ) {
X		    printf("'%s' is a directory...writing all files within\n", argv[i]);
X		    w_dir(argv[i],  &offset);
X		}
X		else {
X			w_file(argv[i], offset);
X			++offset;
X		 }
X	   }
X	w_tapemark();
X}
X
Xw_dir(dirname,  offset)
Xchar *dirname;
Xint *offset;
X{
X	struct carray files, gath();
X	char *p, *malloc();
X	int i;
X
X	p = malloc(256);
X
X	files = gath(dirname);
X	
X	for(i = 0; i < files.num; i++) {
X	    if(*files.array[i] == '.')
X		continue;
X
X	    if(verbose)
X		printf("%s: %s\n", dirname, files.array[i]);
X
X	    strcpy(p, dirname);
X	    strcat(p, "/");
X	    strcat(p, files.array[i]);
X
X	    if ( isdir(p) ) {
X		printf("%s is a subdirectory. Not added to tape\n", p);
X		continue;
X	    }
X	    if( size0(p) )
X		continue;
X	    w_file(p, *offset );
X	    ++*offset;	/* inc file sequence number */
X	}
X}
X
Xint w_data(filename)
Xchar    *filename;
X{
X	FILE    *ioptr;
X	char    c,buf[MAXBLOCKSZ+1];
X	struct stat filestat;
X	long totalchar=0,charcount=0;
X	long nrecs;
X	int nblocks = 0;
X	int length,outcount;
X	char rec[MAXBLOCKSZ+1];
X
X	ioptr = fopen(filename, "r");
X	if(ioptr == NULL) {
X		fprintf(stderr, "Cannot open %s\n", filename);
X		}
X	else {
X
X	if (fixed_length_flag) {
X		stat(filename,&filestat);
X		nrecs = (filestat.st_size%fixreclen ) 
X					? filestat.st_size/fixreclen +1
X					: filestat.st_size/fixreclen ;
X		totalchar = fixreclen * nrecs; /*this will be an even rec size*/
X		while (charcount < totalchar)
X		 {
X			c = getc(ioptr);
X			buf[charcount++ % blocksz] = c;
X			if ((charcount % blocksz) == 0 ) flush_blk(buf,0);
X		 }
X		if ((charcount % blocksz) != 0 ) 
X				flush_blk(buf,charcount % blocksz);
X		fclose(ioptr);
X	nblocks = nrecs/(blocksz/fixreclen);
X	if (nrecs % (blocksz/fixreclen)) nblocks++;
X	}
X	else {  /* variable length records */
X
X		outcount = 0;
X		for(;;){
X			length = (int)fgets(buf, blocksz, ioptr);
X			/* scratch variable for the moment */
X
X			if(length == NULL)
X				break;
X
X			if (makerec(buf, rec, blocksz) == 0) 
X			 {
X				nblocks = 0;
X				break; /* error */
X			 }
X			length = strlen(rec);
X			if(outcount + length > blocksz) {
X				bflush(outcount);
X				nblocks++;
X				outcount = 0;
X				}
X			strcat(databuf, rec);
X			outcount += length;
X			}
X
X		if( outcount ){
X			bflush(outcount);
X			nblocks++;
X			}
X
X		fclose(ioptr);
X		}
X}
X	return(nblocks);
X}
X
X
Xw_file(path, number)
Xchar *path;
Xint number;
X{
X	int nblocks;
X	char *file, *malloc();
X
X	file = malloc(256);
X	strcpy(file, path);
X
X	while(*file != '\0' && *file !='/') file++;
X	if (*file == '\0') file = path;
X	else file++;
X	w_hdr1(file, number);
X	w_hdr2();
X	w_tapemark();
X	nblocks = w_data(path);
X	w_tapemark();
X	w_eof1(file, number, nblocks);
X	w_eof2();
X	w_tapemark();
X	if( nblocks == 0 ){
X	    fprintf(stderr,"%s caused no data area to be written on tape??\n",
X		file);
X	    w_tapemark(); /* make greaceful crash (all other files are okay )*/
X	    exit(FAILURE);
X	}
X}
X
Xw_eof1(filename, filenum, blkcount)
Xchar    *filename;
Xint     filenum;
Xint	blkcount;
X{
X	char    buf[81];
X
X	sprintf(buf,
X		"EOF1%-17s%-6s0001%04d000101%-6s%-6s %06dDECFILE11A          ",
X		filename, vol_label, filenum, CREATION, EXPIRATION, blkcount);
X
X	if(write(magtape, buf, 80) != 80) {
X		fprintf(stderr, "WRITE -- FATAL ERROR\n");
X		exit(FAILURE);
X		}
X}
X
Xw_eof2()
X{
X	char buf[82];
X	sprintf(buf,
X		 "EOF2%c%05d%05d                     %c             00                             ",(fixed_length_flag)?'F':'D',
X			blocksz,(fixed_length_flag)?fixreclen:blocksz-4,
X			(fixed_length_flag) ? 'M' : ' ');
X	if(write(magtape, buf, 80) != 80) {
X		fprintf(stderr, "WRITE -- FATAL ERROR\n");
X		exit(FAILURE);
X		}
X}
X
Xw_hdr1(filename, filenum)
X	char    *filename;
X	int     filenum;
X{
X	char    buf[81];
X	
X	sprintf(buf,
X	    "HDR1%-17s%-6s0001%04d000101%-6s%-6s 000000DECFILE11A          ",
X	    filename, vol_label, filenum, CREATION, EXPIRATION);
X
X	if(write(magtape, buf, 80) != 80) {
X		fprintf(stderr, "WRITE -- FATAL ERROR\n");
X		exit(FAILURE);
X		}
X}
X
Xw_hdr2()
X{
X	char	hdr2_label[RECSIZE];
X	int	i;
X
X	sprintf( hdr2_label, "HDR2%c%05d%05d",(fixed_length_flag)?'F':'D',blocksz,(fixed_length_flag) ? fixreclen: MAXFIXRECLEN);
X	i	= strlen(hdr2_label);
X	for( ; i<RECSIZE ; i++){
X
X		hdr2_label[i]	= ' '; /* By default */
X
X		/* Form control info */
X		if (i == 36 && (fixed_length_flag)) hdr2_label[i] = 'M';
X
X		/* buffer offset = "00" */
X		if( i == 50 || i == 51 ) hdr2_label[i]	= '0';
X
X		}
X
X	if(write(magtape, hdr2_label, RECSIZE) != RECSIZE) {
X		fprintf(stderr, "WRITE -- FATAL ERROR\n");
X		exit(FAILURE);
X		}
X}
X
Xw_label()
X{
X	char    buf[RECSIZE];
X	int	i;
X
X	sprintf(buf,"VOL1%-6s", vol_label);
X
X	i	= strlen(buf);
X	for( ; i<RECSIZE ; i++){
X
X		/* DIGITAL standard version */
X		if( i == 50 ){
X			buf[i]	= '1';
X			continue;
X			}
X
X		/* label standard version */
X		if( i == 79 ){
X			buf[i]	= '3';
X			continue;
X			}
X
X		buf[i]	= ' ';
X		}
X
X	if(write(magtape, buf, RECSIZE) != RECSIZE) {
X		fprintf(stderr, "WRITE -- FATAL ERROR\n");
X		exit(FAILURE);
X		}
X}
Xsize0(filename)
X	char	*filename;
X{
X	struct	stat	statbuf;
X
X	if( stat(filename, &statbuf) < 0 ){
X		printf("'%s' does not exist...not added to tape\n", filename);
X		return(1);
X		}
X	if( statbuf.st_size == 0 ){
X		printf("'%s' is of 0 size...skipped\n", filename);
X		return(1);
X		}
X
X	return(0);
X}
X
Xsubdir(filename)
Xchar *filename;
X{
X	register char *p;
X
X	for(p = filename; *p != '\0'; p++) 
X	    if (*p == '/') {
X		printf("File '%s' from a subdirectory...not added to tape\n", filename);
X		return(1);
X	    }
X	return(0);
X}
X	
Xisdir(file) 
Xchar *file;
X{
X	struct stat sb;
X	register int t;
X
X	stat(file, &sb);
X	t = sb.st_mode & S_IFMT;
X
X	return(t == S_IFDIR);
X}
X
X/*	DIRSIZ, to return the size of the (directory) passed it.
X *	used as an estimate for the amount of space to keep for 
X *	matches.  ERROR if longer than 16 bit's worth.
X *      From Dave Brownell's help program
X */
X
Xint dirsiz(dir) char *dir;
X{
X	struct stat entry;
X
X	if (stat(dir,&entry) == EOF) {
X		printf("Can't stat() %s\n", dir);
X		exit(1);
X	}
X	if (entry.st_size > 65000L) {	/* lazy */
X		printf("Directory exceeds 64K bytes in length\n");
X		exit(1);
X	}
X	else return((int) entry.st_size);
X}
X
X/*	NAMGET, to get the names in a directory and put them in
X *	a string, separated by newlines.  will also count the number
X *	of files. From Dave Brownell's help program.
X *	Modified to reflect 4.2 file changes as of 6/13/84. -- S.K.
X */
X
Xstruct dirlis namget(dir) char *dir;
X{	
X#ifdef OLD_DIR_STRUCT
X	struct direct entry;
X#else
X	struct direct *entry;
X	DIR *dp;
X#endif
X	struct dirlis ret;
X	register int i;
X	register char *t;
X	register FILE *file;
X	extern char *malloc();
X
X	ret.n = 0;
X
X	t = ret.names = malloc(dirsiz(dir));
X#ifdef OLD_DIR_STRUCT
X	if ((file = fopen(dir,"r")) == NULL) return (ret);
X	while (read(file,&entry,sizeof(struct direct))) {
X	    if (entry.d_ino != 0) {
X		for (i = 0 ; entry.d_name[i] != 0 && i < MAXNAMLEN ; i++)
X			*t++ = entry.d_name[i]; /* copy the name */
X		*t++ = '\n';
X		ret.n++;
X		}
X	 }
X	*t++ = '\0';
X	fclose(file);
X	return(ret);
X}
X#else
X	if ((dp = opendir(dir)) == NULL) return (ret);
X	while( entry = readdir(dp)) {
X	    if (entry->d_ino != 0) {
X		for (i = 0 ; entry->d_name[i] != 0 && i < MAXNAMLEN ; i++)
X			*t++ = entry->d_name[i]; /* copy the name */
X		*t++ = '\n';
X		ret.n++;
X	    }
X	    
X	}
X
X	*t++ = '\0';
X	closedir(dp);
X	return(ret);
X}
X#endif
X
X/*	GATH, to return an array of strings representing the names
X *	of the files in the directory.  This is not sorted.
X *	Note that a 'struct carray' has two pointers to blocks which
X *	must be free()ed.
X *	The newlines in the block returned by namget() are changed
X *	to nulls. From Dave Brownell's help program.
X */
X
Xstruct carray gath(dir) char *dir;
X{
X	struct carray ret;
X	struct dirlis names;
X	char *calloc();
X
X	names = namget(dir);
X	ret.block = names.names;
X	ret.array = (char **) calloc(names.n + 1, sizeof(char *));
X	for (ret.num = 0; ret.num < names.n; ret.num++) {
X		(ret.array)[ret.num] = names.names;
X		while (*(names.names) != '\n') (names.names)++;
X		*(names.names)++ = '\0';
X	}
X	ret.array[ret.num] = NULL;
X	return(ret);
X}
SHAR_EOF
chmod 0664 vt_write.c || echo "restore of vt_write.c fails"
echo "x - extracting vmstape.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > vmstape.h &&
X#ifndef MAXNAMLEN /* maxnamlen is defined in the new directory package, but
X			not the old.  This is our way of telling if we
X			are using the new package or not */
X#define MAXNAMLEN 14 /* This will set maxnamlen for old dir structs*/
X#define OLD_DIR_STRUCT 1 /* for compilation of proper subrs */
X#endif
X
X#define TRUE    1
X#define FALSE   0
X
X#define	streq(a,b)	(!strcmp(a,b))
X
X/* exit status codes for program
X */
X#define	SUCCESS	0
X#define	FAILURE (-1)
X
X/* #define MAGTAPE "/dev/rmt8" */
X#define MAGTAPE "/dev/rmt/0m" 
X
Xint blocksz;
X#define BLOCKSZ       2048		
X#define MAXBLOCKSZ 	2048		/* random choice */
Xint fixreclen;
X#define FIXRECLEN	128		/* should be multiple of BLOCKSZ */
X#define MAXFIXRECLEN	MAXBLOCKSZ
X
X#define	RECSIZE		80		/* size of Header and Trailer
X					 * records
X					 */
X
X/*
X * The ANSI Standard Magtape produced by a VAX looks like
X *
X *      Volume Label            80 bytes
X *      --------------------------------
X *      Header 1                80 bytes
X *      Header 2                80 bytes
X *     (Header  3)	       (80 bytes)   ... optional
X *      TAPE MARK
X *      Data Block              2048 bytes
X *      ....
X *      TAPE MARK
X *      Trailer 1               80 bytes
X *      Trailer 2               80 bytes
X *     (Trailer 3)	       (80 bytes)   ... optional
X *      TAPE MARK
X *      ---------------------------------
X *      TAPE MARK
X *
X * The information between the dashed lines is repeated for
X * every file on the tape. See appendix B of VAX-11 RMS Reference
X * for additional detailed information.
X */
X
X/* The definitions used here reflect the fact that in C, counting starts
X * at 0 and not 1
X */
X
X/*
X * fields of Volume Label
X */
X#define __XXX		0,2	/* alphabetic characters "VOL"	*/
X#define __YYY		3,3	/* numberic character "1"	*/
X#define	VLABEL		4,9
X#define	VPROT		10,10	/* protection on volume		*/
X#define	VRES1		11,36
X#define	VOWNER		37,49
X#define	VDSV		50,50	/* DIGITAL standard version	*/
X#define	VRES2		51,78
X#define	VLSV		79,79	/* Label standard version	*/
X
X/*
X * fields of Header 1
X */
X#define	__AAA		0,2	/* alphabetic characters "HDR"	*/
X#define __BBB		3,3	/* numeric character "1"	*/
X#define H1_FNAME        4, 20	/* filename			*/
X#define __CCC		21,26	/* file set identifier		*/
X#define __DDD		27,30	/* file section number		*/
X#define	__EEE		31,34	/* file sequence number		*/
X#define __FFF		35,38	/* generation number		*/
X#define	__GGG		39,40	/* generation version		*/
X#define	H1_CDATE	41,46	/* creation date		*/
X#define	H1_XDATE	47,52	/* expiration date		*/
X#define	H1_ACCESS	53,53	/* access security		*/
X#define	H1_BCOUNT	54,59	/* block count (always 0)	*/
X#define	H1_SYSTEM	60,72	/* system that produced it	*/
X#define __HHH		73,79	/* reserved			*/
X
X/*
X * fields of Header 2
X */
X#define	__III		0,2	/* alphabetic characters "HDR"	*/
X#define	__JJJ		3,3	/* numeric character "2"	*/
X#define	H2_FMT		4,4	/* record format		*/
X#define	H2_BSZ		5,9	/* # characters per block	*/
X#define	H2_RECLEN	10,14	/* record length for fixed length records */
X#define	__KKK		15,35	/* system dependent info	*/
X#define	H2_FORMC	36,36	/* form control
X				 *	'A' : first byte of record contains
X				 *		fortran control characters
X				 *	'M' : record contains all form control
X				 *		info
X				 *	' ' : lf/cr to be inserted between
X				 *		records.
X				 */
X#define	__LLL		37,49	/* system dependent info	*/
X#define	__MMM		50,51	/* buffer offset = "00"		*/
X#define	__NNN		52,79	/* reserved			*/
X
X/*
X * fields of Header 3
X */
X#define	__OOO		0,2	/* alphabetic characters "HDR"	*/
X#define	__PPP		3,3	/* numeric character "3"	*/
X#define	__QQQ		4,67	/* FILES-11 attributes if made on VMS system */
X#define	__RRR		68,79	/* system dependent info. spaces for VMS */
X
X/*
X * DEFINITIONS FOR WRITING TAPES
X */
X
X#define VOL_LABEL       "UNIX"		/* default volume label */
X#define CREATION        " 70001"        /* Julian date: yyddd */
X#define EXPIRATION      " 99365"        /* Julian date: yyddd */
X#define FILLCHAR        '^'
X
Xint     magtape;
X
Xchar    databuf[MAXBLOCKSZ+1];
Xchar	vol_label[80];
X
X
X 
X
X/*
X * These flags represent which operation is to be performed
X */
X
Xint     createflag;             /* Create a new tape            */
Xint     listflag;               /* List the tape contents       */
Xint     extractflag;            /* Extract the files from tape  */
X
X/*
X * These flags represent modifiers to the basic operations
X */
X
Xint     rawflag;
Xint     binflag;
Xint	verbose;
Xint 	fixed_length_flag;
Xint 	section_flag;
X
Xchar    *field();
X
Xchar pad_record[MAXFIXRECLEN];
SHAR_EOF
chmod 0664 vmstape.h || echo "restore of vmstape.h fails"
echo "x - extracting vmstape.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > vmstape.1 &&
X.TH VMSTAPE 1H
X.SH NAME
Xvmstape \- manipulate tapes in accordance with VAX-VMS standards
X.SH SYNOPSIS
Xvmstape [tcxrvfbdFRHV] [files]
X.SH DESCRIPTION
X.LP
X.I Vmstape
Xis a program that manipulates the tape format that is the standard for
XVMS systems.  The format is based on the ANSI standard for tapes.  The
Xswitches to the
X.I vmstape
Xprogram are as similar to the switches for
X.I tar
Xas possible.
X.SH SWITCHES
X.LP
X.I c
Xis used to
X.I create
Xa new tape with the named files on it.
XAll old information on the tape is overwritten.
X.LP
X.I r
Xappends the named files to the end of the tape. All old information
Xis unchanged on the tape.
X.LP
XIf a directory name is passed as an argument to the 
X.I c
Xor
X.I r
Xswitches, all the files in the directory will be written on the tape.
X.LP
X.I t
Xreports a directory listing of the files on the tape.
X.LP
X.I x extracts 
Xthe named files from the tape.  If no individual files are
Xspecified, then all files are extracted from the tape.
X.LP
XAll other switches are modifiers to these basic commands.  Not all modifiers
Xare applicable to all the commands.
X.LP
X.I v
Xcauses a
X.I verbose
Xoutput describing the programs actions on the tape.
X.LP
X.I f
Xis used to specify an alternate magtape device.  The default
Xassumes the tape is 1600 bpi density and will rewind the tape when the
Xprogram is done.
X.LP
X.I d
Xdivides the tape into sections so that the VMS "directory" command will
Xlist the tape in sections.  This is useful when writing subdirectories in
XUNIX.
X.LP
X.I b
Xis used to change the default block size to the length specified.
X.LP
X.I V
Xis used to specify an alternate volume label.
X.LP
X.I F
Xis used to indicate that files are NOT textual, and should therefore be 
Xwritten in a fixed length format.
X.LP
X.I R
Xis used to change the default fixed length record size to the length 
Xspecified.
X.LP
X.I H
Xprovides a help screen.
X
X.SH SEE ALSO
Xtar(1), tp(1), mtb(8), retrieve(8)
X.SH DIAGNOSTICS
X.LP
XImproperly formatted tapes, not made in agreement with the VMS standard,
Xmay generate missing tape mark errors.
X.LP
XProblems with the tape and/or magtape drive will generate messages to the
Xeffect that the program was unable to read or write the tape.
X.SH BUGS
X.LP
XAs DEC changes the standard for VAX-VMS tapes,
Xthe program will need alterations.
X.LP
XIf the user attemps to write a non-textual file without the F (or R) switch,
Xthe file will not be completely written.  
SHAR_EOF
chmod 0664 vmstape.1 || echo "restore of vmstape.1 fails"
exit 0
-- 
W Mat Waites              |  Unlike most of you, I am not a nut.
{gatech,emory}!emcard!mat |             -H. Simpson

donn@hpfcdc.HP.COM (Donn Terry) (08/25/90)

I'll provide a guess....

It's written in some form of VAX proprietary backup or exchange format.
(I have no idea what.)

Some suggestions at getting at it:

1) The VAX may have (I'm no VAX expert) a tar or cpio analog; if so,
   use that.

2) Copy the whole tape into a file, edit out the junk, and you may have
   what you want.

	dd if=<tape> of=<filename> ibs=8192 

   may do it.  If the bytes seem right, but scrambled, try:

	dd if=<tape> of=<filename> ibs=8192 conv=swap

   If still scrambled, you may need to do a custom byte-swapping program.

   You may also have to do some fiddling with line breaks.

3) In situations like this, some form of LAN (specifically email) might
   be even easier.

4) If it's binary data, you will HAVE to write a custom conversion program.
   (Or convert to text and back.)

5) Write an ANSI tape; read it with ANSITAR (from the contrib tape).
   (Here I stick my neck out; you may not have ANSITAR and it may
   be harder to get than you'd (or I'd) like.)

6) Use some sort of copy utility to write it to the tape with no 
   structuring information at all.  Read it back with dd.  Again,
   you may have to translate the line breaks or swap bytes.

Donn Terry
Speaking solely for myself, and no-one else.

rer@hpfcdc.HP.COM (Rob Robason) (08/28/90)

If the other suggestions don't pan out, you may wish to use the mtdump
utility attached below to figure out the format of the tape, then use a
combination of the mt and dd commands to retrieve what you need.  mtdump
is on the HP contrib tape.

Rob Robason

/* @(#) $Revision: 29.2 $ */   
/* 1/2 inch mag tape dump utility .... Oct 25, 1984, Rob Robason */
/* Last modified 1/86 to use 8192 Byte buffer and /dev/rmt/0m  */
/* Usage: mtdump [-t special_file] [-b max_rec_size ] */
/* Default maximum record size is BUFSIZE */

#include <fcntl.h>	/* required for read(2) */
#include <stdio.h>
#include <signal.h>
#define BUFSIZE 8192	/*default buffer size used by malloc(3c) */
#define DFLT_TAPE "/dev/rmt/0m"
#define WIDTH 16	/* width of data fields on output */
int done = 0;		/* set if 'more' dies */
char *malloc();

main(argc,argv)
int argc;
char *argv[];
{
	int filedes, size, recno, pos;
	unsigned bufsize = BUFSIZE;
	char *tape_name = DFLT_TAPE;
	union {
		char *sign;
		unsigned char *unsign;
	} buf;		/* data buffer for mag tape record */
	unsigned char tmp[WIDTH];	/* display buffer for ascii */
	FILE *pfp;
	int moredead();
	int c;
	extern char *optarg;
	extern int optind;

	while ((c = getopt(argc, argv, "t:b:")) != EOF)
		switch (c) {
		case 't':
			tape_name = optarg;
			break;
		case 'b':
			if ((bufsize = atoi(optarg)) == 0) {
				perror(optarg);
				exit (-1);
				}
			break;
		default:
			fprintf(stderr,"Usage: %s [-t special_file] [-b max_rec_size ]\n",argv[0]);
			exit(-1);
		}
	if ((filedes = open(tape_name, O_RDONLY | O_NDELAY)) == -1) {
		perror(tape_name);
		exit(-1);
		}
	if ((buf.sign = malloc(bufsize)) == NULL) {
		perror("malloc");
		exit(-1);
		}
	signal(SIGPIPE, moredead);
	pfp = popen("/usr/bin/more", "w");
	fprintf(pfp,"device to be dumped: %s\n",tape_name);
	recno=1;
	/* read the file, record at a time */
	while ((size = read(filedes,buf.unsign,bufsize)) && !done) {
		fprintf(pfp,"Record #%d, Size=%d bytes\n",recno,size);
		for (pos=0;pos<size;pos++){
			/* print buf out in hex and ascii */
			if ( !( pos % WIDTH ))
				/* print decimal pos in record at SOL*/
				fprintf(pfp,"%.6d  ",pos);
			fprintf(pfp," %.2X",buf.unsign[pos]);
				/* print hex char */
			if(buf.unsign[pos] >= 32 & buf.unsign[pos] <= 127)
				/* put display-able char into display buffer */
				tmp[pos % WIDTH] = buf.unsign[pos];
			else
				/* put '.' into display buffer */
				tmp[pos % WIDTH] = '.';
			if (!((pos+1) % WIDTH))
				/* print ascii buffer at EOL */
				fprintf(pfp,"  %16s\n",tmp);
		}
		if ( size % WIDTH ) {
			/* print the last partial buffer */
			tmp[pos % WIDTH] = 0;
			fprintf(pfp,"\r\t\t\t\t\t\t\t  %s",tmp);
		}
		fprintf(pfp,"\n");
		recno++;
	}
	fprintf(pfp,"end of file\n");
	pclose(pfp);
	close(filedes);
}

moredead()
{
	done++;
	exit(0);
}