how to read IBM tapes on UNIX, (a long summary).

wa371 wa371 at sdcc12.UUCP
Wed May 22 15:55:22 AEST 1985


Question posed to the net: How can I read IBM tapes with a UNIX system?

Replies:
:::::::::::::::::::::
From: Stewart Levin <ucbvax!decvax!mazama!stew at sdcsvax.sdcc12>

Generally they come in fixed length records blocked together.
The dd command can be used to decipher them.  Symbolically,
the correct command is, if I recall correctly,

    dd if=TAPE_DRIVE of=OUTPUT conv=ascii ibs=BLKSIZE cbs=LRECL

To figure out the block size and record length, try first looking
at the outside of the tape for a stickon label with that info. If
that doesn't work, you'll have to scan the tape a bit.  Here's a
homegrown command we have for the purpose.  You'll need to modify
the tape unit array(s) for your own installation.

/*
 *    tplook [-short] [-78/-si] [label ...]
 *
 *    prints the file and record structure of a tape
 *    short form option
 *    label argument goes onto output header
 *    flags -78 and -si explicitly specify input tape drive
 *    default input is TU78 unless stdin's a tape
 */
/*
 * revised 2/7/85  stew for new SI tape drive.
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/file.h>
#include <stdio.h>

#define LEN 65535
#define BAD 10
#define SHORT 3

#define TU78 0
#define SI9721 1
#define STDIN 2  /* should be last in list */

static char *unitnames[] = { "/dev/rnt78l", "/dev/rntsil", "" } ;
static char *unitids[] = { "TU78", "SI", "stdin" } ;

double x[LEN/8+1];

int xargc; char **xargv;
main (argc,argv)
int argc;
char **argv;
    {
    int i=0, length=0, tlength=0, oldlength=0;
    int flength=0, bad=0, eof=0, records=0;
    int trecords=0, frecords=0, tfile=0;
    int rfile, tape, less=0;
    long tvec = 0;
    extern char *getlogin(), *ctime();

    xargc = argc; xargv = argv;
    if(isatape(fileno(stdin))) tape = STDIN;
    else tape = TU78;

    while (argc>1 && argv[1][0]=='-')
        {
        argc--; argv++;
        switch (argv[0][1])
            {
        case 's':
            if(argv[0][2] == 'i') tape = SI9721;
            else less = 1;
            break;
        case '7': tape = TU78;
            break;
            }
        }
    argc--; argv++;
/* printf header */
    (void) time (&tvec);
    fprintf (stderr,"Tplook - User: %s  Date: %s",getlogin(),ctime(&tvec));
    if (argc>0) fprintf (stderr,"Label:  ");
    for (i=0; i<argc;) fprintf (stderr,"%s ",argv[i++]);
    fprintf (stderr,"\n\n");
    if (less > 0) fprintf (stderr,"Short listing\n");
    fprintf(stderr,"Reading %s\n",unitids[tape]);

/* open tape drive */
    switch(tape) {
        case STDIN:
        rfile = fileno(stdin);
        break;
        default:
            if ((rfile = open (unitnames[tape],O_RDONLY)) < 0)
            {
            fprintf (stderr,"cant open %s\n",unitids[tape]);
            exit (-1);
            }
        }
/* read records */
    while (1)
    {
    length = read (rfile,(char *) x,(int) (LEN));
/* end of file mark */
    if (length == 0)
        {
        if (eof++ == 0)
            {
            if (oldlength < 0)
                {
                if (less == 2) fprintf (stderr,
                "\tfile %-d has %-d bad records at record %-d\n",
                    tfile,records,frecords);
                else fprintf (stderr,"\t%-d bad record(s)\n",
                    records);
                }
            else
                {
                if (less != 2) fprintf(stderr,
                    "\t%-d record(s) of length %-d\n",
                    records,oldlength);
                flength += records * oldlength;
                }
            frecords += records;
            if (less != 2 || (tfile % 5) == 0) fprintf (stderr,
                "file %-d:  #records = %-d  #bytes = %-d\n",
                tfile,frecords,flength);
            tfile++;
            trecords += frecords;
            tlength += flength;
            flength = records = frecords = 0;
            if (tfile == SHORT && less == 1) less++;
            }
/* end of tape */
        else
            {
            fprintf (stderr,
                "\ntape: #files = %-d  #records = %-d  ",
                tfile,trecords);
            fprintf (stderr,
                "#bytes = %-d  #disk blocks = %-d\n",
                tlength,tlength/512);
            exit(0);
            }
        }
/* change in record size */
    else 
        {
        eof = 0;
        if (length != oldlength && oldlength != 0)
            {
            if (oldlength < 0)
                {
                if (less == 2) fprintf (stderr,
                "\tfile %-d has %-d bad records at record %-d\n",
                    tfile,records,frecords);
                else fprintf (stderr,"\t%-d bad record(s)\n",
                    records);
                }
            else 
                {
                if (less != 2) fprintf (stderr,
                    "\t%-d record(s) of length %-d\n",
                    records,oldlength);
                flength += records * oldlength;
                }
            frecords += records;
            records = 1;
            }
/* same record length */
        else records++;
/* bad records */
        if (length < 0)
            {
            if (++bad == BAD)
                {
                fprintf (stderr,
                    "%d bad records in a row or end of tape\n",
                    BAD);
                trecords += frecords;
                tlength += flength;
                fprintf (stderr,
                    "\ntape: #files = %-d  #records = %-d  ",
                    tfile,trecords);
                fprintf (stderr,
                    "#bytes = %-d  #disk blocks = %-d\n",
                    tlength,tlength/512);
                exit (0);
                }
            }
        else bad = 0;
        }
    oldlength = length;
    }
}

