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