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