mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-07-26 02:29:51 +02:00
3d239d3db5
* refactor: cleanup va_start/va_end - Missing va_end statements; - Incorrect va_copy ordering in BFR_VSNPRINTF; - Sanitize snprintf results or ensure buffer is initially \0'd. * refactor: introduce vasprintf Replace dynamic format string allocation (i.e., incrementing a buffer by a fixed amount until vsnprintf returns success) with vasprintf. Polyfill'ing for builds that do not include the GNU extension.
851 lines
26 KiB
C
851 lines
26 KiB
C
/* DASDLS.C (C) Copyright Roger Bowler, 1999-2012 */
|
|
/* (C) and others 2013-2023 */
|
|
/* Hercules DASD Utilities: DASD list program */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
/*********************************************************************
|
|
* dasdls
|
|
*
|
|
* Copyright 2000-2009 by Malcolm Beattie
|
|
* Based on code copyright by Roger Bowler, 1999-2009
|
|
* Decode of F1 DSCB by Chris Cheney, 2013, based on
|
|
* P.E. Havercan's VTOCLIST mainframe utility
|
|
* Copied by Erwin Marschalk from 3.12 to 4.0 release
|
|
* Further tweaks and fixes by Fish
|
|
* Sorted report by Fish
|
|
* Support for multiple extents by Ian Shorter
|
|
*********************************************************************/
|
|
|
|
#include "hstdinc.h"
|
|
#include "hercules.h"
|
|
#include "dasdblks.h"
|
|
|
|
#define UTILITY_NAME "dasdls"
|
|
#define UTILITY_DESC "List DASD image file contents"
|
|
|
|
/*********************************************************************/
|
|
/* function prototypes */
|
|
|
|
void pdate (BYTE* value, int runflgs);
|
|
void pdatex (BYTE* value, int runflgs);
|
|
void pbyte (BYTE* value);
|
|
void phword (BYTE* value);
|
|
int hword (HWORD value);
|
|
|
|
int extent_size (DSXTENT *ext, int heads);
|
|
int extents_array (DSXTENT extents[], int max, int *count, int heads);
|
|
int chainf3 (int *size, BYTE *ptr, int *count );
|
|
int ordday_to_calday (int year, int ordinalday, int *month, int *day);
|
|
|
|
int end_of_track (BYTE *p);
|
|
int list_contents (CIFBLK *cif, DSXTENT *extent );
|
|
int do_ls_cif (CIFBLK *cif, char *sfile);
|
|
int do_ls (char *file, char *sfile);
|
|
|
|
/*********************************************************************/
|
|
/* globals */
|
|
|
|
static CIFBLK* cif = NULL;
|
|
static int yroffs = 0; /* year offset */
|
|
#define DEFAULT_DSNLEN 44
|
|
static int dsnlen = DEFAULT_DSNLEN;
|
|
static int runflgs = 0; /* run flags set from command line */
|
|
/* run flags: */
|
|
#define rf_caldate 0x01 /* dates in yyyymmmdd format */
|
|
#define rf_expdate 0x02 /* show expiry dates */
|
|
#define rf_refdate 0x04 /* show last-referenced dates */
|
|
#define rf_header 0x08 /* show header */
|
|
#define rf_info 0x10 /* show F1 info */
|
|
#define rf_cchh 0x20 /* show extent cchh info */
|
|
#define rf_nosort 0x40 /* do NOT sort results */
|
|
|
|
/*********************************************************************/
|
|
/* sort by dsname support */
|
|
|
|
static char** lcchhtab = NULL; /* Parts of a full line */
|
|
static char** lsegstab = NULL; /* Parts of a full line */
|
|
static char** linestab = NULL; /* Complete lines */
|
|
static int numcchh = 0; /* #of segments in lcchhtab */
|
|
static int numsegs = 0; /* #of segments in lsegstab */
|
|
static int numlines = 0; /* #of lines in linestab */
|
|
static char segbuf[256] = {0}; /* Line segment buffer */
|
|
static char linebuf[256*256] = {0}; /* Full line buffer */
|
|
|
|
#define CCHH_COLHDR " Ext# (BEG) (END) "
|
|
static int cchh_colhdr_width;
|
|
|
|
static void prtcchhseg( const char* fmt, ... )
|
|
{
|
|
va_list vl;
|
|
|
|
va_start( vl, fmt );
|
|
if (vsnprintf( segbuf, sizeof( segbuf ), fmt, vl ) >= 0)
|
|
{
|
|
lcchhtab = realloc( lcchhtab, (numcchh + 1) * sizeof( char* ));
|
|
lcchhtab[ numcchh++ ] = strdup( segbuf );
|
|
}
|
|
va_end( vl );
|
|
}
|
|
|
|
static void prtseg( const char* fmt, ... )
|
|
{
|
|
va_list vl;
|
|
|
|
va_start( vl, fmt );
|
|
if (vsnprintf( segbuf, sizeof( segbuf ), fmt, vl ) >= 0)
|
|
{
|
|
lsegstab = realloc( lsegstab, (numsegs + 1) * sizeof( char* ));
|
|
lsegstab[ numsegs++ ] = strdup( segbuf );
|
|
}
|
|
va_end( vl );
|
|
}
|
|
|
|
static void prtline( const char* fmt, ... )
|
|
{
|
|
va_list vl;
|
|
|
|
va_start( vl, fmt );
|
|
if (vsnprintf( linebuf, sizeof( linebuf ), fmt, vl ) >= 0)
|
|
{
|
|
linestab = realloc( linestab, (numlines + 1) * sizeof( char* ));
|
|
linestab[ numlines++ ] = strdup( linebuf );
|
|
}
|
|
va_end( vl );
|
|
}
|
|
|
|
static void print_line_from_segs()
|
|
{
|
|
int cchhnum, segnum;
|
|
char buffer[256*256] = {0};
|
|
|
|
if (runflgs & rf_cchh)
|
|
{
|
|
/* For each extent that the dataset has... */
|
|
for (cchhnum=0; cchhnum < numcchh; ++cchhnum)
|
|
{
|
|
/* Print this extent's BEG/END CCHH */
|
|
STRLCPY( buffer, lcchhtab[ cchhnum ]);
|
|
free( lcchhtab[ cchhnum ]);
|
|
|
|
/* Print the remainder of the information... */
|
|
for (segnum=0; segnum < numsegs; ++segnum)
|
|
{
|
|
/* (very first segment is always dsname) */
|
|
STRLCAT( buffer, lsegstab[ segnum ]);
|
|
|
|
/* (if this is extent #2, then we're done) */
|
|
if (cchhnum > 0)
|
|
{
|
|
STRLCAT( buffer, "\n" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
prtline( "%s", buffer );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Print the remainder of the information... */
|
|
for (segnum=0; segnum < numsegs; ++segnum)
|
|
STRLCAT( buffer, lsegstab[ segnum ]);
|
|
|
|
prtline( "%s", buffer );
|
|
}
|
|
|
|
free( lcchhtab );
|
|
lcchhtab = NULL;
|
|
numcchh = 0;
|
|
|
|
for (segnum=0; segnum < numsegs; ++segnum)
|
|
free( lsegstab[ segnum ]);
|
|
|
|
free( lsegstab );
|
|
lsegstab = NULL;
|
|
numsegs = 0;
|
|
}
|
|
|
|
static int sort_linestab( const void* a, const void* b )
|
|
{
|
|
const char* line_a = *(const char**)a;
|
|
const char* line_b = *(const char**)b;
|
|
|
|
// (we always sort by dataset name...)
|
|
|
|
if (runflgs & rf_cchh)
|
|
{
|
|
int rc;
|
|
if ((rc = strncmp( line_a + cchh_colhdr_width,
|
|
line_b + cchh_colhdr_width, dsnlen )) != 0)
|
|
return rc;
|
|
}
|
|
|
|
return strcmp( line_a, line_b );
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
int end_of_track( BYTE *p )
|
|
{
|
|
return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff
|
|
&& p[4] == 0xff && p[5] == 0xff && p[6] == 0xff && p[7] == 0xff;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* ordinalday is 1..365 (366 in leap year) */
|
|
/* often wrongly called Julian day */
|
|
|
|
#define JAN_FEB_DAYS (31 + 28)
|
|
|
|
int ordday_to_calday( int year, int ordinalday, int *month, int *day )
|
|
{
|
|
int d, m, offset;
|
|
int leap = (((year % 4) == 0) &&
|
|
(((year % 100) != 0) || ((year % 400) == 0)) ? 1 : 0);
|
|
|
|
/* offset the months so that March is month 0 to deal
|
|
with the anomalies of February (short month, leap day) */
|
|
|
|
if ((ordinalday <= 0) || (ordinalday > (365 + leap)))
|
|
return -1;
|
|
|
|
offset = JAN_FEB_DAYS + leap; /* 31 (Jan) + {28, 29} (Feb) */
|
|
|
|
if (ordinalday <= offset)
|
|
offset = - (365 - JAN_FEB_DAYS);
|
|
|
|
d = ordinalday - 1 - offset; /* ordinal day to index day and offset to 1 March */
|
|
|
|
/* the months from March follow 5-month cycles of 31, 30, 31, 30, 31 days each month */
|
|
|
|
m = d / 153; /* which 5-month cycle? */
|
|
d -= (153 * m); /* day within 5-month cycle */
|
|
m *= 5; /* month that starts the 5-month cycle */
|
|
|
|
/* day of month = ((d mod (31 + 30)) mod 31 */
|
|
|
|
while (d >= 61) /* body is executed 0, 1, or 2 times */
|
|
{
|
|
d -= 61;
|
|
m += 2;
|
|
}
|
|
|
|
if (d >= 31)
|
|
{
|
|
d -= 31;
|
|
m += 1;
|
|
}
|
|
|
|
*day = d + 1; /* ordinal day of month */
|
|
|
|
/* convert back to January start of year and ordinal month */
|
|
|
|
if (m >= 10)
|
|
m -= 12;
|
|
|
|
*month = m + 2; /* NB _index_ month, not ordinal month */
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* printing helper functions */
|
|
|
|
void pdate( BYTE* value, int runflgs )
|
|
{
|
|
char *fmt;
|
|
static char *mths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" };
|
|
int y = value[0] + yroffs;
|
|
int m = 12; /* 0..11 = Jan..Dec, 12 indexes empty string */
|
|
int d = (value[1] << 8) | value[2];
|
|
|
|
if (runflgs & rf_caldate)
|
|
{
|
|
/* calendar date (yyyymmmdd) */
|
|
if (ordday_to_calday( y += 1900, d, &m, &d ))
|
|
fmt = " *********"; /* (ordday_to_calday failed!) */
|
|
else
|
|
fmt = " %4.4d%s%2.2d";
|
|
}
|
|
else /* ordinal day (yyddd) */
|
|
{
|
|
y %= 100;
|
|
fmt = " %2.2d%s%3.3d";
|
|
}
|
|
prtseg( fmt, y, mths[m], d );
|
|
}
|
|
|
|
void pdatex( BYTE* value, int runflgs )
|
|
{
|
|
(value[0] | value[1] ? pdate( value, runflgs )
|
|
: prtseg( runflgs & rf_caldate ? " ---------"
|
|
: " -----" ));
|
|
}
|
|
|
|
void pbyte( BYTE* value )
|
|
{
|
|
prtseg(" %3d", value[0]);
|
|
}
|
|
|
|
void phword( BYTE* value )
|
|
{
|
|
prtseg(" %5d", (value[0] << 8) | value[1]);
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* dataset extent processing */
|
|
|
|
int hword( HWORD value )
|
|
{
|
|
return (value[0] << 8) + value[1];
|
|
}
|
|
|
|
int extent_size( DSXTENT *ext, int heads )
|
|
{
|
|
return heads * ( hword( ext->xtecyl ) - hword( ext->xtbcyl ) ) +
|
|
( hword( ext->xtetrk ) - hword( ext->xtbtrk ) ) + 1;
|
|
}
|
|
|
|
int extents_array( DSXTENT extents[], int max, int *count, int heads )
|
|
{
|
|
int i;
|
|
int size = 0;
|
|
|
|
for (i=0; *count > 0 && i < max; i++)
|
|
{
|
|
if (extents[i].xttype)
|
|
{
|
|
size += extent_size( &extents[i], heads );
|
|
*count -= 1;
|
|
|
|
if (runflgs & rf_cchh)
|
|
{
|
|
prtcchhseg("%3d %4.4X/%4.4X %4.4X/%4.4X ",
|
|
numcchh + 1,
|
|
hword( extents[i].xtbcyl ), hword( extents[i].xtbtrk ),
|
|
hword( extents[i].xtecyl ), hword( extents[i].xtetrk ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// "%s record not found"
|
|
FWRMSG( stderr, HHC02471, "E", "Extents_array DSXTENT" );
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
int chainf3( int *size, BYTE *ptr, int *count )
|
|
{
|
|
FORMAT3_DSCB *f3dscb = NULL;
|
|
int rc = 0; /* prime for success */
|
|
|
|
while (*count > 0 && (ptr[0] || ptr[1] || ptr[2] || ptr[3] || ptr[4]))
|
|
{
|
|
//*debug*/fprintf(stderr, "*** %d %.2x%.2x %.2x%.2x %.2x\n",
|
|
//*debug*/ *count, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
|
|
|
|
if (read_block( cif, hword( &ptr[0] ), hword( &ptr[2] ), ptr[4],
|
|
(BYTE**) &f3dscb, NULL, NULL, NULL ) == 0)
|
|
{
|
|
switch (f3dscb->ds3fmtid)
|
|
{
|
|
case 0xf3:
|
|
{
|
|
if (0
|
|
|| f3dscb->ds3keyid[0] != 0x03
|
|
|| f3dscb->ds3keyid[1] != 0x03
|
|
|| f3dscb->ds3keyid[2] != 0x03
|
|
|| f3dscb->ds3keyid[3] != 0x03
|
|
)
|
|
{
|
|
break; /* Error: break out of switch */
|
|
}
|
|
else
|
|
{
|
|
*size += extents_array( &f3dscb->ds3extnt[0], 4, count, cif->heads );
|
|
*size += extents_array( &f3dscb->ds3adext[0], 9, count, cif->heads );
|
|
}
|
|
}
|
|
/* Fall through to below 0xf2 case */
|
|
/* GCC hint */
|
|
/* FALLTHRU */
|
|
case 0xf2:
|
|
{
|
|
/* Note: same offset for both F2 and F3 DSCBs */
|
|
ptr = &f3dscb->ds3ptrds[0];
|
|
continue; /* continue while loop */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Error */
|
|
rc = -1;
|
|
//*debug*/fprintf(stderr, "*** DSCB id=0x%.2x\n", f3dscb->ds3fmtid);
|
|
break;
|
|
|
|
} /* end of while loop */
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* list_contents partly based on dasdutil.c:search_key_equal */
|
|
|
|
int list_contents( CIFBLK *cif, DSXTENT *extent )
|
|
{
|
|
u_int cext = 0;
|
|
u_int ccyl = (extent[cext].xtbcyl[0] << 8) | extent[cext].xtbcyl[1];
|
|
u_int chead = (extent[cext].xtbtrk[0] << 8) | extent[cext].xtbtrk[1];
|
|
u_int ecyl = (extent[cext].xtecyl[0] << 8) | extent[cext].xtecyl[1];
|
|
u_int ehead = (extent[cext].xtetrk[0] << 8) | extent[cext].xtetrk[1];
|
|
|
|
EXTGUIMSG( "ETRK=%d\n", (ecyl * cif->heads) + ehead );
|
|
|
|
if (runflgs & rf_header)
|
|
{
|
|
/* display column headers allowing for optional columns */
|
|
|
|
char cchhbuf[32];
|
|
|
|
if (runflgs & rf_cchh)
|
|
STRLCPY( cchhbuf, CCHH_COLHDR );
|
|
else
|
|
cchhbuf[0] = 0;
|
|
|
|
LOGMSG("%s%*s%s", cchhbuf, -dsnlen, "Dsname",
|
|
runflgs & rf_caldate ? " Created " : " CREDT");
|
|
LOGMSG(runflgs & rf_refdate ? (runflgs & rf_caldate ? " Last Ref." : " REFDT") : "");
|
|
LOGMSG(runflgs & rf_expdate ? (runflgs & rf_caldate ? " Exp. Date" : " EXPDT") : "");
|
|
|
|
LOGMSG(" ORG RECFM LRECL BLKSZ Key Trks%%Use#Ext 2ndry_alloc\n");
|
|
}
|
|
|
|
do {
|
|
BYTE *ptr;
|
|
int rc = read_track( cif, ccyl, chead );
|
|
|
|
EXTGUIMSG( "CTRK=%d\n", (ccyl * cif->heads) + chead );
|
|
|
|
if (rc < 0)
|
|
return -1;
|
|
|
|
ptr = cif->trkbuf + CKD_TRKHDR_SIZE;
|
|
|
|
while (!end_of_track( ptr ))
|
|
{
|
|
|
|
CKD_RECHDR *rechdr = (CKD_RECHDR*)ptr;
|
|
|
|
int kl = rechdr->klen;
|
|
int dl = (rechdr->dlen[0] << 8) | rechdr->dlen[1];
|
|
|
|
FORMAT1_DSCB *f1dscb = (FORMAT1_DSCB*) (ptr + CKD_RECHDR_SIZE);
|
|
|
|
//*debug*/ LOGMSG("F1DSCB\n");
|
|
//*debug*/ data_dump(f1dscb, sizeof(FORMAT1_DSCB));
|
|
|
|
char dsname[ sizeof( f1dscb->ds1dsnam ) + 1 ];
|
|
char txtrecfm[5] = ""; /* recfm text */
|
|
char *tmpstr;
|
|
|
|
int lrecl;
|
|
int numext;
|
|
int space;
|
|
|
|
double value;
|
|
|
|
make_asciiz( dsname, sizeof( dsname ), ptr + CKD_RECHDR_SIZE, kl );
|
|
|
|
if (valid_dsname( dsname ))
|
|
{
|
|
if (runflgs == 0 && dsnlen == DEFAULT_DSNLEN)
|
|
{
|
|
prtseg("%s", dsname);
|
|
}
|
|
else
|
|
{
|
|
prtseg("%*s", -dsnlen, dsname);
|
|
|
|
if (runflgs & rf_info)
|
|
{
|
|
/* CREDT */
|
|
|
|
pdate( f1dscb->ds1credt, runflgs );
|
|
|
|
/* REFDT */
|
|
|
|
if (runflgs & rf_refdate)
|
|
pdatex( f1dscb->ds1refdt, runflgs );
|
|
|
|
/* EXPDT */
|
|
|
|
if (runflgs & rf_expdate)
|
|
pdatex( f1dscb->ds1expdt, runflgs );
|
|
|
|
/* DSORG */
|
|
|
|
tmpstr = "??";
|
|
|
|
if (f1dscb->ds1dsorg[0] == 0 ||
|
|
f1dscb->ds1dsorg[0] == DSORG_U)
|
|
{
|
|
if (f1dscb->ds1dsorg[1] == DSORG_AM)
|
|
tmpstr = "VS";
|
|
}
|
|
|
|
if (f1dscb->ds1dsorg[1] == 0)
|
|
{
|
|
switch (f1dscb->ds1dsorg[0] & (DSORG_PS | DSORG_DA | DSORG_PO))
|
|
{
|
|
case DSORG_PS: tmpstr = "PS"; break;
|
|
case DSORG_DA: tmpstr = "DA"; break;
|
|
case DSORG_PO: tmpstr = "PO"; break;
|
|
case 0: tmpstr = " "; break; /* none of the above */
|
|
default: /* don't change? */ break; /* multiple bits set */
|
|
}
|
|
}
|
|
prtseg(" %s%s", tmpstr, f1dscb->ds1dsorg[0] & DSORG_U ? "U" : " ");
|
|
|
|
/* RECFM */
|
|
|
|
switch (f1dscb->ds1recfm & RECFM_FORMAT)
|
|
{
|
|
case RECFM_FORMAT_F: tmpstr = "F"; break;
|
|
case RECFM_FORMAT_V: tmpstr = "V"; break;
|
|
default: tmpstr = "U"; break;
|
|
}
|
|
STRLCPY( txtrecfm, tmpstr );
|
|
|
|
if (f1dscb->ds1recfm & RECFM_BLOCKED) STRLCAT( txtrecfm, "B" );
|
|
if (f1dscb->ds1recfm & RECFM_SPANNED) STRLCAT( txtrecfm, "S" );
|
|
|
|
switch (f1dscb->ds1recfm & RECFM_CTLCHAR)
|
|
{
|
|
case RECFM_CTLCHAR_A: tmpstr = "A"; break;
|
|
case RECFM_CTLCHAR_M: tmpstr = "M"; break;
|
|
case RECFM_CTLCHAR_A | RECFM_CTLCHAR_M: tmpstr = "?"; break; /* both ?! */
|
|
default: tmpstr = ""; break; /* neither */
|
|
}
|
|
STRLCAT( txtrecfm, tmpstr );
|
|
|
|
if (f1dscb->ds1recfm & RECFM_TRKOFLOW) STRLCAT( txtrecfm, "T" );
|
|
|
|
prtseg(" %-5s", txtrecfm);
|
|
|
|
/* LRECL */
|
|
|
|
lrecl = (f1dscb->ds1lrecl[0] << 8) | f1dscb->ds1lrecl[1];
|
|
|
|
if (lrecl) prtseg(" %5d", lrecl);
|
|
else prtseg(" ");
|
|
|
|
/* BLKSZ, KEYLN */
|
|
|
|
phword( f1dscb->ds1blkl ); /* BLKSZ */
|
|
pbyte( &f1dscb->ds1keyl ); /* KEYLN */
|
|
|
|
/* space allocated */
|
|
|
|
numext = f1dscb->ds1noepv;
|
|
//*debug*/ LOGMSG("NUMEXT = %5d", numext);
|
|
|
|
space = extents_array( &f1dscb->ds1ext1, 3, &numext, cif->heads );
|
|
//*debug*/ LOGMSG("SPACE nach extents_array = %d", space);
|
|
|
|
chainf3( &space, &f1dscb->ds1ptrds[0], &numext );
|
|
//*debug*/ LOGMSG("SPACE nach chainf3 = %d", space);
|
|
|
|
prtseg(" %5d", space);
|
|
|
|
/* % of allocated spaced used */
|
|
|
|
/* fraction of last track used = 1 - ds1trbal / trkzize */
|
|
value = 1.0 - (double)hword( &f1dscb->ds1trbal[0] ) / (cif->trksz);
|
|
|
|
/* add in the number of full tracks used */
|
|
value += hword( &f1dscb->ds1lstar[0] );
|
|
|
|
if (!space)
|
|
prtseg(" ");
|
|
else
|
|
{
|
|
value = value * 100 / space; /* % space used */
|
|
prtseg(" %3.0f", value);
|
|
}
|
|
|
|
/* Number of extents */
|
|
|
|
pbyte( &f1dscb->ds1noepv ); /* #EXT */
|
|
|
|
/* SCALO */
|
|
|
|
if (DS1SCALO_UNITS_ABSTR
|
|
== (f1dscb->ds1scalo[0] & DS1SCALO_UNITS))
|
|
{
|
|
prtseg(" %-11s", "ABSTR");
|
|
}
|
|
else
|
|
{
|
|
tmpstr = "CYL";
|
|
|
|
switch (f1dscb->ds1scalo[0] & DS1SCALO_UNITS)
|
|
{
|
|
case DS1SCALO_UNITS_BLK: tmpstr = "BLK"; break;
|
|
case DS1SCALO_UNITS_TRK: tmpstr = "TRK"; break;
|
|
case DS1SCALO_UNITS_CYL: break;
|
|
}
|
|
prtseg(" %3s%8d", tmpstr,
|
|
(((f1dscb->ds1scalo[1] << 8) +
|
|
f1dscb->ds1scalo[2]) << 8) +
|
|
f1dscb->ds1scalo[3]);
|
|
}
|
|
|
|
} /* end if (runflgs & rf_info) */
|
|
}
|
|
|
|
prtseg("\n");
|
|
print_line_from_segs();
|
|
|
|
} /* end if (valid_dsname( dsname )) */
|
|
|
|
ptr += CKD_RECHDR_SIZE + kl + dl;
|
|
|
|
} /* end while (!end_of_track( ptr )) */
|
|
|
|
chead++;
|
|
|
|
if (chead >= cif->heads)
|
|
{
|
|
ccyl++;
|
|
chead = 0;
|
|
}
|
|
|
|
} while (ccyl < ecyl || (ccyl == ecyl && chead <= ehead));
|
|
|
|
/* If we "printed" any lines... */
|
|
if (numlines)
|
|
{
|
|
int i;
|
|
|
|
/* Sort them into ascending sequence by dsname */
|
|
if (!(runflgs & rf_nosort))
|
|
qsort( linestab, numlines, sizeof( linestab ), sort_linestab );
|
|
|
|
/* NOW actually print them all for real */
|
|
for (i=0; i < numlines; ++i)
|
|
{
|
|
LOGMSG( "%s\n", RTRIM( linestab[i] ));
|
|
free( (linestab[i]) );
|
|
}
|
|
|
|
free( linestab );
|
|
linestab = NULL;
|
|
numlines = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* do_ls_cif based on dasdutil.c:build_extent_array */
|
|
|
|
int do_ls_cif( CIFBLK *cif, char *sfile )
|
|
{
|
|
int rc;
|
|
|
|
U32 cyl;
|
|
U8 head;
|
|
U8 rec;
|
|
|
|
U16 rlen;
|
|
U8 klen;
|
|
|
|
unsigned char *vol1data;
|
|
FORMAT4_DSCB *f4dscb;
|
|
|
|
char volser[7];
|
|
|
|
rc = read_block( cif, 0, 0, 3, 0, 0, &vol1data, &rlen );
|
|
|
|
if (rc < 0)
|
|
return -1;
|
|
|
|
if (rc > 0)
|
|
{
|
|
// "%s record not found"
|
|
FWRMSG( stderr, HHC02471, "E", "VOL1" );
|
|
return -1;
|
|
}
|
|
|
|
make_asciiz( volser, sizeof( volser ), vol1data + 4, 6 );
|
|
|
|
if (sfile)
|
|
LOGMSG( "\nVOLSER: %-6s \"%s\" sf=\"%s\"\n\n", volser, cif->fname, &sfile[3] );
|
|
else
|
|
LOGMSG( "\nVOLSER: %-6s \"%s\"\n\n", volser, cif->fname );
|
|
|
|
cyl = (vol1data[11] << 8) | vol1data[12];
|
|
head = (vol1data[13] << 8) | vol1data[14];
|
|
rec = vol1data[15];
|
|
|
|
rc = read_block( cif, cyl, head, rec, (void *)&f4dscb, &klen, 0, 0 );
|
|
|
|
if (rc < 0)
|
|
return -1;
|
|
|
|
if (rc > 0)
|
|
{
|
|
// "%s record not found"
|
|
FWRMSG( stderr, HHC02471, "E", "Format 4 DSCB" );
|
|
return -1;
|
|
}
|
|
|
|
return list_contents( cif, &f4dscb->ds4vtoce );
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
int do_ls( char *file, char *sfile )
|
|
{
|
|
LOGMSG("\n");
|
|
|
|
if (!(cif = open_ckd_image( file, sfile, O_RDONLY | O_BINARY, IMAGE_OPEN_NORMAL )))
|
|
return -1;
|
|
|
|
if (do_ls_cif( cif, sfile ) != 0)
|
|
{
|
|
close_ckd_image( cif );
|
|
cif = NULL;
|
|
return -1;
|
|
}
|
|
|
|
if (close_ckd_image( cif ) != 0)
|
|
{
|
|
cif = NULL;
|
|
return -1;
|
|
}
|
|
|
|
cif = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
int main( int argc, char **argv )
|
|
{
|
|
char *pgm; /* less any extension (.ext) */
|
|
int rc = 0;
|
|
char *fn, *sfn;
|
|
|
|
INITIALIZE_UTILITY( UTILITY_NAME, UTILITY_DESC, &pgm );
|
|
|
|
if (argc < 2)
|
|
{
|
|
// "Usage: %s [-option [-option ... ]] ckdfile [sf=shadow-file-name]%s"
|
|
WRMSG( HHC02463, "I", pgm );
|
|
exit(2);
|
|
}
|
|
|
|
cchh_colhdr_width = (int) strlen( CCHH_COLHDR );
|
|
|
|
/*
|
|
* If your version of Hercules doesn't have support in its
|
|
* dasdutil.c for turning off verbose messages, then remove
|
|
* the following line but you'll have to live with chatty
|
|
* progress output on stdout.
|
|
*/
|
|
set_verbose_util(0); /* (don't be chatty) */
|
|
|
|
while (*++argv)
|
|
{
|
|
fn = *argv;
|
|
|
|
if (strcmp( fn, "-nosort" ) == 0) /* do NOT sort results */
|
|
{
|
|
runflgs |= rf_nosort;
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-info" ) == 0) /* show F1 info */
|
|
{
|
|
runflgs |= rf_info;
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-caldt" ) == 0) /* calendar date format */
|
|
{
|
|
runflgs |= (rf_caldate | rf_info);
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-expdt" ) == 0) /* show expiry date */
|
|
{
|
|
runflgs |= (rf_expdate | rf_info);
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-refdt" ) == 0) /* show last-reference date */
|
|
{
|
|
runflgs |= (rf_refdate | rf_info);
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-hdr" ) == 0) /* show column headers */
|
|
{
|
|
runflgs |= (rf_header | rf_info);
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-cchh" ) == 0) /* show extent cchh info */
|
|
{
|
|
runflgs |= (rf_cchh | rf_info);
|
|
continue;
|
|
}
|
|
if (1
|
|
&& strlen( *argv ) > 6
|
|
&& !memcmp( fn, "-dsnl=", 6 )) /* restrict dsname width (custom) */
|
|
{
|
|
runflgs |= rf_info;
|
|
dsnlen = atoi( fn + 6 );
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-dsnl" ) == 0) /* restrict dsname width (default) */
|
|
{
|
|
runflgs |= rf_info;
|
|
dsnlen = 26;
|
|
continue;
|
|
}
|
|
if (1
|
|
&& strlen( *argv ) > 8
|
|
&& !memcmp( fn, "-yroffs=", 8 ))/* year offset (custom) */
|
|
{
|
|
runflgs |= rf_info;
|
|
yroffs = atoi( fn + 8 );
|
|
continue;
|
|
}
|
|
if (strcmp( fn, "-yroffs" ) == 0) /* year offset (default) */
|
|
{
|
|
runflgs |= rf_info;
|
|
yroffs = 28;
|
|
continue;
|
|
}
|
|
|
|
/* Check for shadow file */
|
|
if (1
|
|
&& *(argv+1)
|
|
&& strlen( *(argv+1) ) > 3
|
|
&& memcmp( *(argv+1), "sf=", 3 ) == 0
|
|
)
|
|
sfn = *++argv;
|
|
else sfn = NULL;
|
|
|
|
if (do_ls( fn, sfn ))
|
|
rc = 1;
|
|
}
|
|
|
|
LOGMSG("\nEnd of %s; rc=%d\n", UTILITY_NAME, rc );
|
|
return rc;
|
|
}
|
|
|
|
/*********************************************************************/
|