1 /* DASDSEQ.C    (c) Copyright Roger Bowler, 1999-2012                */
2 /*              (c) Copyright James M. Morrison, 2001-2010           */
3 /*              Hercules DASD Utilities: Sequential dataset unloader */
4 
5 /* Code borrowed from dasdpdsu Copyright 1999-2009 Roger Bowler      */
6 /* Changes and additions Copyright 2001-2009, James M. Morrison      */
7 
8 /*-------------------------------------------------------------------*/
9 /*                                                                   */
10 /*                 dasdseq                                           */
11 /*                                                                   */
12 /*      This program retrieves a sequential (DSORG=PS) dataset from  */
13 /*      a Hercules CKD/CCKD volume.  The input file is assumed to be */
14 /*      encoded in the EBCDIC character set.                         */
15 /*                                                                   */
16 /*-------------------------------------------------------------------*/
17 
18 // We don't use some of the regular Hercules dasd routines because
19 // we want the DSCB as read from dasd so we can check some of the
20 // file attributes (such as DSORG, RECFM, LRECL).
21 
22 // Dasdseq now uses the same case for the output dataset as the
23 // user specifies on the command line.  Prior versions always
24 // used upper case, which seems unnecessarily loud.
25 
26 #include "hstdinc.h"
27 
28 #include "hercules.h"
29 
30 typedef struct _DASD_VOL_LABEL {
31 
32         /* dasd cyl 0 trk 0 record 3                            */
33         /* identifies volser, owner, and VTOC location          */
34         /* recorded in EBCDIC; 80 bytes in length               */
35 
36         BYTE    vollabi[3];             // c'VOL'
37         BYTE    volno;                  // volume label sequence #
38         BYTE    volserno[6];            // volume serial
39         BYTE    security;               // security field, set to 0xc0
40         BYTE    volvtoc[5];             // CCHHR of VTOC's F4DSCB
41         BYTE    resv1[21];              // reserved; should be left blank
42         BYTE    volowner[14];           // volume owner
43         BYTE    resv2[29];              // reserved; should be left blank
44 } DASD_VOL_LABEL;
45 
46 #include "dasdblks.h"
47 
48 #ifndef MAX_EXTENTS                     // see getF3dscb for notes
49 #define MAX_EXTENTS     123             // maximum supported dataset extents
50 #endif
51 
52 typedef struct _DADSM {
53         DASD_VOL_LABEL  volrec;                 // volume label record
54         FORMAT4_DSCB    f4buf;                  // F4 DSCB
55         DSXTENT         f4ext;                  // VTOC extent info
56         FORMAT3_DSCB    f3buf;                  // F3 DSCB
57         FORMAT1_DSCB    f1buf;                  // F1 DSCB
58         int             f1numx;                 // # valid dataset extents
59         DSXTENT         f1ext[MAX_EXTENTS];     // dsn extent info
60 } DADSM;
61 
62 //----------------------------------------------------------------------------------
63 //  Globals
64 //----------------------------------------------------------------------------------
65         int     local_verbose = 0;      // verbose setting
66         int     copy_verbose = 0;       // verbose setting for copyfile
67         char    *din;                   // dasd image filename
68         char    *sfn;                   // shadow file parm
69         int     absvalid = 0;           // 1 = -abs specified, use CCHH not dsn
70         char    *argdsn;                // MVS dataset name
71         int     expert = 0;             // enable -abs help
72         int     tran_ascii = 0;         // 1 = ascii output
73 
74 #ifdef DEBUG
75         int     debug = 1;              // enable debug code
76 #else
77         int     debug = 0;              // disable debug code
78 #endif
79 
sayext(int max,DSXTENT * extent)80 void sayext(int max, DSXTENT *extent) {
81         int     i;
82         fprintf(stderr, "     EXTENT --begin-- ---end---\n");
83         fprintf(stderr, "TYPE NUMBER CCCC HHHH CCCC HHHH\n");
84         for (i = 0; i < max; i++) {
85             int bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1];
86             int btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1];
87             int ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1];
88             int etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1];
89             fprintf(stderr, "  %2.2X   %2.2X   %4.4X %4.4X %4.4X %4.4X\n",
90                 extent[i].xttype, extent[i].xtseqn, bcyl, btrk, ecyl, etrk);
91         }
92 } /* sayext */
93 
94 //----------------------------------------------------------------------------------
95 //  Display selected F1 DSCB information
96 //----------------------------------------------------------------------------------
97 
showf1(FILE * fmsg,FORMAT1_DSCB * f1dscb,DSXTENT extent[],int verbose)98 void showf1(    FILE            *fmsg,
99                 FORMAT1_DSCB    *f1dscb,
100                 DSXTENT         extent[],
101                 int             verbose) {
102 
103         int     i, dsorg, lrecl, blksize, volseq, x, y, num_extents;
104         char    volser[sizeof(f1dscb->ds1dssn) + 1];
105         char    dsn[sizeof(f1dscb->ds1dsnam) + 1];
106         char    txtcredt[9];                            // creation date
107         char    txtexpdt[9] = "(n/a)";                  // expiration date
108         char    txtscr[20];
109         char    txtsyscd[14];
110         char    txtdsorg[5] = "";                       // dsorg text
111         char    txtrecfm[5] = "";                       // recfm text
112 
113     if (verbose > 2) {
114         fprintf(fmsg, "showf1 F1 DSCB\n");
115         data_dump(f1dscb, sizeof(FORMAT1_DSCB));
116     }
117     make_asciiz(dsn, sizeof(dsn),
118                 f1dscb->ds1dsnam, sizeof(f1dscb->ds1dsnam));
119     make_asciiz(volser, sizeof(volser),
120                 f1dscb->ds1dssn, sizeof(f1dscb->ds1dssn));
121     volseq = (f1dscb->ds1volsq[0] << 8) | (f1dscb->ds1volsq[1]);
122     x = f1dscb->ds1credt[0] + 1900;
123     y = (f1dscb->ds1credt[1] << 8) | f1dscb->ds1credt[2];
124     sprintf(txtcredt, "%4.4d", x);
125     strcat(txtcredt, ".");
126     sprintf(txtscr, "%3.3d", y);
127     strcat(txtcredt, txtscr);
128     if (f1dscb->ds1expdt[0] || f1dscb->ds1expdt[1] || f1dscb->ds1expdt[2]) {
129         x = f1dscb->ds1expdt[0] + 1900;
130         y = (f1dscb->ds1expdt[1] << 8) | f1dscb->ds1expdt[2];
131         sprintf(txtexpdt, "%4.4d", x);
132         strcat(txtexpdt, ".");
133         sprintf(txtscr, ".%3.3d", y);
134         strcat(txtexpdt, txtscr);
135     }
136     num_extents = f1dscb->ds1noepv;
137 //  Field ignored: ds1nobdb (# bytes used in last PDS dir blk)
138     make_asciiz(txtsyscd, sizeof(txtsyscd),
139                 f1dscb->ds1syscd, sizeof(f1dscb->ds1syscd));
140 
141     dsorg = (f1dscb->ds1dsorg[0] << 8) | (f1dscb->ds1dsorg[1]);
142     if (dsorg & (DSORG_IS * 256))               strcpy(txtdsorg, "IS");
143     if (dsorg & (DSORG_PS * 256))               strcpy(txtdsorg, "PS");
144     if (dsorg & (DSORG_DA * 256))               strcpy(txtdsorg, "DA");
145     if (dsorg & (DSORG_PO * 256))               strcpy(txtdsorg, "PO");
146     if (dsorg &  DSORG_AM)                      strcpy(txtdsorg, "VS");
147     if (txtdsorg[0] == '\0')                    strcpy(txtdsorg, "??");
148     if (dsorg & (DSORG_U * 256))                strcat(txtdsorg, "U");
149 
150     if (f1dscb->ds1recfm & RECFM_FORMAT_F)      strcpy(txtrecfm, "F");
151     if (f1dscb->ds1recfm & RECFM_FORMAT_V)      strcpy(txtrecfm, "V");
152     if ((f1dscb->ds1recfm & RECFM_FORMAT_U) == RECFM_FORMAT_U)
153                                                 strcpy(txtrecfm, "U");
154     if (f1dscb->ds1recfm & RECFM_BLOCKED)       strcat(txtrecfm, "B");
155     if (f1dscb->ds1recfm & RECFM_SPANNED)       strcat(txtrecfm, "S");
156     if (f1dscb->ds1recfm & RECFM_CTLCHAR_A)     strcat(txtrecfm, "A");
157     if (f1dscb->ds1recfm & RECFM_CTLCHAR_M)     strcat(txtrecfm, "M");
158     if (f1dscb->ds1recfm & RECFM_TRKOFLOW)      strcat(txtrecfm, "T");
159 //  Field ignored: ds1optcd (option codes, same as in DCB)
160     blksize = (f1dscb->ds1blkl[0] << 8) | f1dscb->ds1blkl[1];
161     lrecl = (f1dscb->ds1lrecl[0] << 8) | f1dscb->ds1lrecl[1];
162 //  Field ignored: ds1keyl (key length)
163 //  Field ignored: ds1rkp (relative key position)
164 //  Field ignored: ds1dsind (data set indicators)
165 //  Field ignored: ds1scalo (secondary allocation)
166 //  Field ignored: ds1lstar (pointer to last written block; ttr)
167 //  Field ignored: ds1trbal (bytes remaining on last track used)
168 //  Extent information was passed to us, so we ignore what's in F1DSCB
169 
170     fprintf(fmsg, "Dataset %s on volume %s sequence %d\n", dsn, volser, volseq);
171     fprintf(fmsg, "Created %s expires %s\n", txtcredt, txtexpdt);
172     fprintf(fmsg, "Dsorg=%s recfm=%s lrecl=%d blksize=%d\n",
173                     txtdsorg, txtrecfm, lrecl, blksize);
174     fprintf(fmsg, "System code %s\n", txtsyscd);
175     if (verbose > 1) {
176         fprintf(stderr, "Dataset has %d extent(s)\n", num_extents);
177         if (verbose > 2)
178             data_dump((void *)extent, sizeof(DSXTENT) * MAX_EXTENTS);
179         fprintf(stderr, "Extent Information:\n");
180         fprintf(stderr, "     EXTENT --begin-- ---end---\n");
181         fprintf(stderr, "TYPE NUMBER CCCC HHHH CCCC HHHH\n");
182         for (i = 0; i < num_extents; i++) {
183             int bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1];
184             int btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1];
185             int ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1];
186             int etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1];
187             fprintf(stderr, "  %2.2X   %2.2X   %4.4X %4.4X %4.4X %4.4X\n",
188                 extent[i].xttype, extent[i].xtseqn, bcyl, btrk, ecyl, etrk);
189         }
190     }
191     return;
192 } /* showf1 */
193 
194 //----------------------------------------------------------------------------------
195 //  Copy DSORG=PS RECFM=F[B] dataset to output file
196 //
197 //  Input:
198 //      fout            FILE * (opened "w" for ascii, "wb" for ebcdic)
199 //      cif             dasdutil control block
200 //      f1dscb          F1 DSCB
201 //      extent          dataset extent array
202 //      tran            0 = ebcdic output, 1 = ascii output
203 //                      ascii output will have trailing blanks removed
204 //      verbose         0 = no status messages
205 //                      1 = status messages
206 //                      > 1 debugging messages
207 //                      > 2 dump read record
208 //                      > 3 dump written record
209 //                      > 4 dump read record from input buffer
210 //  Output:
211 //      File written, messages displayed on stderr
212 //  Returns -1 on error, else returns # records written
213 //  Notes:
214 //      Caller is responsible for opening and closing fout.
215 //
216 //      The F1 DSCB's DS1LSTAR field is used to determine EOF (absent a prior
217 //      EOF being encountered), since some datasets don't have an EOF marker
218 //      present.  On my MVSRES, for instance, SYS1.BRODCAST has no EOF marker.
219 //
220 //      2003-01-14 jmm DS1LSTAR may be zero; if so, ignore DS1LSTAR and
221 //      hope for valid EOF.
222 //----------------------------------------------------------------------------------
223 
fbcopy(FILE * fout,CIFBLK * cif,DADSM * dadsm,int tran,int verbose)224 int fbcopy(     FILE            *fout,
225                 CIFBLK          *cif,
226                 DADSM           *dadsm,
227                 int             tran,
228                 int             verbose) {
229 
230         FORMAT1_DSCB    *f1dscb = &dadsm->f1buf;
231         DSXTENT         extent[MAX_EXTENTS];
232         int     rc, trk = 0, trkconv = 999, rec = 1;
233         int     cyl = 0, head = 0, rc_rb, len, offset;
234         int     rc_copy = 0;
235         int     recs_written = 0, lrecl, num_extents;
236         int     lstartrack = 0, lstarrec = 0, lstarvalid = 0;
237         BYTE    *buffer;
238         char    *pascii = NULL;
239         char    zdsn[sizeof(f1dscb->ds1dsnam) + 1];     // ascii dsn
240 
241     // Kludge to avoid rewriting this code (for now):
242     memcpy(&extent, (void *)&(dadsm->f1ext), sizeof(extent));
243 
244     num_extents = f1dscb->ds1noepv;
245     lrecl = (f1dscb->ds1lrecl[0] << 8) | (f1dscb->ds1lrecl[1]);
246     if (absvalid) {
247         strcpy(zdsn, argdsn);
248         if (debug) fprintf(stderr, "fbcopy absvalid\n");
249     } else {
250         make_asciiz(zdsn, sizeof(zdsn),
251                 f1dscb->ds1dsnam, sizeof(f1dscb->ds1dsnam));
252         if ((f1dscb->ds1lstar[0] !=0) ||
253                 (f1dscb->ds1lstar[1] != 0) ||
254                 (f1dscb->ds1lstar[2] != 0)) {
255             lstartrack = (f1dscb->ds1lstar[0] << 8) | (f1dscb->ds1lstar[1]);
256             lstarrec = f1dscb->ds1lstar[2];
257             lstarvalid = 1;     // DS1LSTAR valid
258         }
259     }
260     if (debug) {
261         fprintf(stderr, "fbcopy zdsn %s\n", zdsn);
262         fprintf(stderr, "fbcopy num_extents %d\n", num_extents);
263         fprintf(stderr, "fbcopy lrecl %d\n", lrecl);
264         fprintf(stderr, "fbcopy F1 DSCB\n");
265         data_dump(f1dscb, sizeof(FORMAT1_DSCB));
266         sayext(num_extents, (void *)&extent);
267     }
268     if (verbose)                // DS1LSTAR = last block written TTR
269         fprintf(stderr,
270                 "fbcopy DS1LSTAR %2.2X%2.2X%2.2X lstartrack %d "
271                 "lstarrec %d lstarvalid %d\n",
272                 f1dscb->ds1lstar[0], f1dscb->ds1lstar[1], f1dscb->ds1lstar[2],
273                 lstartrack, lstarrec, lstarvalid);
274 
275     if (tran) {                 // need ASCII translation buffer?
276         pascii = malloc(lrecl + 1);
277         if (pascii == NULL) {
278             fprintf(stderr, "fbcopy unable to allocate ascii buffer\n");
279             return -1;
280         }
281     }
282 
283     while (1) {                 // output records until something stops us
284 
285 //  Honor DS1LSTAR when valid
286 
287         if ((lstarvalid) && (trk == lstartrack) && (rec > lstarrec)) {
288             if (verbose)
289                 fprintf(stderr, "fbcopy DS1LSTAR indicates EOF\n"
290                         "fbcopy DS1LSTAR %2.2X%2.2X%2.2X "
291                         "track %d record %d\n",
292                         f1dscb->ds1lstar[0], f1dscb->ds1lstar[1],
293                         f1dscb->ds1lstar[2], trk, rec);
294             rc_copy = recs_written;
295             break;
296         }
297 
298 //  Convert TT to CCHH for upcoming read_block call
299 
300         if (trkconv != trk) {           // avoid converting for each block
301             trkconv = trk;              // current track converted
302             rc = convert_tt(trk, num_extents, extent, cif->heads, &cyl, &head);
303             if (rc < 0) {
304                 fprintf(stderr,
305                         "fbcopy convert_tt track %5.5d, rc %d\n", trk, rc);
306                 if (absvalid)
307                     rc_copy = recs_written;
308                 else
309                     rc_copy = -1;
310                 break;
311             }
312             if (verbose > 1)
313                 fprintf(stderr, "fbcopy convert TT %5.5d CCHH %4.4X %4.4X\n",
314                         trk, cyl, head);
315         }
316 
317 //  Read block from dasd
318 
319         if (verbose > 2)
320             fprintf(stderr, "fbcopy reading track %d "
321                 "record %d CCHHR = %4.4X %4.4X %2.2X\n",
322                  trk, rec, cyl, head, rec);
323         rc_rb = read_block(cif, cyl, head, rec, NULL, NULL, &buffer, &len);
324         if (rc_rb < 0) {                        // error
325             fprintf(stderr, "fbcopy error reading %s, rc %d\n", zdsn, rc_rb);
326             rc_copy = -1;
327             break;
328         }
329 
330 //  Handle end of track return from read_block
331 
332         if (rc_rb > 0) {                        // end of track
333             if (verbose > 2)
334                 fprintf(stderr, "fbcopy End Of Track %d rec %d\n", trk, rec);
335             trk++;                              // next track
336             rec = 1;                            // record 1 on new track
337             continue;
338         }
339 
340 //  Check for dataset EOF
341 
342         if (len == 0) {                         // EOF
343             if (verbose)
344                 fprintf(stderr, "fbcopy EOF track %5.5d rec %d\n", trk, rec);
345             if (absvalid) {     // capture as much -abs data as possible
346                 if (verbose) fprintf(stderr, "fbcopy ignoring -abs EOF\n");
347             } else {
348                 rc_copy = recs_written;
349                 break;
350             }
351         }
352         if (verbose > 3)
353             fprintf(stderr, "fbcopy read %d bytes\n", len);
354         if (verbose > 2) {
355             data_dump(buffer, len);
356             fprintf(stderr, "\n");
357         }
358 
359 //  Deblock input dasd block, write records to output dataset
360 
361         for (offset = 0; offset < len; offset += lrecl) {
362             if (verbose > 3) {
363                 fprintf(stderr, "fbcopy offset %d length %d rec %d\n",
364                         offset, lrecl, recs_written);
365             }
366 
367             if (tran) {                 // ASCII output
368                 memset(pascii, 0, lrecl + 1);
369                 make_asciiz(pascii, lrecl + 1, buffer + offset, lrecl);
370                 if (verbose > 4) {
371                     fprintf(stderr, "fbcopy buffer offset %d rec %d\n",
372                                 offset, rec);
373                     data_dump(buffer + offset, lrecl);
374                 }
375                 if (verbose > 3) {
376                     fprintf(stderr, "->%s<-\n", pascii);
377                     data_dump(pascii, lrecl);
378                 }
379                 fprintf(fout, "%s\n", pascii);
380 
381             } else {                    // EBCDIC output
382                 if (verbose > 3) {
383                     fprintf(stderr, "fbcopy EBCDIC buffer\n");
384                     data_dump(buffer + offset, lrecl);
385                 }
386                 fwrite(buffer + offset, lrecl, 1, fout);
387             }
388             if (ferror(fout)) {
389                 fprintf(stderr, "fbcopy error writing %s\n", zdsn);
390                 fprintf(stderr, "%s\n", strerror(errno));
391                 rc_copy = -1;
392             }
393             recs_written++;
394         }
395         if (rc_copy != 0)
396             break;
397         else
398             rec++;                      // next record on track
399     } /* while (1) */
400     if (pascii)
401         free(pascii);                   // release ASCII conversion buffer
402     return rc_copy;
403 
404 } /* fbcopy */
405 
406 //----------------------------------------------------------------------------------
407 //  Given extent information, place it into appropriate extent table entry
408 //----------------------------------------------------------------------------------
409 
makext(int i,int heads,DSXTENT * extent,int startcyl,int starttrk,int size)410 void makext(
411         int i,                  // extent #
412         int heads,              // # heads per cylinder on device
413         DSXTENT *extent,        // extent table entry
414         int startcyl,           // start cylinder
415         int starttrk,           // start track
416         int size) {             // extent size in tracks
417 
418         int endcyl = ((startcyl * heads) + starttrk + size - 1) / heads;
419         int endtrk = ((startcyl * heads) + starttrk + size - 1) % heads;
420 
421         if (i > (MAX_EXTENTS - 1)) {
422                 fprintf(stderr,
423                         "makext extent # parm invalid %d, abort\n", i);
424                 exit(4);
425         }
426 
427         extent[i].xttype = 1;                   // extent type
428         extent[i].xtseqn = i;                   // extent # (relative zero)
429 
430         extent[i].xtbcyl[0] = startcyl >> 8;                    // begin cyl
431         extent[i].xtbcyl[1] = startcyl - ((startcyl / 256) * 256);
432         extent[i].xtbtrk[0] = starttrk >> 8;
433         extent[i].xtbtrk[1] = starttrk - ((starttrk / 256) * 256);
434 
435         extent[i].xtecyl[0] = endcyl >> 8;                      // end cyl
436         extent[i].xtecyl[1] = endcyl - ((endcyl / 256) * 256);
437         extent[i].xtetrk[0] = endtrk >> 8;
438         extent[i].xtetrk[1] = endtrk - ((endtrk / 256) * 256);  // end track
439         return;
440 } /* makext */
441 
442 //----------------------------------------------------------------------------------
443 // showhelp - display syntax help
444 //----------------------------------------------------------------------------------
445 
showhelp()446 void showhelp() {
447 
448     fprintf(stderr, (expert) ?
449         "Usage: dasdseq [-debug] [-expert] [-ascii] image [sf=shadow] [attr] filespec\n"
450         "  -debug    optional - Enables debug mode, additional debug help appears\n"
451         :
452         "Usage: dasdseq [-expert] [-ascii] image [sf=shadow] filespec\n");
453     fprintf(stderr,
454         "  -expert   optional - Additional help describes expert operands\n"
455         "  -ascii    optional - translate output file to ascii, trim trailing blanks\n"
456         "  image     required - [path/]filename of dasd image file (dasd volume)\n"
457         "  shadow    optional - [path/]filename of shadow file (note sf=)\n");
458     if (expert)
459         fprintf(stderr,
460         "  ALL EXPERT FACILITIES ARE EXPERIMENTAL\n"
461         "  attr      optional - dataset attributes (only useful with -abs)\n"
462         "            attr syntax: [-recfm fb] [-lrecl aa]\n"
463         "            -recfm designates RECFM, reserved for future support\n"
464         "            fb - fixed, blocked (only RECFM currently supported)\n"
465         "            -lrecl designates dataset LRECL\n"
466         "            aa - decimal logical record length (default 80)\n"
467         "                 Blocksize need not be specified; dasdseq handles whatever\n"
468         "                 block size comes off the volume.\n"
469         "  filespec  required (optional sub-operands in the following order):\n"
470         "                 [-heads xx]\n"
471         "                 [-abs cc hh tt] [...] [-abs cc hh tt ]\n"
472         "                 filename\n"
473         "            When -abs is -not- specified,\n"
474         "                 Filename specifies the MVS DSORG=PS dataset on the volume.\n"
475         "                 The dasd image volume containing the dataset must have a valid VTOC\n"
476         "                 structure, and a F1 DSCB describing the dataset.\n"
477         "                 Specifying -debug will (eventually) display extent information.\n"
478         "            When -abs is specified, each -abs group specifies one dataset extent.\n"
479         "                 For multi-extent datasets, -abs groups may be repeated as needed,\n"
480         "                 in the order in which the dataset's extents occur.\n"
481         "                 A maximum of %d extents are supported.\n"
482         "                 No VTOC structure is implied, a F1 DSCB will not be sought.\n"
483         "                 Dasdseq will frequently report 'track not found in extent table'\n"
484         "                 (along with a message from fbcopy about rc -1 from convert_tt)\n"
485         "                 due to potentially missing EOF markers in the extent, and the\n"
486         "                 fact that the F1 DSCB DS1LSTAR field is not valid.\n"
487         "                 Check your output file before you panic.\n"
488         "                 Fbcopy ignores EOF, in case you are attempting to recovery PDS\n"
489         "                 member(s) from a damaged dasd volume, preferring to wait until\n"
490         "                 all tracks in the extent have been processed.\n"
491         "                 Tracks containing PDS members may have more than one EOF per track.\n"
492         "                 Expect a lot of associated manual effort with -abs.\n"
493         "            -heads defines # tracks per cylinder on device;\n"
494         "            xx - decimal number of heads per cylinder on device\n"
495         "                 default xx = 15 (valid for 3380s, 3390s)\n"
496         "            -abs indicates the beginning of each extent's location in terms of\n"
497         "                 absolute dasd image location.\n"
498         "            cc - decimal cylinder number (relative zero)\n"
499         "            hh - decimal head number (relative zero)\n"
500         "            tt - decimal number of tracks in extent\n"
501         "            filename will be the filename of the output file in the current directory;\n"
502         "                 output filename in the same case as the command line filename.\n",
503                         MAX_EXTENTS);
504     else fprintf(stderr,
505         "  filespec  required - MVS dataset name of DSORG=PS dataset, output filename\n");
506     if (debug)
507         fprintf(stderr, "\n"
508                 "Debugging options (at end of dasdseq command)\n"
509                 "  [verbose [x [y [z]]]]\n\n"
510                 "  verbose   debug output level (default = 0 when not specified)\n"
511                 "      x  main program (default = 1 when verbose specified)\n"
512                 "      y  copyfile + showf1\n"
513                 "      z  dasdutil\n"
514                 "      Higher numbers produces more output\n");
515     return;
516 } /* showhelp */
517 
518 //----------------------------------------------------------------------------------
519 // parsecmd - parse command line; results stored in program globals
520 //----------------------------------------------------------------------------------
521 
parsecmd(int argc,char ** argv,DADSM * dadsm)522 int parsecmd(int argc, char **argv, DADSM *dadsm) {
523 
524         int     util_verbose = 0;       // Hercules dasdutil.c diagnostic level
525         int     heads = 15;             // # heads per cylinder on device
526         int     extnum = 0;             // extent number for makext()
527         int     abscyl = 0;             // absolute CC (default 0)
528         int     abshead = 0;            // absolute HH (default 0)
529         int     abstrk = 1;             // absolute tracks (default 1)
530         int     lrecl = 80;             // default F1 DSCB lrecl
531 
532 //  Usage: dasdseq [-debug] [-expert] [-ascii] image [sf=shadow] [attr] filespec
533 
534     argv++;                             // skip dasdseq command argv[0]
535     if ((*argv) && (strcasecmp(*argv, "-debug") == 0)) {
536             argv++;
537             debug = 1;
538             fprintf(stderr, "Command line DEBUG specified\n");
539     }
540     if ((*argv) && (strcasecmp(*argv, "-expert") == 0)) {
541             argv++;
542             expert = 1;
543             if (debug) fprintf(stderr, "EXPERT mode\n");
544     }
545     if ((*argv) && (strcasecmp(*argv, "-ascii") == 0)) {
546             argv++;
547             tran_ascii = 1;
548             if (debug) fprintf(stderr, "ASCII translation enabled\n");
549     }
550     if (*argv) din = *argv++;           // dasd image filename
551     if (debug) fprintf(stderr, "IMAGE %s\n", din);
552     if (*argv && strlen(*argv) > 3 && !memcmp(*argv, "sf=", 3)) {
553         sfn = *argv++;                  // shadow file parm
554     } else
555         sfn = NULL;
556     if (debug) fprintf(stderr, "SHADOW %s\n", sfn);
557     dadsm->f1buf.ds1recfm =
558                 RECFM_FORMAT_F | RECFM_BLOCKED; // recfm FB for fbcopy
559     if ((*argv) && (strcasecmp(*argv, "-recfm") == 0)) {
560         argv++;                                 // skip -recfm
561         if ((*argv) && (strcasecmp(*argv, "fb") == 0)) {
562             argv++;                             // skip fb
563             if (debug) fprintf(stderr, "RECFM fb\n");
564         } else {
565             argv++;                             // skip bad recfm
566             fprintf(stderr, "Unsupported -recfm value %s\n", *argv);
567         }
568     }
569     if ((*argv) && (strcasecmp(*argv, "-lrecl") == 0)) {
570         argv++;                                         // skip -lrecl
571         if (*argv) lrecl = atoi(*argv++);               // lrecl value
572         if (debug) fprintf(stderr, "LRECL %d\n", lrecl);
573     }
574     dadsm->f1buf.ds1lrecl[0] = lrecl >> 8;      // for fbcopy
575     dadsm->f1buf.ds1lrecl[1] = lrecl - ((lrecl >> 8) << 8);
576     if ((*argv) && (strcasecmp(*argv, "-heads") == 0)) {
577         argv++;                                 // skip -heads
578         if (*argv) heads = atoi(*argv++);       // heads value
579     }
580     if (debug) fprintf(stderr, "HEADS %d\n", heads);
581     if ((*argv) &&
582         (strcasecmp(*argv, "-abs") == 0)) {
583             absvalid = 1;                               // CCHH valid
584             while ((*argv) && (strcasecmp(*argv, "-abs") == 0)) {
585                 argv++;                                 // skip -abs
586                 abscyl = 0; abshead = 0; abstrk = 1;    // defaults
587                 if (*argv) abscyl = atoi(*argv++);      // abs cc
588                 if (*argv) abshead = atoi(*argv++);     // abs hh
589                 if (*argv) abstrk = atoi(*argv++);      // abs tracks
590                 // Build extent entry for -abs group
591                 makext(extnum, heads,
592                         (DSXTENT *) &dadsm->f1ext, abscyl, abshead, abstrk);
593                 extnum++;
594                 dadsm->f1buf.ds1noepv = extnum;         // for fbcopy
595                 if (debug) fprintf(stderr, "Absolute CC %d HH %d tracks %d\n",
596                         abscyl, abshead, abstrk);
597                 if (extnum > MAX_EXTENTS) {
598                         fprintf(stderr, "Too many extents, abort\n");
599                         exit(3);
600                 }
601 
602             }
603 //          if (debug) sayext(MAX_EXTENTS, dadsm->f1ext);// show extent table
604     }
605     if (debug) {
606         fprintf(stderr, "parsecmd completed F1 DSCB\n");
607         data_dump(&dadsm->f1buf, sizeof(FORMAT1_DSCB));
608     }
609     if (*argv) argdsn = *argv++;        // [MVS dataset name/]output filename
610     if (debug) fprintf(stderr, "DSN %s\n", argdsn);
611     if ((*argv) && (            // support deprecated 'ascii' operand
612                 (strcasecmp(*argv, "ascii") == 0) ||
613                 (strcasecmp(*argv, "-ascii") == 0)
614                 )
615         ) {
616             argv++;
617             tran_ascii = 1;
618             if (debug) fprintf(stderr, "ASCII translation enabled\n");
619     }
620     set_verbose_util(0);                // default util verbosity
621     if ((*argv) && (strcasecmp(*argv, "verbose") == 0)) {
622             local_verbose = 1;
623             argv++;
624         if (*argv) local_verbose = atoi(*argv++);
625         if (*argv) copy_verbose = atoi(*argv++);
626         if (*argv) {
627             util_verbose = atoi(*argv++);
628             set_verbose_util(util_verbose);
629             if (debug) fprintf(stderr, "Utility verbose %d\n", util_verbose);
630         }
631     }
632 
633 //  If the user specified expert mode without -abs, give help & exit
634 //  Additionally, if the user has "extra" parms, show help & exit
635 //  No "extraneous parms" message is issued, since some of the code
636 //  above forces *argv to be true when it wants help displayed
637 
638     if ((argc < 3) || (*argv) || ((expert) && (!absvalid))) {
639         showhelp();                     // show syntax before bailing
640         exit(2);
641     }
642     return 0;
643 
644 } /* parsecmd */
645 
646 //----------------------------------------------------------------------------------
647 //  getlabel - retrieve label record from dasd volume image
648 //----------------------------------------------------------------------------------
649 //
650 //  Input:
651 //      cif             ptr to opened CIFBLK of dasd image
652 //      glbuf           ptr to 80 byte buffer provided by caller
653 //      verbose         0 = no status messages
654 //                      1 = status messages
655 //                      > 1 debugging messages
656 //
657 //  Output:
658 //      glbuf           dasd volume label record
659 //
660 //  Returns:            0 OK, else error
661 //
662 //  Notes:
663 //      The volume label record always resides at CCHHR 0000 0000 03.
664 //      The dasd volume label record contains the CCHHR of the VTOC.
665 //      The volume label record is copied to the caller's buffer.
666 //----------------------------------------------------------------------------------
667 
getlabel(CIFBLK * cif,DASD_VOL_LABEL * glbuf,int verbose)668 int getlabel(
669                 CIFBLK          *cif,
670                 DASD_VOL_LABEL  *glbuf,
671                 int             verbose) {
672 
673         int     len, rc;
674         void    *plabel;
675 
676     if (verbose) fprintf(stderr, "getlabel reading volume label\n");
677     rc = read_block(cif, 0, 0, 3, NULL, NULL, (void *) &plabel, &len);
678     if (rc) {
679         fprintf(stderr, "getlabel error reading volume label, rc %d\n", rc);
680         return 1;
681     }
682     if (len != sizeof(DASD_VOL_LABEL)) {
683         fprintf(stderr, "getlabel error: volume label %d, not 80 bytes long\n", len);
684         return 2;
685     }
686     memcpy((void *)glbuf, plabel, sizeof(DASD_VOL_LABEL));
687     if (verbose > 1) {
688         fprintf(stderr, "getlabel volume label\n");
689         data_dump(glbuf, len);
690     }
691     return 0;
692 
693 } /* getlabel */
694 
695 //----------------------------------------------------------------------------------
696 //  getF4dscb - retrieve Format 4 DSCB - VTOC self-descriptor record
697 //----------------------------------------------------------------------------------
698 //
699 //  Input:
700 //      cif             ptr to opened CIFBLK of dasd image containing dataset
701 //      f4dscb          ptr to F4 DSCB buffer (key & data)
702 //      volrec          ptr to buffer containing volume label rec
703 //      vtocx           ptr to VTOC extent array (one extent only)
704 //      verbose         0 = no status messages
705 //                      1 = status messages
706 //                      > 1 debugging messages
707 //
708 //  Output:
709 //      f4buf           F4 DSCB in buffer (44 byte key, 96 bytes of data)
710 //      vtocx           VTOC extent array updated
711 //
712 //  Returns:            0 OK, else error
713 //
714 //  Notes:
715 //      There should only be one F4 DSCB in the VTOC, and it should always be
716 //      the first record in the VTOC.  The F4 provides VTOC extent information,
717 //      anchors free space DSCBs, and provides information about the device on
718 //      which the VTOC resides.
719 //----------------------------------------------------------------------------------
720 
getF4dscb(CIFBLK * cif,FORMAT4_DSCB * f4dscb,DASD_VOL_LABEL * volrec,DSXTENT * vtocx,int verbose)721 int getF4dscb(
722                 CIFBLK          *cif,
723                 FORMAT4_DSCB    *f4dscb,
724                 DASD_VOL_LABEL  *volrec,
725                 DSXTENT         *vtocx,
726                 int             verbose) {
727 
728         char            vtockey[sizeof(f4dscb->ds4keyid)];
729         void            *f4key, *f4data;
730         int             f4kl, f4dl;
731         int             cyl, head, rec, rc;
732 
733 //  Extract VTOC's CCHHR from volume label
734 
735     cyl = (volrec->volvtoc[0] << 8) | volrec->volvtoc[1];
736     head = (volrec->volvtoc[2] << 8) | volrec->volvtoc[3];
737     rec = volrec->volvtoc[4];
738     if (verbose > 1)
739         fprintf(stderr, "getF4dscb VTOC F4 at cyl %d head %d rec %d\n", cyl, head, rec);
740 
741 //  Read VTOC's Format 4 DSCB (VTOC self-descriptor)
742 
743     if (verbose)
744         fprintf(stderr, "getF4dscb reading VTOC F4 DSCB\n");
745     rc = read_block(cif, cyl, head, rec, (void *) &f4key, &f4kl, (void *) &f4data, &f4dl);
746     if (rc) {
747         fprintf(stderr, "getF4dscb error reading F4 DSCB, rc %d\n", rc);
748         return 1;
749     }
750 
751 //  Verify correct key and data length
752 
753     if ((f4kl != sizeof(f4dscb->ds4keyid)) ||
754         (f4dl != (sizeof(FORMAT4_DSCB) - sizeof(f4dscb->ds4keyid)))) {
755         fprintf(stderr, "getF4dscb erroneous key length %d or data length %d\n",
756                 f4kl, f4dl);
757         return 2;
758     }
759 
760 //  Return data to caller
761 
762     memcpy((void *) &f4dscb->ds4keyid, f4key, f4kl);    // copy F4 key into buffer
763     memcpy((void *) &f4dscb->ds4fmtid, f4data, f4dl);   // copy F4 data into buffer
764     memcpy((void *) vtocx, (void *)&f4dscb->ds4vtoce,
765         sizeof(f4dscb->ds4vtoce));                      // copy VTOC extent entry
766     if (verbose > 1) {
767         fprintf(stderr, "getF4dscb F4 DSCB\n");
768         data_dump((void *) f4dscb, sizeof(FORMAT4_DSCB));
769     }
770 
771 //  Verify DS4FMTID byte = x'F4', DS4KEYID key = x'04', and DS4NOEXT = x'01'
772 //  Do this after copying data to caller's buffer so we can use struct fields
773 //  rather than having to calculate offset to verified data; little harm done
774 //  if it doesn't verify since we're toast if they're bad.
775 
776     memset(vtockey, 0x04, sizeof(vtockey));
777     if ((f4dscb->ds4fmtid != 0xf4) ||
778         (f4dscb->ds4noext != 0x01) ||
779         (memcmp(&f4dscb->ds4keyid, vtockey, sizeof(vtockey)))) {
780         fprintf(stderr, "getF4dscb "
781                 "VTOC format id byte invalid (DS4IDFMT) %2.2X, \n"
782                 "VTOC key invalid, or multi-extent VTOC\n",
783                 f4dscb->ds4fmtid);
784         return 3;
785     }
786 
787 //  Display VTOC extent info (always one extent, never more)
788 
789     if (verbose > 1) {
790         fprintf (stderr, "getF4dscb "
791                 "VTOC start CCHH=%2.2X%2.2X %2.2X%2.2X "
792                        "end CCHH=%2.2X%2.2X %2.2X%2.2X\n",
793                 vtocx->xtbcyl[0], vtocx->xtbcyl[1],
794                 vtocx->xtbtrk[0], vtocx->xtbtrk[1],
795                 vtocx->xtecyl[0], vtocx->xtecyl[1],
796                 vtocx->xtetrk[0], vtocx->xtetrk[1]);
797     }
798     return 0;
799 } /* getF4dscb */
800 
801 //----------------------------------------------------------------------------------
802 //  getF1dscb - retrieve Format 1 DSCB
803 //----------------------------------------------------------------------------------
804 //
805 //  Input:
806 //      cif             ptr to opened CIFBLK of dasd image containing dataset
807 //      zdsn            ASCII null-terminated dataset name
808 //      f1dscb          ptr to F1 DSCB buffer (key & data)
809 //      vtocext         ptr to VTOC's extent info
810 //      verbose         0 = no status messages
811 //                      1 = status messages
812 //                      > 1 debugging messages
813 //
814 //  Output:
815 //      f1buf           F1 DSCB (44 byte key, 96 byte data)
816 //
817 //  Returns: 0 OK, else error
818 //
819 //  Notes:  The F1 DSCB describes the MVS dataset's physical and logical attributes
820 //          such as RECFM, LRECL, BLKSIZE, and where on the volume the dataset
821 //          resides (the extent information).  The first 3 possible extents are
822 //          described in the F1 DSCB.  If additional extents are allocated, they
823 //          are described by F3 DSCBs referred to by the F1 DSCB.
824 //----------------------------------------------------------------------------------
825 
getF1dscb(CIFBLK * cif,char * pdsn[],FORMAT1_DSCB * f1dscb,DSXTENT * vtocext[],int verbose)826 int getF1dscb(
827                 CIFBLK          *cif,
828                 char            *pdsn[],
829                 FORMAT1_DSCB    *f1dscb,
830                 DSXTENT         *vtocext[],
831                 int             verbose) {
832 
833         char    zdsn[sizeof(f1dscb->ds1dsnam) + 1];     // zASCII dsn
834         BYTE    edsn[sizeof(f1dscb->ds1dsnam)];         // EBCDIC dsn
835         void    *f1key, *f1data;
836         int     f1kl, f1dl;
837         int     cyl, head, rec, rc;
838         int     vtocextents = 1;        // VTOC has only one extent
839 
840 //  Locate dataset's F1 DSCB
841 
842     memset(zdsn, 0, sizeof(zdsn));
843     strncpy(zdsn, *pdsn, sizeof(zdsn) - 1);
844     string_to_upper(zdsn);
845     convert_to_ebcdic(edsn, sizeof(edsn), zdsn);
846     if (verbose)
847         fprintf(stderr, "getF1dscb searching VTOC for %s\n", zdsn);
848     rc = search_key_equal(cif, edsn, sizeof(edsn),
849                         vtocextents, (DSXTENT *)vtocext,
850                         &cyl, &head, &rec);
851     if (rc) {
852         fprintf(stderr, "getF1dscb search_key_equal rc %d\n", rc);
853         if (verbose) {
854             fprintf(stderr, "getF1dscb key\n");
855             data_dump(edsn, sizeof(edsn));
856         }
857         if (rc == 1)
858             fprintf(stderr, "getF1dscb no DSCB found for %s\n", zdsn);
859         return 1;
860     }
861 
862 //  Read F1 DSCB describing dataset
863 
864     if (verbose)
865         fprintf(stderr, "getF1dscb reading F1 DSCB\n");
866     rc = read_block(cif, cyl, head, rec,
867                 (void *)&f1key, &f1kl,
868                 (void *) &f1data, &f1dl);
869     if (rc) {
870         fprintf(stderr, "getF1dscb error reading F1 DSCB, rc %d\n", rc);
871         return 2;
872     }
873 
874 //  Return data to caller
875 
876     if ((f1kl == sizeof(f1dscb->ds1dsnam)) &&
877         (f1dl == (sizeof(FORMAT1_DSCB) - sizeof(f1dscb->ds1dsnam)))) {
878         memcpy((void *) &f1dscb->ds1dsnam,
879                 f1key, f1kl);           // copy F1 key to buffer
880         memcpy((void *) &f1dscb->ds1fmtid,
881                 f1data, f1dl);          // copy F1 data to buffer
882     } else {
883         fprintf(stderr, "getF1dscb bad key %d or data length %d\n",
884                 f1kl, f1dl);
885         return 3;
886     }
887     if (verbose > 1) {
888         fprintf(stderr, "getF1dscb F1 DSCB\n");
889         data_dump((void *) f1dscb, sizeof(FORMAT1_DSCB));
890     }
891 
892 //  Verify DS1FMTID byte = x'F1'
893 //  Do this after copying data to caller's buffer so we can use struct fields
894 //  rather than having to calculate offset to verified data; little harm done
895 //  if it doesn't verify since we're toast if it's bad.
896 
897     if (f1dscb->ds1fmtid != 0xf1) {
898         fprintf(stderr, "getF1dscb "
899                 "F1 DSCB format id byte invalid (DS1IDFMT) %2.2X\n",
900                 f1dscb->ds1fmtid);
901         return 4;
902     }
903     return 0;
904 } /* getF1dscb */
905 
906 //----------------------------------------------------------------------------------
907 //  getF3dscb - Retrieve Format 3 DSCB
908 //----------------------------------------------------------------------------------
909 //
910 //  Input:
911 //      cif             ptr to opened CIFBLK of dasd image containing dataset
912 //      f3cchhr         CCHHR of F3 DSCB to be read (key & data)
913 //      f3dscb          ptr to F3 DSCB buffer
914 //      verbose         0 = no status messages
915 //                      1 = status messages
916 //                      > 1 debugging messages
917 //
918 //  Output:
919 //      f3buf           F3 DSCB (44 byte key, 96 byte data)
920 //
921 //  Returns:            0 OK, else error
922 //
923 //  Notes:      The F3 DSCB describes additional dataset extents beyond those
924 //              described by the F1 DSCB.  Each F3 DSCB describes 13 extents.
925 //              Physical sequential datasets are limited to 16 extents on each
926 //              volume, extended format datasets are limited to 123 extents on
927 //              each volume.  Dasdseq doesn't provide explicit support for
928 //              multi-volume datasets.
929 //
930 //              Note there is extent information embedded in the key.
931 //
932 //              If you want support for > 16 extents, you will have to recompile
933 //              dasdseq after changing MAX_EXTENTS.
934 //
935 //  Warning:    I haven't tested the "chase the F3 chain" code, as I have no
936 //              reasonable way to do so.  The highest level of MVS I can run under
937 //              Hercules is MVS38j.
938 //----------------------------------------------------------------------------------
939 
getF3dscb(CIFBLK * cif,BYTE * f3cchhr,FORMAT3_DSCB * f3dscb,int verbose)940 int getF3dscb(
941                 CIFBLK          *cif,
942                 BYTE            *f3cchhr,
943                 FORMAT3_DSCB    *f3dscb,
944                 int             verbose) {
945 
946         int             cyl, head, rec, rc;
947         void            *f3key, *f3data;
948         int             f3kl, f3dl;
949 
950     cyl = (f3cchhr[0] << 8) | f3cchhr[1];
951     head = (f3cchhr[2] << 8) | f3cchhr[3];
952     rec = f3cchhr[4];
953     if (verbose)
954         fprintf(stderr, "getF3dscb reading F3 DSCB "
955                 "cyl %d head %d rec %d\n", cyl, head, rec);
956     rc = read_block (cif, cyl, head, rec,
957                 (void *)&f3key, &f3kl,
958                 (void *)&f3data, &f3dl);
959     if (rc) {
960         fprintf(stderr,
961                 "getF3dscb error reading F3 DSCB, rc %d\n", rc);
962         return 1;
963     }
964     if ((f3kl != 44) || (f3dl != 96)) {
965         fprintf(stderr, "getF3dscb bad key %d or data %d length\n",
966                 f3kl, f3dl);
967         return 2;
968     }
969     memcpy((void *) &f3dscb->ds3keyid,
970                 f3key, f3kl);           // copy F3 key to buffer
971     memcpy((void *) ((BYTE*)f3dscb + f3kl),
972                 f3data, f3dl);          // copy F3 data to buffer
973     if (verbose > 1) {
974             fprintf(stderr, "getF3dscb F3 DSCB\n");
975             data_dump((void *) f3dscb, sizeof(FORMAT3_DSCB));
976     }
977 
978 //  Verify DS3FMTID byte = x'F3'
979 //  Do this after copying data to caller's buffer so we can use struct fields
980 //  rather than having to calculate offset to verified data; little harm done
981 //  if it doesn't verify since we're toast if it's bad.
982 
983     if (f3dscb->ds3fmtid != 0xf3) {
984         fprintf(stderr, "getF3dscb "
985                 "F3 DSCB format id byte invalid (DS3IDFMT) %2.2X\n",
986                 f3dscb->ds3fmtid);
987         return 2;
988     }
989     return 0;
990 } /* getF3dscb */
991 
992 //----------------------------------------------------------------------------------
993 //  dadsm_setup - retrieve volume label & DSCBs sufficient to describe dataset
994 //----------------------------------------------------------------------------------
995 //
996 //      This routine reads the volume label rec, the VTOC F4 DSCB, the F1 DSCB
997 //      for the dataset, and any F3 DSCB(s) associated with the dataset.
998 //      Constructs extent array describing space allocated to the dataset.
999 //
1000 //  Input:
1001 //      cif             ptr to opened CIFBLK of dasd image containing dataset
1002 //      pdsn            ptr to ASCII null-terminated dataset name
1003 //      dadsm           ptr to DADSM workarea
1004 //      verbose         0 = no status messages
1005 //                      1 = status messages
1006 //                      > 1 debugging messages
1007 //
1008 //  Output:
1009 //      dadsm           DADSM workarea
1010 //
1011 //  Returns: 0 OK, else error
1012 //
1013 //  Notes:
1014 //----------------------------------------------------------------------------------
1015 
dadsm_setup(CIFBLK * cif,char * pdsn[],DADSM * dadsm,int verbose)1016 int dadsm_setup(
1017                 CIFBLK          *cif,
1018                 char            *pdsn[],
1019                 DADSM           *dadsm,
1020                 int             verbose) {
1021 
1022         DSXTENT         *f1x;
1023         BYTE            *pcchhr;
1024         int             numx = MAX_EXTENTS;     // # extent slots available
1025         int             rc;
1026 
1027 
1028 //  Read dasd volume label record
1029 
1030     rc = getlabel(cif, &dadsm->volrec, verbose);
1031     if (rc) return rc;
1032 
1033 //  Read F4 DSCB, save VTOC extent info
1034 
1035     rc = getF4dscb(cif, &dadsm->f4buf, &dadsm->volrec, &dadsm->f4ext, verbose);
1036     if (rc) return rc;
1037 
1038 //  Read F1 DSCB, save first three extents from F1 DSCB
1039 
1040     rc = getF1dscb(cif, pdsn, &dadsm->f1buf, (void *)&dadsm->f4ext, verbose);
1041     if (rc) return rc;
1042 
1043     f1x = &dadsm->f1ext[0];                     // @ extent # 0
1044     numx -= 3;                                  // will use 3 slots (if available)
1045     if (numx < 0) {
1046         fprintf(stderr, "dadsm_setup exhausted extent slots\n");
1047         return 1;
1048     }
1049     memcpy(f1x, &dadsm->f1buf.ds1ext1, sizeof(DSXTENT) * 3);
1050     f1x += 3;                                   // @ extent # 3
1051     dadsm->f1numx = dadsm->f1buf.ds1noepv;      // # extents alloc'd to dataset
1052     if (dadsm->f1numx < 4) {
1053         if (verbose > 1)
1054             fprintf(stderr, "dadsm_setup "
1055                 "no F3 DSCB required, only %d extent(s); all in F1\n",
1056                 dadsm->f1numx);
1057         return 0;
1058     }
1059 
1060 //  When more than 3 extents, get additional extent info from F3 DSCB(s).
1061 //  Chase the F3 chain starting with the CCHHR in the F1, accumulating
1062 //  extent information for the dataset as we progress.
1063 
1064     pcchhr = (BYTE *)&dadsm->f1buf.ds1ptrds;            // @ F1 ptr to F3
1065     while (pcchhr[0] || pcchhr[1] || pcchhr[2] || pcchhr[3] || pcchhr[4]) {
1066         rc = getF3dscb(cif, pcchhr, &dadsm->f3buf, verbose);
1067         if (rc) return rc;
1068         numx -= 4;                              // use extent slots
1069         if (numx < 0) {
1070             fprintf(stderr, "dadsm_setup exhausted extent slots\n");
1071             return 2;
1072         }
1073         memcpy(f1x, &dadsm->f3buf.ds3extnt[0], sizeof(DSXTENT) * 4);
1074         f1x += 4;
1075         numx -= 9;                              // use extent slots
1076         if (numx < 0) {
1077             fprintf(stderr, "dadsm_setup exhausted extent slots\n");
1078             fprintf(stderr, "Maximum supported extents %d\n", MAX_EXTENTS);
1079             return 3;
1080         }
1081         memcpy(f1x, &dadsm->f3buf.ds3adext[0], sizeof(DSXTENT) * 9);
1082         f1x += 9;
1083         pcchhr = (BYTE *)&dadsm->f3buf.ds3ptrds;        // @ next F3 CCHHR
1084     }
1085     return 0;
1086 } /* dadsm_setup */
1087 
1088 //----------------------------------------------------------------------------------
1089 //  Main
1090 //----------------------------------------------------------------------------------
1091 
main(int argc,char ** argv)1092 int main(int argc, char **argv) {
1093 
1094     DADSM    dadsm;                  // DADSM workarea
1095     FILE    *fout = NULL;           // output file
1096     CIFBLK  *cif;
1097     int      dsn_recs_written = 0, bail, dsorg, rc;
1098     char     pathname[MAX_PATH];
1099 
1100     fprintf(stderr, "dasdseq %s (C) Copyright 1999-2010 Roger Bowler\n"
1101         "Portions (C) Copyright 2001-2010 James M. Morrison\n", VERSION);
1102     if (debug) fprintf(stderr, "DEBUG enabled\n");
1103 
1104 //  Parse command line
1105 
1106     memset(&dadsm, 0, sizeof(dadsm));           // init DADSM workarea
1107     rc = parsecmd(argc, argv, &dadsm);
1108     if (rc) exit(rc);
1109 
1110 //  Open CKD image
1111 
1112     cif = open_ckd_image(din, sfn, O_RDONLY | O_BINARY, 0);
1113     if (!cif) {
1114         fprintf(stderr, "dasdseq unable to open image file %s\n", din);
1115         exit(20);
1116     }
1117 
1118 //  Unless -abs specified (in which case trust the expert user):
1119 //  Retrieve extent information for the dataset
1120 //  Display dataset attributes
1121 //  Verify dataset has acceptable attributes
1122 
1123     if (!absvalid) {
1124         rc = dadsm_setup(cif, &argdsn, &dadsm, local_verbose);
1125         if (rc) {
1126             close_ckd_image(cif);
1127             exit(rc);
1128         }
1129         if (local_verbose) {
1130             fprintf(stderr, "\n");
1131             showf1(stderr, &dadsm.f1buf, dadsm.f1ext, copy_verbose);
1132             fprintf(stderr, "\n");
1133         }
1134         bail = 1;
1135         dsorg = (dadsm.f1buf.ds1dsorg[0] << 8) | (dadsm.f1buf.ds1dsorg[1]);
1136         if (dsorg & (DSORG_PS * 256)) {
1137             if ((dadsm.f1buf.ds1recfm & RECFM_FORMAT) == RECFM_FORMAT_F)
1138                 bail = 0;
1139             if ((dadsm.f1buf.ds1recfm & RECFM_FORMAT) == RECFM_FORMAT_V) {
1140                 bail = 1;               // not yet
1141                 fprintf(stderr, "dasdseq only supports RECFM=F[B]\n");
1142             }
1143         } else
1144             fprintf(stderr, "dasdseq only supports DSORG=PS datasets\n");
1145         if (bail) {
1146             close_ckd_image(cif);
1147             exit(21);
1148         }
1149     }
1150 
1151 //  Open output dataset (EBCDIC requires binary open)
1152 
1153     hostpath(pathname, argdsn, sizeof(pathname));
1154 
1155     fout = fopen(pathname, (tran_ascii) ? "wb" : "w");
1156     if (fout == NULL) {
1157         fprintf(stderr, "dasdseq unable to open output file %s, %s\n",
1158                 argdsn, strerror(errno));
1159         close_ckd_image(cif);
1160         exit(22);
1161     }
1162     if (local_verbose)
1163         fprintf(stderr, "dasdseq writing %s\n", argdsn);
1164 
1165 //  Write dasd data to output dataset
1166 
1167     dsn_recs_written = fbcopy(fout, cif, &dadsm, tran_ascii, copy_verbose);
1168     if (dsn_recs_written == -1)
1169         fprintf(stderr, "dasdseq error processing %s\n", argdsn);
1170     else
1171         fprintf(stderr, "dasdseq wrote %d records to %s\n",
1172                 dsn_recs_written, argdsn);
1173 
1174 //  Close output dataset, dasd image and return to caller
1175 
1176     fclose(fout);
1177     if (local_verbose > 2) fprintf(stderr, "CLOSED %s\n", argdsn);
1178     if (local_verbose > 3) {
1179         fprintf(stderr, "CIFBLK\n");
1180         data_dump((void *) cif, sizeof(CIFBLK));
1181     }
1182     close_ckd_image(cif);
1183     if (local_verbose > 2) fprintf(stderr, "CLOSED image\n");
1184     return rc;
1185 
1186 } /* main */
1187 
1188