1 /* TAPESPLT.C   (c) Copyright Jay Maynard, 2000-2009                 */
2 /*              Split AWSTAPE format tape image                      */
3 
4 /*-------------------------------------------------------------------*/
5 /* This program reads an AWSTAPE format tape image file and produces */
6 /* output files containing pieces of it, controlled by command line  */
7 /* options.                                                          */
8 /*-------------------------------------------------------------------*/
9 
10 #include "hstdinc.h"
11 
12 #include "hercules.h"
13 
14 /*-------------------------------------------------------------------*/
15 /* Structure definition for AWSTAPE block header                     */
16 /*-------------------------------------------------------------------*/
17 typedef struct _AWSTAPE_BLKHDR {
18         HWORD   curblkl;                /* Length of this block      */
19         HWORD   prvblkl;                /* Length of previous block  */
20         BYTE    flags1;                 /* Flags byte 1              */
21         BYTE    flags2;                 /* Flags byte 2              */
22     } AWSTAPE_BLKHDR;
23 
24 /* Definitions for AWSTAPE_BLKHDR flags byte 1 */
25 #define AWSTAPE_FLAG1_NEWREC    0x80    /* Start of new record       */
26 #define AWSTAPE_FLAG1_TAPEMARK  0x40    /* Tape mark                 */
27 #define AWSTAPE_FLAG1_ENDREC    0x20    /* End of record             */
28 
29 /*-------------------------------------------------------------------*/
30 /* Static data areas                                                 */
31 /*-------------------------------------------------------------------*/
32 static BYTE vollbl[] = "\xE5\xD6\xD3";  /* EBCDIC characters "VOL"   */
33 static BYTE hdrlbl[] = "\xC8\xC4\xD9";  /* EBCDIC characters "HDR"   */
34 static BYTE eoflbl[] = "\xC5\xD6\xC6";  /* EBCDIC characters "EOF"   */
35 static BYTE eovlbl[] = "\xC5\xD6\xE5";  /* EBCDIC characters "EOV"   */
36 static BYTE buf[65536];
37 
38 #ifdef EXTERNALGUI
39 /* Report progress every this many bytes */
40 #define PROGRESS_MASK (~0x3FFFF /* 256K */)
41 /* How many bytes we've read so far. */
42 long  curpos = 0;
43 long  prevpos = 0;
44 #endif /*EXTERNALGUI*/
45 
46 /*-------------------------------------------------------------------*/
47 /* tapesplt main entry point                                        */
48 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])49 int main (int argc, char *argv[])
50 {
51 int             rc;                     /* Return code               */
52 int             i;                      /* Array subscript           */
53 int             len;                    /* Block length              */
54 int             prevlen;                /* Previous block length     */
55 char           *infilename;             /* -> Input file name        */
56 char           *outfilename;            /* -> Current out file name  */
57 int             infd = -1;              /* Input file descriptor     */
58 int             outfd = -1;             /* Current out file desc     */
59 int             fileno;                 /* Tape file number          */
60 int             blkcount;               /* Block count               */
61 int             curblkl;                /* Current block length      */
62 int             minblksz;               /* Minimum block size        */
63 int             maxblksz;               /* Maximum block size        */
64 int             outfilenum;             /* Current out file# in argv */
65 int             outfilecount;           /* Current # files copied    */
66 int             files2copy;             /* Current # files to copy   */
67 BYTE            labelrec[81];           /* Standard label (ASCIIZ)   */
68 AWSTAPE_BLKHDR  awshdr;                 /* AWSTAPE block header      */
69 char            pathname[MAX_PATH];     /* file path in host format  */
70 
71     INITIALIZE_UTILITY("tapesplt");
72 
73     /* Display the program identification message */
74     display_version (stderr, "Hercules tape split program ", FALSE);
75 
76     /* The only argument is the tape image file name */
77     if (argc > 3 && argv[1] != NULL)
78     {
79         infilename = argv[1];
80     }
81     else
82     {
83         printf ("Usage: tapesplt infilename outfilename count [...]\n");
84         exit (1);
85     }
86 
87     /* Open the tape device */
88     hostpath(pathname, infilename, sizeof(pathname));
89     infd = hopen(pathname, O_RDONLY | O_BINARY);
90     if (infd < 0)
91     {
92         printf ("tapesplt: error opening input file %s: %s\n",
93                 infilename, strerror(errno));
94         exit (2);
95     }
96 
97     /* Copy blocks from input to output files */
98     fileno = 1;
99     blkcount = 0;
100     minblksz = 0;
101     maxblksz = 0;
102     len = 0;
103 
104     for (outfilenum = 2; outfilenum < argc; outfilenum += 2)
105     {
106         outfilename = argv[outfilenum];
107         printf ("Writing output file %s.\n", outfilename);
108         hostpath(pathname, outfilename, sizeof(pathname));
109         outfd = hopen(pathname, O_WRONLY | O_CREAT | O_BINARY,
110                         S_IRUSR | S_IWUSR | S_IRGRP);
111 
112         if (outfd < 0)
113         {
114             printf ("tapesplt: error opening output file %s: %s\n",
115                     outfilename, strerror(errno));
116             exit (3);
117         }
118 
119         if (outfilenum == argc)
120         {
121             /* count not specified for last file, so use big number */
122             files2copy = 32767;
123         }
124         else
125         {
126             files2copy = atoi(argv[outfilenum + 1]);
127         }
128 
129         /* Copy just that many files */
130         for (outfilecount = 0; outfilecount < files2copy; )
131         {
132 
133             /* Save previous block length */
134             prevlen = len;
135 
136             /* Read a block from the tape */
137             len = read (infd, buf, sizeof(AWSTAPE_BLKHDR));
138             if (len < 0)
139             {
140                 printf ("tapesplt: error reading header block from %s: %s\n",
141                         infilename, strerror(errno));
142                 exit (4);
143             }
144 
145             /* Did we finish too soon? */
146             if ((len > 0) && (len < (int)sizeof(AWSTAPE_BLKHDR)))
147             {
148                 printf ("tapesplt: incomplete block header on %s\n",
149                         infilename);
150                 exit(5);
151             }
152 
153 #ifdef EXTERNALGUI
154             if (extgui)
155             {
156                 curpos += len;
157                 /* Report progress every nnnK */
158                 if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) )
159                 {
160                     prevpos = curpos;
161                     fprintf( stderr, "IPOS=%ld\n", curpos );
162                 }
163             }
164 #endif /*EXTERNALGUI*/
165 
166             /* Check for end of tape. */
167             if (len == 0)
168             {
169                 printf ("End of input tape.\n");
170                 break;
171             }
172 
173             /* Copy the header to the output file. */
174             rc = write(outfd, buf, sizeof(AWSTAPE_BLKHDR));
175             if (rc < (int)sizeof(AWSTAPE_BLKHDR))
176             {
177                 printf ("tapesplt: error writing block header to %s: %s\n",
178                         outfilename, strerror(errno));
179                 exit(6);
180             }
181 
182             /* Parse the block header */
183             memcpy(&awshdr, buf, sizeof(AWSTAPE_BLKHDR));
184 
185             /* Tapemark? */
186             if ((awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) != 0)
187             {
188                 /* Print summary of current file */
189                 printf ("File %u: Blocks=%u, block size min=%u, max=%u\n",
190                         fileno, blkcount, minblksz, maxblksz);
191 
192                 /* Reset counters for next file */
193                 fileno++;
194                 minblksz = 0;
195                 maxblksz = 0;
196                 blkcount = 0;
197 
198                 /* Count the file we just copied. */
199                 outfilecount++;
200 
201             }
202             else /* if(tapemark) */
203             {
204                 /* Count blocks and block sizes */
205                 blkcount++;
206                 curblkl = awshdr.curblkl[0] + (awshdr.curblkl[1] << 8);
207                 if (curblkl > maxblksz) maxblksz = curblkl;
208                 if (minblksz == 0 || curblkl < minblksz) minblksz = curblkl;
209 
210                 /* Read the data block. */
211                 len = read (infd, buf, curblkl);
212                 if (len < 0)
213                 {
214                     printf ("tapesplt: error reading data block from %s: %s\n",
215                             infilename, strerror(errno));
216                     exit (7);
217                 }
218 
219                 /* Did we finish too soon? */
220                 if ((len > 0) && (len < curblkl))
221                 {
222                     printf ("tapesplt: incomplete final data block on %s: "
223                             "expected %d bytes, got %d\n",
224                             infilename, curblkl, len);
225                     exit(8);
226                 }
227 
228                 /* Check for end of tape */
229                 if (len == 0)
230                 {
231                     printf ("tapesplt: header block with no data on %s\n",
232                             infilename);
233                     exit(9);
234                 }
235 
236 #ifdef EXTERNALGUI
237                 if (extgui)
238                 {
239                     curpos += len;
240                     /* Report progress every nnnK */
241                     if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) )
242                     {
243                         prevpos = curpos;
244                         fprintf( stderr, "IPOS=%ld\n", curpos );
245                     }
246                 }
247 #endif /*EXTERNALGUI*/
248 
249                 /* Copy the header to the output file. */
250                 rc = write(outfd, buf, len);
251                 if (rc < len)
252                 {
253                     printf ("tapesplt: error writing data block to %s: %s\n",
254                             outfilename, strerror(errno));
255                     exit(10);
256                 }
257 
258                 /* Print standard labels */
259                 if (len == 80 && blkcount < 4
260                     && (memcmp(buf, vollbl, 3) == 0
261                         || memcmp(buf, hdrlbl, 3) == 0
262                         || memcmp(buf, eoflbl, 3) == 0
263                         || memcmp(buf, eovlbl, 3) == 0))
264                 {
265                     for (i=0; i < 80; i++)
266                         labelrec[i] = guest_to_host(buf[i]);
267                     labelrec[i] = '\0';
268                     printf ("%s\n", labelrec);
269                 }
270 
271             } /* end if(tapemark) */
272 
273         } /* end for(outfilecount) */
274 
275         close(outfd);
276 
277     } /* end for(outfilenum) */
278 
279     /* Close files and exit */
280     close (infd);
281 
282     return 0;
283 
284 } /* end function main */
285