1 /* DASDLS.C (c) Copyright Roger Bowler, 1999-2012 */
2 /* Hercules DASD Utilities: DASD image loader */
3
4 /*
5 * dasdls
6 *
7 * Copyright 2000-2009 by Malcolm Beattie
8 * Based on code copyright by Roger Bowler, 1999-2009
9 * Decode of F1 DSCB by Chris Cheney, 2013, based on
10 * P.E. Havercan's VTOCLIST mainframe utility
11 *
12 */
13
14 #include "hstdinc.h"
15
16 #include "hercules.h"
17 #include "dasdblks.h"
18
19 static int needsep = 0; /* Write newline separator next time */
20
21 /* other globals */
22 int yroffs = 0; /* year offset */
23 int dsnlen = 44; /* dsname length (default value) */
24 int runflgs = 0; /* flags set from command line */
25 /* distinct CIF instance for F3 DSCB processing else screw up the F1 processing */
26 CIFBLK *cifx = NULL;
27
28 /* -------------------------- */
29 /* runflgs - flag settings */
30 /* -------------------------- */
31 /* dates in yyyymmmdd format */
32 #define rf_caldate (0x1)
33 /* show expiry dates */
34 #define rf_expdate (0x2)
35 /* show last-referenced dates */
36 #define rf_refdate (0x4)
37 /* show header */
38 #define rf_header (0x8)
39 /* show F1 info */
40 #define rf_info (0x10)
41
end_of_track(BYTE * p)42 int end_of_track(BYTE *p)
43 {
44 return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff
45 && p[4] == 0xff && p[5] == 0xff && p[6] == 0xff && p[7] == 0xff;
46 }
47
48 /* ordinalday is 1..365 (366 in leap year) - often wrongly called Julian day */
49
ordday_to_calday(int year,int ordinalday,int * month,int * day)50 int ordday_to_calday(int year, int ordinalday, int *month, int *day)
51 {
52 int d, m, offset;
53 int leap = (((year % 4) == 0) &&
54 (((year % 100) != 0) || ((year % 400) == 0)) ? 1 : 0);
55 #define janfebdays (31 + 28)
56 /* offset the months so that March is month 0 to deal
57 with the anomalies of February (short month, leap day) */
58 if ((ordinalday <= 0) || (ordinalday > (365 + leap))) return -1;
59 offset = janfebdays + leap; /* 31 (Jan) + {28, 29} (Feb) */
60 if (ordinalday <= offset) offset = - (365 - janfebdays);
61 d = ordinalday - 1 - offset; /* ordinal day to index day and offset to 1 March */
62 /* the months from March follow 5-month cycles of 31, 30, 31, 30, 31 days each month */
63 m = d / 153; /* which 5-month cycle? */
64 d -= (153 * m); /* day within 5-month cycle */
65 m *= 5; /* month that starts the 5-month cycle */
66 /* day of month = ((d mod (31 + 30)) mod 31 */
67 while (d >= 61) { d -= 61; m += 2; } /* body is executed 0, 1, or 2 times */
68 if (d >= 31) { d -= 31; m += 1; }
69 *day = d + 1; /* ordinal day of month */
70 /* convert back to January start of year and ordinal month */
71 if (m >= 10) m -= 12;
72 *month = m + 2; /* NB _index_ month, not ordinal month */
73 return 0;
74 }
75
pdate(BYTE * value,int runflgs)76 void pdate(BYTE* value, int runflgs)
77 {
78 int y = value[0] + yroffs;
79 int m = 12; /* 0..11 = Jan..Dec, 12 indexes empty string */
80 int d = (value[1] << 8) | value[2];
81 char *fmt;
82 static char *mths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
83 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" };
84 if (runflgs & rf_caldate)
85 {
86 /* calendar date (yyyymmmdd) */
87 if (ordday_to_calday(y += 1900, d, &m, &d))
88 fmt = " *********"; /* ordday_to_calday failed */
89 else
90 fmt = " %4.4d%s%2.2d";
91 }
92 else /* ordinal day (yyddd) */
93 {
94 y %= 100;
95 fmt = " %2.2d%s%3.3d";
96 }
97 printf(fmt, y, mths[m], d);
98 }
99
pdatex(BYTE * value,int runflgs)100 void pdatex(BYTE* value, int runflgs)
101 {
102 (value[0] | value[1] ? pdate(value, runflgs)
103 : printf(runflgs & rf_caldate ? " ---------"
104 : " -----"));
105 }
106
pbyte(BYTE * value)107 void pbyte(BYTE* value)
108 {
109 printf(" %3d", value[0]);
110 }
111
phword(BYTE * value)112 void phword(BYTE* value)
113 {
114 printf(" %5d", (value[0] << 8) | value[1]);
115 }
116
117 /* dataset extent processing */
118
hword(HWORD value)119 int hword(HWORD value)
120 {
121 return (value[0] << 8) + value[1];
122 }
123
extent_size(DSXTENT * ext,int heads)124 int extent_size(DSXTENT *ext, int heads)
125 {
126 return heads * (hword(ext->xtecyl) - hword(ext->xtbcyl)) +
127 (hword(ext->xtetrk) - hword(ext->xtbtrk)) + 1;
128 }
129
extents_array(DSXTENT extents[],int max,int * count,int heads)130 int extents_array(DSXTENT extents[], int max, int *count, int heads)
131 {
132 int i;
133 int size = 0;
134 for (i = 0; (*count > 0) && (i < max); i++)
135 if ((&(extents[i]))->xttype)
136 {
137 size += extent_size(&(extents[i]), heads);
138 *count -= 1;
139 }
140 else fprintf(stderr, "*** extents_array type failure\n");
141 return size;
142 }
143
chainf3(int * size,BYTE * ptr,int * count,char * fname,char * sfname)144 int chainf3(int *size, BYTE *ptr, int *count, char *fname, char *sfname)
145 {
146 FORMAT3_DSCB *f3dscb = NULL;
147 int rc = 0; /* prime for success */
148
149 while ((*count > 0) && (ptr[0] || ptr[1] || ptr[2] || ptr[3] || ptr[4]))
150 {
151 //*debug*/fprintf(stderr, "*** %d %.2x%.2x %.2x%.2x %.2x\n",
152 //*debug*/ *count, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
153
154 if (cifx == NULL)
155 if (NULL == (cifx = open_ckd_image(fname, sfname,
156 O_RDONLY|O_BINARY, 0)))
157 {
158 //*debug*/ fprintf(stderr, "*** Open cifx failed\n");
159
160 return -1; /* open failed */
161 }
162 if ((read_block(cifx, hword(&(ptr[0])), hword(&(ptr[2])), ptr[4],
163 (BYTE **)&f3dscb, NULL, NULL, NULL) == 0))
164 switch (f3dscb->ds3fmtid)
165 {
166 case 0xf3: if ((f3dscb->ds3keyid[0] != 0x03) || (f3dscb->ds3keyid[1] != 0x03) ||
167 (f3dscb->ds3keyid[2] != 0x03) || (f3dscb->ds3keyid[3] != 0x03))
168 break; /* break out of switch */
169 else
170 {
171 *size += extents_array(&(f3dscb->ds3extnt[0]), 4, count, cifx->heads);
172 *size += extents_array(&(f3dscb->ds3adext[0]), 9, count, cifx->heads);
173 }
174 case 0xf2: ptr = &(f3dscb->ds3ptrds[0]); /* same offset for both F2 and F3 DSCBs */
175 continue; /* continue while loop */
176 } /* end of switch */
177 rc = -1;
178
179 //*debug*/fprintf(stderr, "*** DSCB id=0x%.2x\n", f3dscb->ds3fmtid);
180
181 break;
182 } /* end of while loop */
183 return rc;
184 }
185
186 /* list_contents partly based on dasdutil.c:search_key_equal */
187
list_contents(CIFBLK * cif,char * volser,DSXTENT * extent,char * fname,char * sfname)188 int list_contents(CIFBLK *cif, char *volser, DSXTENT *extent, char *fname, char *sfname)
189 {
190 int cext = 0;
191 int ccyl = (extent[cext].xtbcyl[0] << 8) | extent[cext].xtbcyl[1];
192 int chead = (extent[cext].xtbtrk[0] << 8) | extent[cext].xtbtrk[1];
193 int ecyl = (extent[cext].xtecyl[0] << 8) | extent[cext].xtecyl[1];
194 int ehead = (extent[cext].xtetrk[0] << 8) | extent[cext].xtetrk[1];
195
196 #ifdef EXTERNALGUI
197 if (extgui) fprintf(stderr,"ETRK=%d\n",((ecyl*(cif->heads))+ehead));
198 #endif /*EXTERNALGUI*/
199
200 printf("%s%s: VOLSER=%s\n", needsep ? "\n" : "", cif->fname, volser);
201 needsep = 1;
202
203 if (runflgs & rf_header)
204 {
205 /* display column headers allowing for optional columns */
206 printf("%*s%s", -dsnlen, "Dsname", runflgs & rf_caldate ? " Created " :" CREDT");
207 printf(runflgs & rf_refdate ? (runflgs & rf_caldate ? " Last Ref." : " REFDT") : "");
208 printf(runflgs & rf_expdate ? (runflgs & rf_caldate ? " Exp. Date" : " EXPDT") : "");
209 printf(" ORG RECFM LRECL BLKSZ Key Trks%%Use#Ext 2ndry_alloc\n");
210 }
211
212 do {
213 BYTE *ptr;
214 int rc = read_track(cif, ccyl, chead);
215
216 #ifdef EXTERNALGUI
217 if (extgui) fprintf(stderr,"CTRK=%d\n",((ccyl*(cif->heads))+chead));
218 #endif /*EXTERNALGUI*/
219
220 if (rc < 0)
221 return -1;
222
223 ptr = cif->trkbuf + CKDDASD_TRKHDR_SIZE;
224
225 while (!end_of_track(ptr))
226 {
227 CKDDASD_RECHDR *rechdr = (CKDDASD_RECHDR*)ptr;
228 int kl = rechdr->klen;
229 int dl = (rechdr->dlen[0] << 8) | rechdr->dlen[1];
230
231 FORMAT1_DSCB *f1dscb = (FORMAT1_DSCB*)(ptr + CKDDASD_RECHDR_SIZE);
232
233 char dsname[sizeof(f1dscb->ds1dsnam) + 1];
234 char txtrecfm[5] = ""; /* recfm text */
235 char *tmpstr;
236 int lrecl;
237 int numext;
238 int space;
239 double value;
240
241
242 make_asciiz(dsname, sizeof(dsname), f1dscb->ds1dsnam, kl);
243
244 if ( valid_dsname( dsname ) )
245 {
246 printf("%*s", -dsnlen, dsname);
247
248 if (runflgs & rf_info)
249 {
250 /* CREDT */
251
252 pdate(f1dscb->ds1credt, runflgs);
253
254 /* REFDT */
255
256 #define ds1refdt resv2
257 if (runflgs & rf_refdate) pdatex(f1dscb->ds1refdt, runflgs);
258
259 /* EXPDT */
260
261 if (runflgs & rf_expdate) pdatex(f1dscb->ds1expdt, runflgs);
262
263 /* DSORG */
264
265 tmpstr = "??";
266 if (f1dscb->ds1dsorg[0] == 0 || f1dscb->ds1dsorg[0] == DSORG_U)
267 {
268 if (f1dscb->ds1dsorg[1] == DSORG_AM) tmpstr = "VS";
269 }
270
271 if (f1dscb->ds1dsorg[1] == 0)
272 switch (f1dscb->ds1dsorg[0] & (DSORG_PS | DSORG_DA | DSORG_PO))
273 {
274 case DSORG_PS: tmpstr = "PS"; break;
275 case DSORG_DA: tmpstr = "DA"; break;
276 case DSORG_PO: tmpstr = "PO"; break;
277 case 0: tmpstr = " ";
278 }
279
280 printf(" %s%s", tmpstr, f1dscb->ds1dsorg[0] & DSORG_U ? "U" : " ");
281
282 /* RECFM */
283
284 tmpstr = "U\0V\0F";
285 switch (f1dscb->ds1recfm & RECFM_FORMAT_U)
286 {
287 case RECFM_FORMAT_F: tmpstr = (char*)(tmpstr + 2);
288 case RECFM_FORMAT_V: tmpstr = (char*)(tmpstr + 2);
289 case RECFM_FORMAT_U: ;
290 }
291 strcpy(txtrecfm, tmpstr);
292
293 if (f1dscb->ds1recfm & RECFM_BLOCKED) strcat(txtrecfm, "B");
294 if (f1dscb->ds1recfm & RECFM_SPANNED) strcat(txtrecfm, "S");
295
296 tmpstr = "";
297 switch (f1dscb->ds1recfm & (RECFM_CTLCHAR_A | RECFM_CTLCHAR_M))
298 {
299 case RECFM_CTLCHAR_A: tmpstr = "A"; break;
300 case RECFM_CTLCHAR_M: tmpstr = "M"; break;
301 case RECFM_CTLCHAR_A | RECFM_CTLCHAR_M: tmpstr = "?";
302 }
303 strcat(txtrecfm, tmpstr);
304
305 if (f1dscb->ds1recfm & RECFM_TRKOFLOW) strcat(txtrecfm, "T");
306 printf(" %-5s", txtrecfm);
307
308 /* LRECL */
309
310 lrecl = (f1dscb->ds1lrecl[0] << 8) | f1dscb->ds1lrecl[1];
311 if (lrecl) {
312 printf(" %5d", lrecl);
313 } else {
314 printf(" ");
315 }
316
317 /* BLKSZ, KEYLN */
318
319 phword(f1dscb->ds1blkl); /* BLKSZ */
320 pbyte(&(f1dscb->ds1keyl)); /* KEYLN */
321
322 /* space allocated */
323
324 numext = f1dscb->ds1noepv;
325 space = extents_array(&(f1dscb->ds1ext1), 3, &numext, cif->heads);
326 chainf3(&space, &(f1dscb->ds1ptrds[0]), &numext, fname, sfname);
327 printf(" %5d", space);
328
329 /* % of allocated spaced used */
330
331 /* fraction of last track used = 1 - ds1trbal / trkzize */
332 value = 1.0 - (double)hword(&(f1dscb->ds1trbal[0])) / (cif->trksz);
333 /* add in the number of full tracks used */
334 value += hword(&(f1dscb->ds1lstar[0]));
335 if (space)
336 {
337 value = value * 100 / space; /* % space used */
338 printf(" %3.0f", value);
339 }
340 else printf(" "); /* avoiding divide by zero */
341
342 /* Number of extents */
343
344 pbyte(&(f1dscb->ds1noepv)); /* #EXT */
345
346 /* SCALO */
347
348 tmpstr = "CYL\0TRK\0BLK";
349 switch (f1dscb->ds1scalo[0] & DS1SCALO_UNITS)
350 {
351 case DS1SCALO_UNITS_ABSTR: printf(" %-11s", "ABSTR"); break;
352 case DS1SCALO_UNITS_BLK: tmpstr = (char*)(tmpstr + 4);
353 case DS1SCALO_UNITS_TRK: tmpstr = (char*)(tmpstr + 4);
354 case DS1SCALO_UNITS_CYL: printf(" %3s%8d", tmpstr,
355 (((f1dscb->ds1scalo[1] << 8) +
356 f1dscb->ds1scalo[2]) << 8) +
357 f1dscb->ds1scalo[3]);;
358 }
359
360 } /* end of if (runflgs & rf_info) */
361
362 /* done */
363 printf("\n");
364
365 }
366
367 ptr += CKDDASD_RECHDR_SIZE + kl + dl;
368 }
369
370 chead++;
371 if (chead >= cif->heads) {
372 ccyl++;
373 chead = 0;
374 }
375 } while (ccyl < ecyl || (ccyl == ecyl && chead <= ehead));
376
377 return 0;
378 }
379
380 /* do_ls_cif based on dasdutil.c:build_extent_array */
381
do_ls_cif(CIFBLK * cif,char * fname,char * sfname)382 int do_ls_cif(CIFBLK *cif, char *fname, char *sfname)
383 {
384 int rc, cyl, head, rec, len;
385 unsigned char *vol1data;
386 FORMAT4_DSCB *f4dscb;
387 char volser[7];
388
389 rc = read_block(cif, 0, 0, 3, 0, 0, &vol1data, &len);
390 if (rc < 0)
391 return -1;
392 if (rc > 0) {
393 fprintf(stderr, "VOL1 record not found\n");
394 return -1;
395 }
396
397 make_asciiz(volser, sizeof(volser), vol1data+4, 6);
398 cyl = (vol1data[11] << 8) | vol1data[12];
399 head = (vol1data[13] << 8) | vol1data[14];
400 rec = vol1data[15];
401
402 rc = read_block(cif, cyl, head, rec, (void *)&f4dscb, &len, 0, 0);
403 if (rc < 0)
404 return -1;
405 if (rc > 0) {
406 fprintf(stderr, "F4DSCB record not found\n");
407 return -1;
408 }
409 return list_contents(cif, volser, &f4dscb->ds4vtoce, fname, sfname);
410 }
411
do_ls(char * file,char * sfile)412 int do_ls(char *file, char *sfile)
413 {
414 int rc = 0;
415 CIFBLK *cif = open_ckd_image(file, sfile, O_RDONLY|O_BINARY, 0);
416
417 if (!cif || do_ls_cif(cif, file, sfile) || close_ckd_image(cif))
418 rc = -1;
419 if (cifx && close_ckd_image(cifx)) /* if necc., close the CIFBLK used for F3 DSCBs */
420 rc = -1;
421 return 0;
422 }
423
main(int argc,char ** argv)424 int main(int argc, char **argv)
425 {
426 int rc = 0;
427 char *fn, *sfn;
428
429 INITIALIZE_UTILITY("dasdls");
430
431 /* Display program info message */
432 display_version (stderr, "Hercules DASD list program ", FALSE);
433
434 if (argc < 2) {
435 fprintf(stderr, "Usage: dasdls [options] dasd_image [sf=shadow-file-name]...\n"
436 "Options:[-hdr] [-dsnl[=n]] [-info] [-caldt]\n"
437 "\t[-refdt] [-expdt] [-yroffs[=n]]\n");
438 exit(2);
439 }
440
441 /*
442 * If your version of Hercules doesn't have support in its
443 * dasdutil.c for turning off verbose messages, then remove
444 * the following line but you'll have to live with chatty
445 * progress output on stdout.
446 */
447 set_verbose_util(0);
448
449 while (*++argv)
450 {
451 fn = *argv;
452 if (strcmp(fn, "-info") == 0) /* show F1 info */
453 {
454 runflgs |= rf_info; continue;
455 }
456 if (strcmp(fn, "-caldt") == 0) /* calendar date format */
457 {
458 runflgs |= (rf_caldate | rf_info); continue;
459 }
460 if (strcmp(fn, "-expdt") == 0) /* show expiry date */
461 {
462 runflgs |= (rf_expdate | rf_info); continue;
463 }
464 if (strcmp(fn, "-refdt") == 0) /* show last-reference date */
465 {
466 runflgs |= (rf_refdate | rf_info) ; continue;
467 }
468 if (strcmp(fn, "-hdr") == 0) /* show column headers */
469 {
470 runflgs |= (rf_header | rf_info); continue;
471 }
472 if (strlen(*argv) > 6 && !memcmp(fn, "-dsnl=", 6)) /* restrict dsname width */
473 {
474 dsnlen = atoi(fn+6); runflgs |= rf_info; continue;
475 }
476 if (strcmp(fn, "-dsnl") == 0) /* restrict dsname width (default) */
477 {
478 dsnlen = 26; runflgs |= rf_info; continue;
479 }
480 if (strlen(*argv) > 8 && !memcmp(fn, "-yroffs=", 8)) /* year offset */
481 {
482 yroffs = atoi(fn+8); runflgs |= rf_info; continue;
483 }
484 if (strcmp(fn, "-yroffs") == 0) /* year offset (default) */
485 {
486 yroffs = 28; runflgs |= rf_info; continue;
487 }
488 if (*(argv+1) && strlen (*(argv+1)) > 3 && !memcmp(*(argv+1), "sf=", 3))
489 sfn = *++argv;
490 else sfn = NULL;
491 if (do_ls(fn, sfn))
492 rc = 1;
493 }
494
495 return rc;
496 }
497
498