1 /* DASDPDSU.C (c) Copyright Roger Bowler, 1999-2009 */
2 /* Hercules DASD Utilities: PDS unloader */
3
4 /*-------------------------------------------------------------------*/
5 /* This program unloads members of a partitioned dataset from */
6 /* a virtual DASD volume and copies each member to a flat file. */
7 /* */
8 /* The command format is: */
9 /* dasdpdsu ckdfile dsname [ascii] */
10 /* where: ckdfile is the name of the CKD image file */
11 /* dsname is the name of the PDS to be unloaded */
12 /* ascii is an optional keyword which will cause the members */
13 /* to be unloaded as ASCII variable length text files. */
14 /* Each member is copied to a file memname.mac in the current */
15 /* working directory. If the ascii keyword is not specified then */
16 /* the members are unloaded as fixed length binary files. */
17 /*-------------------------------------------------------------------*/
18
19 #include "hstdinc.h"
20
21 #include "hercules.h"
22 #include "dasdblks.h"
23
24 /*-------------------------------------------------------------------*/
25 /* Static data areas */
26 /*-------------------------------------------------------------------*/
27 static BYTE asciiflag = 0; /* 1=Translate to ASCII */
28 static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
29
30 /*-------------------------------------------------------------------*/
31 /* Subroutine to process a member */
32 /* Input: */
33 /* cif -> CKD image file descriptor structure */
34 /* noext Number of extents in dataset */
35 /* extent Dataset extent array */
36 /* memname Member name (ASCIIZ) */
37 /* ttr Member TTR */
38 /* */
39 /* Return value is 0 if successful, or -1 if error */
40 /*-------------------------------------------------------------------*/
41 static int
process_member(CIFBLK * cif,int noext,DSXTENT extent[],char * memname,BYTE * ttr)42 process_member (CIFBLK *cif, int noext, DSXTENT extent[],
43 char *memname, BYTE *ttr)
44 {
45 int rc; /* Return code */
46 int len; /* Record length */
47 int trk; /* Relative track number */
48 int cyl; /* Cylinder number */
49 int head; /* Head number */
50 int rec; /* Record number */
51 BYTE *buf; /* -> Data block */
52 FILE *ofp; /* Output file pointer */
53 char ofname[256]; /* Output file name */
54 int offset; /* Offset of record in buffer*/
55 char card[81]; /* Logical record (ASCIIZ) */
56 char pathname[MAX_PATH]; /* ofname in host format */
57
58 /* Build the output file name */
59 memset (ofname, 0, sizeof(ofname));
60 strncpy (ofname, memname, 8);
61 string_to_lower (ofname);
62 strcat (ofname, ".mac");
63
64 /* Open the output file */
65 hostpath(pathname, ofname, sizeof(pathname));
66 ofp = fopen (pathname, (asciiflag? "w" : "wb"));
67 if (ofp == NULL)
68 {
69 fprintf (stderr,
70 "Cannot open %s: %s\n",
71 ofname, strerror(errno));
72 return -1;
73 }
74
75 /* Point to the start of the member */
76 trk = (ttr[0] << 8) | ttr[1];
77 rec = ttr[2];
78
79 fprintf (stderr,
80 "Member %s TTR=%4.4X%2.2X\n",
81 memname, trk, rec);
82
83 /* Read the member */
84 while (1)
85 {
86 /* Convert relative track to cylinder and head */
87 rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head);
88 if (rc < 0) return -1;
89
90 // fprintf (stderr,
91 // "CCHHR=%4.4X%4.4X%2.2X\n",
92 // cyl, head, rec);
93
94 /* Read a data block */
95 rc = read_block (cif, cyl, head, rec, NULL, NULL, &buf, &len);
96 if (rc < 0) return -1;
97
98 /* Move to next track if record not found */
99 if (rc > 0)
100 {
101 trk++;
102 rec = 1;
103 continue;
104 }
105
106 /* Exit at end of member */
107 if (len == 0) break;
108
109 /* Check length of data block */
110 if (len % 80 != 0)
111 {
112 fprintf (stderr,
113 "Bad block length %d at cyl %d head %d rec %d\n",
114 len, cyl, head, rec);
115 return -1;
116 }
117
118 /* Process each record in the data block */
119 for (offset = 0; offset < len; offset += 80)
120 {
121 if (asciiflag)
122 {
123 make_asciiz (card, sizeof(card), buf + offset, 72);
124 fprintf (ofp, "%s\n", card);
125 }
126 else
127 {
128 fwrite (buf+offset, 80, 1, ofp);
129 }
130
131 if (ferror(ofp))
132 {
133 fprintf (stderr,
134 "Error writing %s: %s\n",
135 ofname, strerror(errno));
136 return -1;
137 }
138 } /* end for(offset) */
139
140 /* Point to the next data block */
141 rec++;
142
143 } /* end while */
144
145 /* Close the output file and exit */
146 fclose (ofp);
147 return 0;
148
149 } /* end function process_member */
150
151 /*-------------------------------------------------------------------*/
152 /* Subroutine to process a directory block */
153 /* Input: */
154 /* cif -> CKD image file descriptor structure */
155 /* noext Number of extents in dataset */
156 /* extent Dataset extent array */
157 /* dirblk Pointer to directory block */
158 /* */
159 /* Return value is 0 if OK, +1 if end of directory, or -1 if error */
160 /*-------------------------------------------------------------------*/
161 static int
process_dirblk(CIFBLK * cif,int noext,DSXTENT extent[],BYTE * dirblk)162 process_dirblk (CIFBLK *cif, int noext, DSXTENT extent[], BYTE *dirblk)
163 {
164 int rc; /* Return code */
165 int size; /* Size of directory entry */
166 int k; /* Userdata halfword count */
167 BYTE *dirptr; /* -> Next byte within block */
168 int dirrem; /* Number of bytes remaining */
169 PDSDIR *dirent; /* -> Directory entry */
170 char memname[9]; /* Member name (ASCIIZ) */
171
172 /* Load number of bytes in directory block */
173 dirptr = dirblk;
174 dirrem = (dirptr[0] << 8) | dirptr[1];
175 if (dirrem < 2 || dirrem > 256)
176 {
177 fprintf (stderr, "Directory block byte count is invalid\n");
178 return -1;
179 }
180
181 /* Point to first directory entry */
182 dirptr += 2;
183 dirrem -= 2;
184
185 /* Process each directory entry */
186 while (dirrem > 0)
187 {
188 /* Point to next directory entry */
189 dirent = (PDSDIR*)dirptr;
190
191 /* Test for end of directory */
192 if (memcmp(dirent->pds2name, eighthexFF, 8) == 0)
193 return +1;
194
195 /* Extract the member name */
196 make_asciiz (memname, sizeof(memname), dirent->pds2name, 8);
197
198 /* Process the member */
199 rc = process_member (cif, noext, extent, memname,
200 dirent->pds2ttrp);
201 if (rc < 0) return -1;
202
203 /* Load the user data halfword count */
204 k = dirent->pds2indc & PDS2INDC_LUSR;
205
206 /* Point to next directory entry */
207 size = 12 + k*2;
208 dirptr += size;
209 dirrem -= size;
210 }
211
212 return 0;
213 } /* end function process_dirblk */
214
215 /*-------------------------------------------------------------------*/
216 /* DASDPDSU main entry point */
217 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])218 int main (int argc, char *argv[])
219 {
220 int rc; /* Return code */
221 int i=0; /* Arument index */
222 int len; /* Record length */
223 int cyl; /* Cylinder number */
224 int head; /* Head number */
225 int rec; /* Record number */
226 int trk; /* Relative track number */
227 char *fname; /* -> CKD image file name */
228 char *sfname=NULL; /* -> CKD shadow file name */
229 char dsnama[45]; /* Dataset name (ASCIIZ) */
230 int noext; /* Number of extents */
231 DSXTENT extent[16]; /* Extent descriptor array */
232 BYTE *blkptr; /* -> PDS directory block */
233 BYTE dirblk[256]; /* Copy of directory block */
234 CIFBLK *cif; /* CKD image file descriptor */
235
236 INITIALIZE_UTILITY("dasdpdsu");
237
238 /* Display the program identification message */
239 display_version (stderr, "Hercules PDS unload program ", FALSE);
240
241 /* Check the number of arguments */
242 if (argc < 3 || argc > 5)
243 {
244 fprintf (stderr,
245 "Usage: %s ckdfile [sf=shadow-file-name] pdsname [ascii]\n",
246 argv[0]);
247 return -1;
248 }
249
250 /* The first argument is the name of the CKD image file */
251 fname = argv[1];
252
253 /* The next argument may be the shadow file name */
254 if (!memcmp (argv[2], "sf=", 3))
255 {
256 sfname = argv[2];
257 i = 1;
258 }
259
260 /* The second argument is the dataset name */
261 memset (dsnama, 0, sizeof(dsnama));
262 strncpy (dsnama, argv[2|+i], sizeof(dsnama)-1);
263 string_to_upper (dsnama);
264
265 /* The third argument is an optional keyword */
266 if (argc > 3+i && argv[3+i] != NULL)
267 {
268 if (strcasecmp(argv[3+i], "ascii") == 0)
269 asciiflag = 1;
270 else
271 {
272 fprintf (stderr,
273 "Keyword %s is not recognized\n",
274 argv[3+i]);
275 return -1;
276 }
277 }
278
279 /* Open the CKD image file */
280 cif = open_ckd_image (fname, sfname, O_RDONLY|O_BINARY, 0);
281 if (cif == NULL) return -1;
282
283 /* Build the extent array for the requested dataset */
284 rc = build_extent_array (cif, dsnama, extent, &noext);
285 if (rc < 0) return -1;
286
287 #ifdef EXTERNALGUI
288 /* Calculate ending relative track */
289 if (extgui)
290 {
291 int bcyl; /* Extent begin cylinder */
292 int btrk; /* Extent begin head */
293 int ecyl; /* Extent end cylinder */
294 int etrk; /* Extent end head */
295 int trks; /* total tracks in dataset */
296 int i; /* loop control */
297
298 for (i = 0, trks = 0; i < noext; i++)
299 {
300 bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1];
301 btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1];
302 ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1];
303 etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1];
304
305 trks += (((ecyl * cif->heads) + etrk) - ((bcyl * cif->heads) + btrk)) + 1;
306 }
307
308 fprintf(stderr,"ETRK=%d\n",trks-1);
309 }
310 #endif /*EXTERNALGUI*/
311
312 /* Point to the start of the directory */
313 trk = 0;
314 rec = 1;
315
316 /* Read the directory */
317 while (1)
318 {
319 #ifdef EXTERNALGUI
320 if (extgui) fprintf(stderr,"CTRK=%d\n",trk);
321 #endif /*EXTERNALGUI*/
322
323 /* Convert relative track to cylinder and head */
324 rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head);
325 if (rc < 0) return -1;
326
327 /* Read a directory block */
328 fprintf (stderr,
329 "Reading directory block at cyl %d head %d rec %d\n",
330 cyl, head, rec);
331
332 rc = read_block (cif, cyl, head, rec,
333 NULL, NULL, &blkptr, &len);
334 if (rc < 0) return -1;
335
336 /* Move to next track if block not found */
337 if (rc > 0)
338 {
339 trk++;
340 rec = 1;
341 continue;
342 }
343
344 /* Exit at end of directory */
345 if (len == 0) break;
346
347 /* Copy the directory block */
348 memcpy (dirblk, blkptr, sizeof(dirblk));
349
350 /* Process each member in the directory block */
351 rc = process_dirblk (cif, noext, extent, dirblk);
352 if (rc < 0) return -1;
353 if (rc > 0) break;
354
355 /* Point to the next directory block */
356 rec++;
357
358 } /* end while */
359
360 fprintf (stderr,
361 "End of directory\n");
362
363 /* Close the CKD image file and exit */
364 rc = close_ckd_image (cif);
365 return rc;
366
367 } /* end function main */
368