1 /* TAPEMAP.C (c) Copyright Jay Maynard, 2000-2009 */
2 /* Map AWSTAPE format tape image */
3
4 /*-------------------------------------------------------------------*/
5 /* This program reads an AWSTAPE format tape image file and produces */
6 /* a map of the tape, printing any standard label records it finds. */
7 /*-------------------------------------------------------------------*/
8
9 #include "hstdinc.h"
10
11 #include "hercules.h"
12
13 /*-------------------------------------------------------------------*/
14 /* Structure definition for AWSTAPE block header */
15 /*-------------------------------------------------------------------*/
16 typedef struct _AWSTAPE_BLKHDR {
17 HWORD curblkl; /* Length of this block */
18 HWORD prvblkl; /* Length of previous block */
19 BYTE flags1; /* Flags byte 1 */
20 BYTE flags2; /* Flags byte 2 */
21 } AWSTAPE_BLKHDR;
22
23 /* Definitions for AWSTAPE_BLKHDR flags byte 1 */
24 #define AWSTAPE_FLAG1_NEWREC 0x80 /* Start of new record */
25 #define AWSTAPE_FLAG1_TAPEMARK 0x40 /* Tape mark */
26 #define AWSTAPE_FLAG1_ENDREC 0x20 /* End of record */
27
28 /*-------------------------------------------------------------------*/
29 /* Static data areas */
30 /*-------------------------------------------------------------------*/
31 static BYTE vollbl[] = "\xE5\xD6\xD3"; /* EBCDIC characters "VOL" */
32 static BYTE hdrlbl[] = "\xC8\xC4\xD9"; /* EBCDIC characters "HDR" */
33 static BYTE eoflbl[] = "\xC5\xD6\xC6"; /* EBCDIC characters "EOF" */
34 static BYTE eovlbl[] = "\xC5\xD6\xE5"; /* EBCDIC characters "EOV" */
35 static BYTE buf[65536];
36
37 #ifdef EXTERNALGUI
38 /* Report progress every this many bytes */
39 #define PROGRESS_MASK (~0x3FFFF /* 256K */)
40 /* How many bytes we've read so far. */
41 long curpos = 0;
42 long prevpos = 0;
43 #endif /*EXTERNALGUI*/
44
45 /*-------------------------------------------------------------------*/
46 /* TAPEMAP main entry point */
47 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])48 int main (int argc, char *argv[])
49 {
50 int i; /* Array subscript */
51 int len; /* Block length */
52 int prevlen; /* Previous block length */
53 char *filename; /* -> Input file name */
54 int infd = -1; /* Input file descriptor */
55 int fileno; /* Tape file number */
56 int blkcount; /* Block count */
57 int curblkl; /* Current block length */
58 int minblksz; /* Minimum block size */
59 int maxblksz; /* Maximum block size */
60 BYTE labelrec[81]; /* Standard label (ASCIIZ) */
61 AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */
62 char pathname[MAX_PATH]; /* file path in host format */
63
64 INITIALIZE_UTILITY("tapemap");
65
66 /* Display the program identification message */
67 display_version (stderr, "Hercules tape map program ", FALSE);
68
69 /* The only argument is the tape image file name */
70 if (argc == 2 && argv[1] != NULL)
71 {
72 filename = argv[1];
73 }
74 else
75 {
76 printf ("Usage: tapemap filename\n");
77 exit (1);
78 }
79
80 /* Open the tape device */
81 hostpath(pathname, filename, sizeof(pathname));
82 infd = hopen(pathname, O_RDONLY | O_BINARY);
83 if (infd < 0)
84 {
85 printf ("tapemap: Error opening %s: %s\n",
86 filename, strerror(errno));
87 exit (2);
88 }
89
90 /* Read blocks from the input file and report on them */
91 fileno = 1;
92 blkcount = 0;
93 minblksz = 0;
94 maxblksz = 0;
95 len = 0;
96
97 while (1)
98 {
99 #ifdef EXTERNALGUI
100 if (extgui)
101 {
102 /* Report progress every nnnK */
103 if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) )
104 {
105 prevpos = curpos;
106 fprintf( stderr, "IPOS=%ld\n", curpos );
107 }
108 }
109 #endif /*EXTERNALGUI*/
110 /* Save previous block length */
111 prevlen = len;
112
113 /* Read a block from the tape */
114 len = read (infd, buf, sizeof(AWSTAPE_BLKHDR));
115 #ifdef EXTERNALGUI
116 if (extgui) curpos += len;
117 #endif /*EXTERNALGUI*/
118 if (len < 0)
119 {
120 printf ("tapemap: error reading header block from %s: %s\n",
121 filename, strerror(errno));
122 exit (3);
123 }
124
125 /* Did we finish too soon? */
126 if ((len > 0) && (len < (int)sizeof(AWSTAPE_BLKHDR)))
127 {
128 printf ("tapemap: incomplete block header on %s\n",
129 filename);
130 exit(4);
131 }
132
133 /* Check for end of tape. */
134 if (len == 0)
135 {
136 printf ("End of tape.\n");
137 break;
138 }
139
140 /* Parse the block header */
141 memcpy(&awshdr, buf, sizeof(AWSTAPE_BLKHDR));
142
143 /* Tapemark? */
144 if ((awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) != 0)
145 {
146 /* Print summary of current file */
147 printf ("File %u: Blocks=%u, block size min=%u, max=%u\n",
148 fileno, blkcount, minblksz, maxblksz);
149
150 /* Reset counters for next file */
151 fileno++;
152 minblksz = 0;
153 maxblksz = 0;
154 blkcount = 0;
155
156 }
157 else /* if(tapemark) */
158 {
159 /* Count blocks and block sizes */
160 blkcount++;
161 curblkl = awshdr.curblkl[0] + (awshdr.curblkl[1] << 8);
162 if (curblkl > maxblksz) maxblksz = curblkl;
163 if (minblksz == 0 || curblkl < minblksz) minblksz = curblkl;
164
165 /* Read the data block. */
166 len = read (infd, buf, curblkl);
167 #ifdef EXTERNALGUI
168 if (extgui) curpos += len;
169 #endif /*EXTERNALGUI*/
170 if (len < 0)
171 {
172 printf ("tapemap: error reading data block from %s: %s\n",
173 filename, strerror(errno));
174 exit (5);
175 }
176
177 /* Did we finish too soon? */
178 if ((len > 0) && (len < curblkl))
179 {
180 printf ("tapemap: incomplete final data block on %s, "
181 "expected %d bytes, got %d\n",
182 filename, curblkl, len);
183 exit(6);
184 }
185
186 /* Check for end of tape */
187 if (len == 0)
188 {
189 printf ("tapemap: header block with no data on %s\n",
190 filename);
191 exit(7);
192 }
193
194 /* Print standard labels */
195 if (len == 80 && blkcount < 4
196 && (memcmp(buf, vollbl, 3) == 0
197 || memcmp(buf, hdrlbl, 3) == 0
198 || memcmp(buf, eoflbl, 3) == 0
199 || memcmp(buf, eovlbl, 3) == 0))
200 {
201 for (i=0; i < 80; i++)
202 labelrec[i] = guest_to_host(buf[i]);
203 labelrec[i] = '\0';
204 printf ("%s\n", labelrec);
205 }
206
207 } /* end if(tapemark) */
208
209 } /* end while */
210
211 /* Close files and exit */
212 close (infd);
213
214 return 0;
215
216 } /* end function main */
217