:::::::::::::::::::
From: ihnp4!mhuxj!presley at sdcsvax

If it's unlabled, unblocked, you can use dd(1).
--
Joe Presley (mhuxm!presley)

:::::::::::::::::::
From: uw-beaver!tektronix!tekig!tekcbi!lindat at sdcsvax

First I would check the DECUS UNIX SIG tapes for a utility that reads
IBM tapes. You can find out about the closest DECUS person from
you local DEC salesperson.

If that doesn't work, you may have to write one yourself.

IBM tape format is very similiar to ANSI standard tape format,
except that IBM tapes are usually written in EBCDIC.
If you are going to be working with IBM tapes very often,
you want to order the IBM manual that on their tape format.
The title should be something like "IBM TAPE FORMAT" or "IBM TAPE LABELS".
It is meticulously detailed.

I am working from memory and I don't have the document. Please
get the manual and double check this info. The tape layout is something like:

<Beginning of Tape>

<Physical File 1> <Physical Record 1> = 80 byte EBCDIC record, 
				starts with "VOL1", includes
				the tape volume serial number
	<Physical Record 2> = 80 byte EBCDIC record,
				starts with "HDR1", gives 
				file name and other details.
	<Physical Record 3> = 80 byte EBCDIC record,
				starts with "HDR2", gives 
				record size, block size, etc.

<Tape Mark (also know as End of File Mark)>

<Physical File 2> <Physical Record 1> = length = block size given in file
				header record, data is in EBCDIC
				(or ASCII if it was created with 
				special DD DCB parameter),
				logical records are fixed length within the
				block, for example:
					block size = 800
					record length = 80
					There are 10 records in each block
				Records are NOT terminated with CR or LF.
				If the file was created with Fortran
				control characters, than the first character
				of each record tells whether to do form
				feed, new line, etc. BEFORE outputing
				the record.
	...
	<Physical Record n>
<Tape Mark>
<Physical File 3> <Physical Record 1> = 80 byte EBCDIC record,
				starts with "EOF1", gives 
				file name and other details.
	<Physical Record 2> = 80 byte EBCDIC record,
				starts with "EOF2", gives 
				record size, block size, etc.
<Tape Mark>
If this is the end of the tape, there will be two tape marks in a row.
If there are more data files, then the same sequence of 3 physical files
given above repeats, except that the "VOL1" record exists only at the
beginning of the tape.

