wa371@sdcc12.UUCP (wa371) (05/22/85)
Question posed to the net: How can I read IBM tapes with a UNIX system? Replies: ::::::::::::::::::::: From: Stewart Levin <ucbvax!decvax!mazama!stew@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@sdcsvax If it's unlabled, unblocked, you can use dd(1). -- Joe Presley (mhuxm!presley) ::::::::::::::::::: From: uw-beaver!tektronix!tekig!tekcbi!lindat@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@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@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@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@nosc *** hooray for USENET ***