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