You have several choices:

	1. If your source of IBM tape data is willing to work with
		you and help you out, tell them to create the tape
		with ASCII data instead of EBCDIC. They may not realize that
		they can do this. They need to specify a parameter 
		in the DCB (data control block)section of their
		DD (data definition) statement in their JCL.
		If they are willing to do this, then 
		a. you can skip the label file (use the 'mt' command 
			to position the tape)
			and read the sequential ASCII data file with a 
			utility such as 'cat'.
		b. The write a small program to read the file you created,
			and insert \n (LF) after every 'x' characters 
			where x is the record length.
		c. IF the file has Fortran control characters,
			your utility above needs to interpret the control
			characters and:
				a. Leave the LF at the end of the
				  preceding record as a LF,
				b. Change the preceding LF to a CR to
				  cause this record to overstrike the
				  previous record when printed,
				c. Insert a FF before this record.
				d. Possibly insert another LF or
					two before this record.

	2. If your source isn't willing to make IBM tapes with ASCII data
		then you have to add an EBCDIC to ASCII converion routine
		to execute before the other routines listed above.

Like I said, I don't have the exact info available to me anymore,
so don't take my word for it. GET THE MANUAL.

	Good luck,
	Linda Todd
	tektronix!tekcbi!lindat

:::::::::::::::::::::
From: dcdwest!ittvax!decvax!seismo!philabs!linus!peg at sdcsvax.sdcc12 (Margaret E. Craft)

You have to use dd.
I forget the painful details, but I did this a while ago from IBM running
MSV/TSO to PWB UNIX on 11/70.

Tricky things include records being divisible into block size
and using IEBGENER (?) to read into IBM.

I didn't try to move IBM file to UNIX, only UNIX to IBM.

good luck....

::::::::::::::::::::
Original-From:     Bennett E. Todd III <bet at ecsvax>
Organization: Duke University Computation Center

Use mt(1) to control the tape drive, and dd(1) to convert the files.
"Standard IBM format, unlabelled" isn't too bad, mostly. If you are
lucky (and you probably are, for anything that would be useful on
a UNIX system), then this means fixed blocked records, each of which
is 80 characters long, in EBCDIC. dd(1) not only has no trouble with
this, the example in my UNIX programmer's manual is how to do this!

	dd if=/dev/rmt0 of=x ibs=800 cbs=80 conv=ascii,lcase

You will only need to determine the blocksize for this to work. You
can sorta count on 80 character ("card-image") datasets. There are
variable-length record formats, but they aren't much used for tapes.
Let me know if you need details on one of these. The IBM Tape Labels
manual documents them, and they aren't too unlike ANSI Decimal Blocked
format, except in EBCDIC. Load module libraries probably wouldn't contain
anything you would find useful on a UNIX system anyway, so the only other
problem is if there is a Partitioned Dataset on the magtape. Partitioned
Datasets (PDS's) are really strictly random-access disk type things, and
when they get copied to a magtape they are "unloaded" -- i.e. transformed
with a tape backup utility into sequential files. If you have to cope with
one of these, it would probably be best to read it on an IBM mainframe,
and write the members of the PDS out as individual files. If you need to get
access to an IBM mainframe for such a conversion, or have further questions
about IBM magtapes, drop me a note.

Bennett Todd
...{decvax,ihnp4,akgua}!mcnc!ecsvax!bet

::::::::::::::::::::
From: ihnp4!utzoo!lsuc!dave at sdcsvax
From: ihnp4!wuphys!mff (Swamp Thing)

I've only done this once, and it was quite a while ago.  We're running Berkley
4.2, but I don't think there should be any difference.  Anyways, I used the
'dd' command.  Specifically, I think

dd if=/dev/mt0 of=outfile conv=ascii cbs=80 ibs=?

This should read in a ebcdic tape and output to "outfile".  If you don't know
the block size, I guess you'll just have to guess.

						Mark F. Flynn
						Department of Physics
						Washington University
						St. Louis, MO  63130
						ihnp4!wuphys!mff

:::::::::::::::::::
end of replies.

Bernd <bear-nd> 
(Not affiliated with, nor speaking for U.C. San Diego)
UUCP: ...!ucbvax!sdcsvax!sdcc12!wa371,   ARPA: sdcsvax!sdcc12!wa371 at nosc
            *** hooray for USENET ***



More information about the Comp.unix.wizards mailing list