/*
 * File...........: s390-tools/dasdview/dasdview.c
 * Author(s)......: Volker Sameske <sameske@de.ibm.com>
 * Bugreports.to..: <Linux390@de.ibm.com>
 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2001-2002
 *
 * History of changes (starts March 2002)
 * 2002-03-12 removed dependency to kernel headers
 * 2002-05-10 changed API version handling
 * 2002-07-01 added -j option to display volser
 */

#define _LARGEFILE64_SOURCE    /* needed for unistd.h */
#define _FILE_OFFSET_BITS 64   /* needed for unistd.h */

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>

#include <sys/stat.h>
#include <sys/ioctl.h>


#include "vtoc.h"
#include "dasdview.h"

static int api_version;

static void
dasdview_usage(void)
{
	printf("\nprints DASD information:\n\n");
	printf("dasdview [-b begin] [-s size] [-1|-2] \n"
	       "         [-i] [-x] [-j]\n"
	       "         [-l] [-t {info|f1|f4|f5|f7|all}] \n"
	       "         [-h] [-?] [-v] \n"
	       "         {-n devno|-f node}\n"
	       "\nwhere:\n"
	       "-b: prints a DASD dump from 'begin'\n"
	       "-s: prints a DASD dump with size 'size'\n"
	       "-1: use format 1 for the dump (default)\n"
	       "-2: use format 2 for the dump\n"
	       "    'begin' and 'size' can have the following format:\n"
	       "    x[k|m|b|t|c]\n"
	       "    for x byte, kilobyte, megabyte, blocks, tracks and\n"
	       "    cylinders\n"
	       "-i: prints general DASD information and geometry\n"
	       "-x: prints extended DASD information\n"
	       "-j: prints the volume serial number (volume identifier)\n"
	       "-l: prints information about the volume label\n"
	       "-t: prints the table of content (VTOC)\n"
	       "-h: prints this usage text\n"
	       "-?: prints this usage text\n"
	       "-v: prints the version number\n"
	       "-n: specifies the device by a device number (needs devfs)\n"
	       "-f: specifies a device by a device node\n");
}


static void 
dasdview_error(enum dasdview_failure why) 
{
        char    error[2*LINE_LENGTH], *message = error;

	switch (why) 
	{
        case open_error:
	        sprintf(error, "%s open error\n%s\n", 
			DASDVIEW_ERROR, error_str);
		break;
        case seek_error:
	        sprintf(error, "%s seek error\n%s\n", 
			DASDVIEW_ERROR, error_str);
		break;
        case read_error:
	        sprintf(error, "%s read error\n%s\n", 
			DASDVIEW_ERROR, error_str);
		break;
        case ioctl_error:
	        sprintf(error, "%s ioctl error\n%s\n", 
			DASDVIEW_ERROR, error_str);
		break;
        case usage_error:
	        sprintf(error, "%s usage error\n%s\n", 
			DASDVIEW_ERROR, error_str);
		break;
        case disk_layout:
	        sprintf(error, "%s disk layout error\n%s\n", 
			DASDVIEW_ERROR, error_str);
		break;
        case vtoc_error:
	        sprintf(error, "%s VTOC error\n%s\n", 
			DASDVIEW_ERROR, error_str);
		break;
	default: 
	        sprintf(error,"%s bug\n%s\n",
			DASDVIEW_ERROR, error_str);
	}

	fputc('\n', stderr);
	fputs(message, stderr);

	exit(-1);
}


/*
 * replace special characters with dots and question marks
 */
static void 
dot (unsigned char label[16]) {

        int i;
	unsigned char c; 

  	for (i = 0; i < 16; i++) {

	        c = label[i];
		if (c <= 0x20) label[i] = '?';
		if (c == 0x00) label[i] = '.';
		if (c == 0x60) label[i] = '?';
		if (c >= 0x7f) label[i] = '?';
	}
}


static void
dasdview_init_info(dasdview_info_t *info)
{
	bzero(info->device, sizeof(info->device));
	bzero(&info->dasd_info, sizeof(info->dasd_info));
	bzero(&info->dasd_info2, sizeof(info->dasd_info2));
	info->blksize = 0;
	info->devno   = 0x0;
	bzero(&info->geo, sizeof(info->geo));

	info->begin   = 0;
	info->size    = 0;
	info->format1 = 0;
	info->format2 = 0;

	info->action_specified = 0;
	info->devno_specified  = 0;
	info->node_specified   = 0;
	info->begin_specified  = 0;
	info->size_specified   = 0;
	info->short_info       = 0;
	info->long_info        = 0;
	info->volser           = 0;
	info->vtoc             = 0;
	info->vtoc_info        = 0;
	info->vtoc_f1          = 0;
	info->vtoc_f4          = 0;
	info->vtoc_f5          = 0;
	info->vtoc_f7          = 0;
	info->vtoc_all         = 0;
	info->vlabel_info      = 0;

	bzero(&info->f1, NO_F1_LABELS * sizeof(format1_label_t));
	bzero(&info->f4, sizeof(format4_label_t));
	bzero(&info->f5, sizeof(format5_label_t));
	bzero(&info->f7, sizeof(format7_label_t));
	info->f1c = 0;
	info->f4c = 0;
	info->f5c = 0;
	info->f7c = 0;
}

static void
dasdview_get_info(dasdview_info_t *info)
{
	int f;

	f = open(info->device, O_RDONLY);
	if (f == -1)
	{
		sprintf(error_str,"Could not open device '%s'.\n"
			"Maybe you are using the -n option without devfs or \n"
			"you have specified an unknown device or \n"
			"you are not authorized to do that.\n", 
			info->device);
		dasdview_error(open_error);
	}

	// get dasd driver API version
	if (ioctl(f,DASDAPIVER,&api_version)) {
		close(f);
		sprintf(error_str, 
			"Could not retrieve DASD_MIN_API_VERSION");
		dasdview_error(ioctl_error); 
	}

	// check API versions
	if (api_version < DASD_MIN_API_VERSION) {
		close(f);
		sprintf(error_str,
			"WARNING: This API version '%d' doesn't match " \
			"with the API version of the DASD driver '%d'!\n",
			DASD_MIN_API_VERSION, api_version);
		dasdview_error(ioctl_error);
	}

	if (api_version == 1) {
		close(f);
		sprintf(error_str, "WARNING: The dasd driver API version '1' "
			"is not supported!\n");
		dasdview_error(ioctl_error);
	}


	/* get disk geometry */
	if (ioctl(f, HDIO_GETGEO, &info->geo) != 0) 
	{
	        close(f);
		sprintf(error_str, "Could not retrieve disk geometry " \
			"information.");
		dasdview_error(ioctl_error); 
	}

	if (ioctl(f, BLKSSZGET, &info->blksize) != 0)
	{
	        close(f);
		sprintf(error_str,
			"Could not retrieve blocksize information!\n");
		dasdview_error(ioctl_error);
	}

	/* get disk information */
	if (api_version < 2) {
	        if (ioctl(f, BIODASDINFO, &info->dasd_info) != 0) {
		        close(f);
			sprintf(error_str, "Could not retrieve disk information.");
			dasdview_error(ioctl_error);
		}
		memcpy(&info->dasd_info2, &info->dasd_info, 
		       sizeof(info->dasd_info));
	} else {
	        if (ioctl(f, BIODASDINFO2, &info->dasd_info2) != 0) {
		        close(f); 
			sprintf(error_str, "Could not retrieve disk information.");
			dasdview_error(ioctl_error);
		}
	}

	close(f);
}


static void
dasdview_parse_input(unsigned long long *p, dasdview_info_t *info, char *s)
{
	unsigned long long l=0;

	switch (s[strlen(s)-1]) 
	{
		case 'k':
		case 'K':
		        l = 1024LL * strtoull(s, NULL, 0);
			break;
		case 'm':
		case 'M':
		        l = 1024LL * 1024LL * strtoull(s, NULL, 0);
			break;
		case 't':
		case 'T':
		        l = (unsigned long long) info->blksize * 
			    (unsigned long long) info->geo.sectors * 
			    strtoull(s, NULL, 0);
			break;
		case 'b':
		case 'B':
		        l = (unsigned long long) info->blksize * 
			    strtoull(s, NULL, 0);
			break;
		case 'c':
		case 'C':
		        l = (unsigned long long) info->blksize * 
			    (unsigned long long) info->geo.sectors *
			    (unsigned long long) info->geo.heads * 
			    strtoull(s, NULL, 0);
			break;
		default:
		        l = strtoull(s, NULL, 0);
	}

	*p = l;
}

static void
dasdview_print_info(dasdview_info_t *info)
{
	printf("\n--- general DASD information -----------------" \
	       "---------------------------------\n");
	printf("device node            : %s\n",info->device);
        printf("device number          : hex %x  \tdec %d\n", 
	       info->dasd_info2.devno,
	       info->dasd_info2.devno);
	printf("type                   : %4s\n", info->dasd_info2.type);
	printf("device type            : hex %x  \tdec %d\n", 
	       info->dasd_info2.dev_type,
	       info->dasd_info2.dev_type);
	printf("\n--- DASD geometry ----------------------------" \
	       "---------------------------------\n");
	printf("number of cylinders    : hex %x  \tdec %d\n", 
	       info->geo.cylinders,
	       info->geo.cylinders);
	printf("tracks per cylinder    : hex %x  \tdec %d\n", 
	       info->geo.heads,
	       info->geo.heads);
	printf("blocks per track       : hex %x  \tdec %d\n", 
	       info->geo.sectors,
	       info->geo.sectors);
	printf("blocksize              : hex %x  \tdec %d\n", 
	       info->blksize,
	       info->blksize);
}


static void
dasdview_print_more_info(dasdview_info_t *info)
{
	int i, j, k;
	int cpl=16; /* chars per line */
	
	printf("\n--- extended DASD information ----------------" \
	       "---------------------------------\n");
        printf("real device number     : hex %x  \tdec %d\n", 
	       info->dasd_info2.real_devno, 
	       info->dasd_info2.real_devno);
	printf("subchannel identifier  : hex %x  \tdec %d\n", 
	       info->dasd_info2.schid, 
	       info->dasd_info2.schid);
	printf("CU type  (SenseID)     : hex %x  \tdec %d\n", 
	       info->dasd_info2.cu_type, 
	       info->dasd_info2.cu_type);
	printf("CU model (SenseID)     : hex %x  \tdec %d\n", 
	       info->dasd_info2.cu_model,  
	       info->dasd_info2.cu_model);
	printf("device type  (SenseID) : hex %x  \tdec %d\n", 
	       info->dasd_info2.dev_type, 
	       info->dasd_info2.dev_type);
	printf("device model (SenseID) : hex %x  \tdec %d\n", 
	       info->dasd_info2.dev_model, 
	       info->dasd_info2.dev_model);
	printf("open count             : hex %x  \tdec %d\n", 
	       info->dasd_info2.open_count, 
	       info->dasd_info2.open_count);
        printf("req_queue_len          : hex %x  \tdec %d\n", 
	       info->dasd_info2.req_queue_len, 
	       info->dasd_info2.req_queue_len);
	printf("chanq_len              : hex %x  \tdec %d\n", 
	       info->dasd_info2.chanq_len, 
	       info->dasd_info2.chanq_len);
	printf("status                 : hex %x  \tdec %d\n", 
	       info->dasd_info2.status, 
	       info->dasd_info2.status);
	printf("label_block            : hex %x  \tdec %d\n", 
	       info->dasd_info2.label_block, 
	       info->dasd_info2.label_block);
	printf("FBA_layout             : hex %x  \tdec %d\n", 
	       info->dasd_info2.FBA_layout, 
	       info->dasd_info2.FBA_layout);
        printf("characteristics_size   : hex %x  \tdec %d\n", 
	       info->dasd_info2.characteristics_size,
	       info->dasd_info2.characteristics_size);
        printf("confdata_size          : hex %x  \tdec %d\n", 
	       info->dasd_info2.confdata_size,
	       info->dasd_info2.confdata_size);

	if (api_version > 1) {
	        printf("format                 : hex %x  \tdec %d      \t%s\n", 
		       info->dasd_info2.format, 
		       info->dasd_info2.format,
		       info->dasd_info2.format == DASD_FORMAT_NONE ? "NOT formatted" :
		       info->dasd_info2.format == DASD_FORMAT_LDL  ? "LDL formatted" :
		       info->dasd_info2.format == DASD_FORMAT_CDL  ? "CDL formatted" :
		       "unknown format");
		printf("features               : hex %x  \tdec %d      \t%s\n", 
		       info->dasd_info2.features, 
		       info->dasd_info2.features,
		       info->dasd_info2.features == DASD_FEATURE_READONLY ? "ro" :
		       "default");
	}

	j = sizeof(info->dasd_info2.characteristics);
	for (k=0; k<(j/cpl); k++)
	{
		if (k == 0)
			printf("\ncharacteristics        : "); 
		else
			printf("                         ");
		for (i=0; i<cpl; i++)
		{ 
			printf("%02x",
			       info->dasd_info2.characteristics[k*cpl+i]);
			if ((i+1)%4 == 0) printf(" ");
			if ((i+1)%8 == 0) printf(" ");
		}
		printf("\n");
	}

	j = sizeof(info->dasd_info2.configuration_data);
	for (k=0; k<(j/cpl); k++)
	{
		if (k == 0)
			printf("\nconfiguration_data     : "); 
		else
			printf("                         ");
		for (i=0; i<cpl; i++)
		{ 
			printf("%02x",
			       info->dasd_info2.configuration_data[k*cpl+i]);
			if ((i+1)%4 == 0) printf(" ");
			if ((i+1)%8 == 0) printf(" ");
		}
		printf("\n");
	}
}


static void
dasdview_read_vlabel(dasdview_info_t *info, volume_label_t *vlabel)
{
	volume_label_t tmp;
	unsigned long  pos;

	pos = info->dasd_info2.label_block * info->blksize;

	bzero(vlabel, sizeof(volume_label_t));
	if ((strncmp(info->dasd_info2.type, "ECKD", 4) == 0) && 
	    (!info->dasd_info2.FBA_layout)) {
		/* OS/390 and zOS compatible disk layout */
		vtoc_read_volume_label(info->device, pos, vlabel);
	}
	else {
		/* standard LINUX disk layout */
		vtoc_read_volume_label(info->device, pos, &tmp);
		memcpy(vlabel->vollbl, &tmp, sizeof(tmp)-4);
	}
}


static void
dasdview_print_vlabel(dasdview_info_t *info)
{
	volume_label_t vlabel;

	char s4[5], t4[5], s5[6], t5[6], s6[7], t6[7];
	char s14[15], t14[15], s29[30], t29[30];
	int i;

	dasdview_read_vlabel(info, &vlabel);

	printf("\n--- volume label -----------------------------" \
	       "---------------------------------\n");

	bzero(s4, 5); bzero(t4, 5); strncpy(s4, vlabel.volkey, 4);
	printf("volume label key        : ascii  '%4s'\n", s4);
	vtoc_ebcdic_dec(s4, t4, 4);
	printf("                        : ebcdic '%4s'\n", t4);
	printf("                        : hex    ");
	for (i=0; i<4; i++) printf("%02x", s4[i]);

	bzero(s4, 5); bzero(s4, 5); strncpy(s4, vlabel.vollbl, 4);
	printf("\n\nvolume label identifier : ascii  '%4s'\n", s4);
	vtoc_ebcdic_dec(s4, t4, 4);
	printf("                        : ebcdic '%4s'\n", t4);
	printf("                        : hex    ");
	for (i=0; i<4; i++) printf("%02x", s4[i]);

	bzero(s6, 7); bzero(t6, 7); strncpy(s6, vlabel.volid, 6);
	printf("\n\nvolume identifier       : ascii  '%6s'\n", s6);
	vtoc_ebcdic_dec(s6, t6, 6);
	printf("                        : ebcdic '%6s'\n", t6);
	printf("                        : hex    ");
	for (i=0; i<6; i++) printf("%02x", s6[i]);

	printf("\n\nsecurity byte           : hex    %02x\n", vlabel.security);

	printf("\n\nVTOC pointer            : hex    %04x%04x%02x ",
	       vlabel.vtoc.cc, vlabel.vtoc.hh, vlabel.vtoc.b);
	if ((vlabel.vtoc.cc == 0x4040) && (vlabel.vtoc.hh == 0x4040) && 
	    (vlabel.vtoc.b == 0x40))
		printf("\n");
	else
		printf("\n                                 " \
		       "(cyl %d, trk %d, blk %d)\n\n", 
		       vlabel.vtoc.cc, vlabel.vtoc.hh, vlabel.vtoc.b);

	bzero(s5, 6); bzero(t5, 6); strncpy(s5, vlabel.res1, 5);
	printf("reserved                : ascii  '%5s'\n", s5);
	vtoc_ebcdic_dec(s5, t5, 5);
	printf("                        : ebcdic '%5s'\n", t5);
	printf("                        : hex    ");
	for (i=0; i<5; i++) printf("%02x", s5[i]);

	bzero(s4, 5); bzero(t4, 5); strncpy(s4, vlabel.cisize, 4);
	printf("\n\nCI size for FBA         : ascii  '%4s'\n", s4);
	vtoc_ebcdic_dec(s4, t4, 4);
	printf("                        : ebcdic '%4s'\n", t4);
	printf("                        : hex    ");
	for (i=0; i<4; i++) printf("%02x", s4[i]);

	bzero(s4, 5); bzero(t4,5); strncpy(s4, vlabel.blkperci, 4);
	printf("\n\nblocks per CI (FBA)     : ascii  '%4s'\n", s4);
	vtoc_ebcdic_dec(s4, t4, 4);
	printf("                        : ebcdic '%4s'\n", t4);
	printf("                        : hex    ");
	for (i=0; i<4; i++) printf("%02x", s4[i]);

	bzero(s4, 5); bzero(t4, 5); strncpy(s4, vlabel.labperci, 4);
	printf("\n\nlabels per CI (FBA)     : ascii  '%4s'\n", s4);
	vtoc_ebcdic_dec(s4, t4, 4);
	printf("                        : ebcdic '%4s'\n", t4);
	printf("                        : hex    ");
	for (i=0; i<4; i++) printf("%02x", s4[i]);

	bzero(s4, 5); bzero(t4, 5); strncpy(s4, vlabel.res2, 4);
	printf("\n\nreserved                : ascii  '%4s'\n", s4);
	vtoc_ebcdic_dec(s4, t4, 4);
	printf("                        : ebcdic '%4s'\n", t4);
	printf("                        : hex    ");
	for (i=0; i<4; i++) printf("%02x", s4[i]);

	bzero(s14, 15); bzero(t14, 15); strncpy(s14, vlabel.lvtoc, 14);
	printf("\n\nowner code for VTOC     : ascii  '%14s'\n", s14);
	vtoc_ebcdic_dec(s14, t14, 14);
	printf("                          ebcdic '%14s'\n", t14);
	printf("                          hex    ");
	for (i=0; i<14; i++) 
	{
		printf("%02x", s14[i]);
		if ((i+1)%4 == 0) printf(" ");
		if ((i+1)%8 == 0) printf(" ");
	}

	bzero(s29, 30); strncpy(s29, vlabel.res3, 29);
	printf("\n\nreserved                : ascii  '%29s'\n", s29);
	bzero(t29, 30);
	vtoc_ebcdic_dec(s29, t29, 29);
	printf("                          ebcdic '%29s'\n", t29);
	printf("                          hex    ");
	for (i=0; i<29; i++) 
	{
		printf("%02x", s29[i]);
		if ((i+1)%4 == 0) printf(" ");
		if ((i+1)%8 == 0) printf(" ");
		if ((i+1)%16 == 0) printf("\n                " \
					  "                 ");
	}
	printf("\n");
}


static void
dasdview_print_volser(dasdview_info_t *info)
{
	volume_label_t vlabel;
	char           volser[7];
	char           vollbl[5];

	dasdview_read_vlabel(info, &vlabel);

	bzero(vollbl, 5); 
	bzero(volser, 7); 
	strncpy(vollbl, vlabel.vollbl, 4);
	vtoc_ebcdic_dec(vollbl, vollbl, 4);

	if ((strncmp(vollbl, "VOL1", 4) == 0)||(strncmp(vollbl, "LNX1", 4) == 0)) {
	        strncpy(volser, vlabel.volid, 6);
		vtoc_ebcdic_dec(volser, volser, 6);
	} else
	        strncpy(volser, "      ", 6);

	printf("%6.6s\n", volser);
}


static void
dasdview_read_vtoc(dasdview_info_t *info)
{
        volume_label_t vlabel;
	format1_label_t tmp;
	unsigned long pos, vtocblk, maxblk;
	int i;

	pos = info->dasd_info2.label_block * info->blksize;

	bzero(&vlabel, sizeof(vlabel));
	if ((strncmp(info->dasd_info2.type, "ECKD", 4) == 0) && 
	    (!info->dasd_info2.FBA_layout))
	{
		/* OS/390 and zOS compatible disk layout */
		vtoc_read_volume_label(info->device, pos, &vlabel);
	}
	else
	{
		sprintf(error_str, "%s is not formatted with the z/OS " \
			"compatible disk layout!\n", info->device);
		dasdview_error(disk_layout);
	}

	vtocblk = vlabel.vtoc.cc * info->geo.heads +
		vlabel.vtoc.hh * info->geo.sectors +
		vlabel.vtoc.b;

	maxblk = info->geo.cylinders * info->geo.heads * info->geo.sectors;

	if ((vtocblk <= 0) || (vtocblk > maxblk))
	{
		sprintf(error_str, 
			"Volume label VTOC pointer is not valid!\n");
		dasdview_error(vtoc_error);
	} 

	vtoc_read_label(info->device, (vtocblk - 1) * info->blksize, 
			NULL, &info->f4, NULL, NULL);

	if ((info->f4.DS4KEYCD[0] != 0x04) || 
	    (info->f4.DS4KEYCD[43] != 0x04) || 
	    (info->f4.DS4IDFMT != 0xf4)) 
	{
		/* format4 DSCB is invalid */
		sprintf(error_str, "Format 4 DSCB is invalid!\n");
		dasdview_error(vtoc_error);
	}

	info->f4c++;
	pos = (vtocblk - 1) * info->blksize;

	for (i=1; i<info->geo.sectors; i++)
	{
	        pos += info->blksize;
	        vtoc_read_label(info->device, pos, &tmp, NULL, NULL, NULL);

		switch (tmp.DS1FMTID)
		{
		  case 0xf1:
		          memcpy(&info->f1[info->f1c], &tmp, 
				 sizeof(format1_label_t));
		          info->f1c++;
		          break;
		  case 0xf4:
		          info->f4c++;
		          break;
		  case 0xf5:
		          memcpy(&info->f5, &tmp, sizeof(format1_label_t));
		          info->f5c++;
		          break;
		  case 0xf7:
		          memcpy(&info->f7, &tmp, sizeof(format1_label_t));
		          info->f7c++;
		          break;
		  default:
			  printf("Unknown label in VTOC detected (id=%x)\n",
				 tmp.DS1FMTID);
		}
	}

	if (info->f4c > 1)
        {
		sprintf(error_str, "More than one FMT4 DSCB!\n");
		dasdview_error(vtoc_error);
	}

	if (info->f5c > 1)
        {
		sprintf(error_str, "More than one FMT5 DSCB!\n");
		dasdview_error(vtoc_error);
	}

	if (info->f7c > 1)
        {
		sprintf(error_str, "More than one FMT7 DSCB!\n");
		dasdview_error(vtoc_error);
	}
}


static void
dasdview_print_vtoc_info(dasdview_info_t *info)
{
        int i;
	char s6[7], s13[14], s44[45];
	unsigned long l1 ,l2;

	printf("--- VTOC info --------------------------------" \
	       "---------------------------------\n");
	printf("The VTOC contains:\n");
	printf("  %d format 1 label(s)\n", info->f1c);
	printf("  %d format 4 label(s)\n", info->f4c);
	printf("  %d format 5 label(s)\n", info->f5c);
	printf("  %d format 7 label(s)\n", info->f7c);

	if (info->f1c < 1)
	{
	        printf("There are no partitions defined.\n");
	} else {
	        printf("Other S/390 and zSeries operating systems would see " \
		       "the following data sets:\n");
		printf(" +----------------------------------------------+" \
		       "--------------+--------------+\n");
		printf(" | data set                                     |" \
		       " start        | end          |\n");
		printf(" +----------------------------------------------+" \
		       "--------------+--------------+\n");

		for (i=0; i<info->f1c; i++)
		{
		        bzero(s44, 45);
			strncpy(s44, info->f1[i].DS1DSNAM, 44);
			vtoc_ebcdic_dec(s44, s44, 44);
		        bzero(s6, 7);
			strncpy(s6, info->f1[i].DS1DSSN, 6);
			vtoc_ebcdic_dec(s6, s6, 6);
		        bzero(s13, 14);
			strncpy(s13, info->f1[i].DS1SYSCD, 13);
			vtoc_ebcdic_dec(s13, s13, 13);

			l1 = (unsigned long) info->f1[i].DS1EXT1.llimit.cc *
			     (unsigned long) info->geo.heads +
			     (unsigned long) info->f1[i].DS1EXT1.llimit.hh;
			l2 = (unsigned long) info->f1[i].DS1EXT1.ulimit.cc *
			     (unsigned long) info->geo.heads +
			     (unsigned long) info->f1[i].DS1EXT1.ulimit.hh;

			printf(" | %44s |          trk |          trk |\n",
			       s44);
			printf(" | data set serial number :" \
			       " '%6s'            |" \
			       " %12ld | %12ld |\n", s6, l1, l2);
			printf(" | system code            :" \
			       " '%13s'     |" \
			       "      cyl/trk |      cyl/trk |\n", s13);
			printf(" | creation date          :" \
			       "  year %4d, day %3d |" \
			       " %8d/%3d | %8d/%3d |\n",
			       info->f1[i].DS1CREDT.year + 1900,
			       info->f1[i].DS1CREDT.day,
			       info->f1[i].DS1EXT1.llimit.cc,
			       info->f1[i].DS1EXT1.llimit.hh,
			       info->f1[i].DS1EXT1.ulimit.cc,
			       info->f1[i].DS1EXT1.ulimit.hh);
			printf(" +-----------------------------------------" \
			       "-----+--------------+--------------+\n");
		}
	}

}


static void
dasdview_print_vtoc_f1(dasdview_info_t *info)
{
        int i, j;
	char s6[7], s13[14], s44[45];

	bzero(s6, 7);
	bzero(s13, 14);
	bzero(s44, 45);

	printf("--- VTOC format 1 labels ----------------------" \
	       "---------------------------------\n");

	if (info->f1c < 1)
	{
	        printf("This VTOC doesn't contain a format 1 label.\n");
		return;
	}

	for (j=0; j<info->f1c; j++)
	{
	        printf("\n--- format 1 DSCB number %d ---\n", j+1);
		strncpy(s44, info->f1[j].DS1DSNAM, 44);
		printf("DS1DSNAM    : ascii  '%44s'\n", s44);
		vtoc_ebcdic_dec(s44, s44, 44);
		printf("              ebcdic '%44s'\n", s44);
		printf("DS1FMTID    : dec %d, hex %02x\n", 
		       info->f1[j].DS1FMTID, info->f1[j].DS1FMTID);
		printf("DS1DSSN     : hex    ");
		for (i=0; i<6; i++) printf("%02x", info->f1[j].DS1DSSN[i]);
		strncpy(s6, info->f1[j].DS1DSSN, 6);
		printf("\n              ascii  '%6s'\n", s6);
		vtoc_ebcdic_dec(s6, s6, 6);
		printf("              ebcdic '%6s'\n", s6);
		printf("DS1VOLSQ    : dec %d, hex %04x\n", 
		       info->f1[j].DS1VOLSQ, info->f1[j].DS1VOLSQ);
		printf("DS1CREDT    : hex %02x%04x " \
		       "(year %d, day %d)\n", 
		       info->f1[j].DS1CREDT.year, info->f1[j].DS1CREDT.day,
		       info->f1[j].DS1CREDT.year + 1900, 
		       info->f1[j].DS1CREDT.day);
		printf("DS1EXPDT    : hex %02x%04x " \
		       "(year %d, day %d)\n", 
		       info->f1[j].DS1EXPDT.year, info->f1[j].DS1EXPDT.day,
		       info->f1[j].DS1EXPDT.year + 1900, 
		       info->f1[j].DS1EXPDT.day);
		printf("DS1NOEPV    : dec %d, hex %02x\n", 
		       info->f1[j].DS1NOEPV, info->f1[j].DS1NOEPV);
		printf("DS1NOBDB    : dec %d, hex %02x\n", 
		       info->f1[j].DS1NOBDB, info->f1[j].DS1NOBDB);
		printf("DS1FLAG1    : dec %d, hex %02x\n", 
		       info->f1[j].DS1FLAG1, info->f1[j].DS1FLAG1);
		printf("DS1SYSCD    : hex    ");
		for (i=0; i<13; i++) printf("%02x", info->f1[j].DS1SYSCD[i]);
		strncpy(s13, info->f1[j].DS1SYSCD, 13);
		printf("\n              ascii  '%13s'\n", s13);
		vtoc_ebcdic_dec(s13, s13, 13);
		printf("              ebcdic '%13s'\n", s13);
		printf("DS1REFD     : hex %02x%04x " \
		       "(year %d, day %d)\n", 
		       info->f1[j].DS1REFD.year, info->f1[j].DS1REFD.day,
		       info->f1[j].DS1REFD.year + 1900, 
		       info->f1[j].DS1REFD.day);
		printf("DS1SMSFG    : dec %d, hex %02x\n", 
		       info->f1[j].DS1SMSFG, info->f1[j].DS1SMSFG);
		printf("DS1SCXTF    : dec %d, hex %02x\n", 
		       info->f1[j].DS1SCXTF, info->f1[j].DS1SCXTF);
		printf("DS1SCXTV    : dec %d, hex %04x\n", 
		       info->f1[j].DS1SCXTV, info->f1[j].DS1SCXTV);
		printf("DS1DSRG1    : dec %d, hex %02x\n", 
		       info->f1[j].DS1DSRG1, info->f1[j].DS1DSRG1);
		printf("DS1DSRG2    : dec %d, hex %02x\n", 
		       info->f1[j].DS1DSRG2, info->f1[j].DS1DSRG2);
		printf("DS1RECFM    : dec %d, hex %02x\n", 
		       info->f1[j].DS1RECFM, info->f1[j].DS1RECFM);
		printf("DS1OPTCD    : dec %d, hex %02x\n", 
		       info->f1[j].DS1OPTCD, info->f1[j].DS1OPTCD);
		printf("DS1BLKL     : dec %d, hex %04x\n", 
		       info->f1[j].DS1BLKL, info->f1[j].DS1BLKL);
		printf("DS1LRECL    : dec %d, hex %04x\n", 
		       info->f1[j].DS1LRECL, info->f1[j].DS1LRECL);
		printf("DS1KEYL     : dec %d, hex %02x\n", 
		       info->f1[j].DS1KEYL, info->f1[j].DS1KEYL);
		printf("DS1RKP      : dec %d, hex %04x\n", 
		       info->f1[j].DS1RKP, info->f1[j].DS1RKP);
		printf("DS1DSIND    : dec %d, hex %02x\n", 
		       info->f1[j].DS1DSIND, info->f1[j].DS1DSIND);
		printf("DS1SCAL1    : dec %d, hex %02x\n", 
		       info->f1[j].DS1SCAL1, info->f1[j].DS1SCAL1);
		printf("DS1SCAL3    : hex ");
		for (i=0; i<3; i++) printf("%02x", info->f1[j].DS1SCAL3[i]);
		printf("\nDS1LSTAR    : hex %04x%02x " \
		       "(trk %d, blk %d)\n", 
		       info->f1[j].DS1LSTAR.tt, info->f1[j].DS1LSTAR.r,
		       info->f1[j].DS1LSTAR.tt, info->f1[j].DS1LSTAR.r);
		printf("DS1TRBAL    : dec %d, hex %04x\n", 
		       info->f1[j].DS1TRBAL, info->f1[j].DS1TRBAL);
		printf("reserved    : dec %d, hex %04x\n",
		       info->f1[j].res1, info->f1[j].res1);
		printf("DS1EXT1     : hex %02x%02x%04x%04x%04x%04x\n",
		       info->f1[j].DS1EXT1.typeind,   
		       info->f1[j].DS1EXT1.seqno,
		       info->f1[j].DS1EXT1.llimit.cc, 
		       info->f1[j].DS1EXT1.llimit.hh,
		       info->f1[j].DS1EXT1.ulimit.cc, 
		       info->f1[j].DS1EXT1.ulimit.hh);
		printf("              typeind    : dec %d, hex %02x\n", 
		       info->f1[j].DS1EXT1.typeind, 
		       info->f1[j].DS1EXT1.typeind);
		printf("              seqno      : dec %d, hex %02x\n", 
		       info->f1[j].DS1EXT1.seqno, info->f1[j].DS1EXT1.seqno);
		printf("              llimit     : hex %04x%04x " \
		       "(cyl %d, trk %d)\n", 
		       info->f1[j].DS1EXT1.llimit.cc, 
		       info->f1[j].DS1EXT1.llimit.hh,
		       info->f1[j].DS1EXT1.llimit.cc, 
		       info->f1[j].DS1EXT1.llimit.hh);
		printf("              ulimit     : hex %04x%04x " \
		       "(cyl %d, trk %d)\n", 
		       info->f1[j].DS1EXT1.ulimit.cc, 
		       info->f1[j].DS1EXT1.ulimit.hh,
		       info->f1[j].DS1EXT1.ulimit.cc, 
		       info->f1[j].DS1EXT1.ulimit.hh);
		printf("DS1EXT2     : hex %02x%02x%04x%04x%04x%04x\n",
		       info->f1[j].DS1EXT2.typeind,   
		       info->f1[j].DS1EXT2.seqno,
		       info->f1[j].DS1EXT2.llimit.cc, 
		       info->f1[j].DS1EXT2.llimit.hh,
		       info->f1[j].DS1EXT2.ulimit.cc, 
		       info->f1[j].DS1EXT2.ulimit.hh);
		printf("              typeind    : dec %d, hex %02x\n", 
		       info->f1[j].DS1EXT2.typeind, 
		       info->f1[j].DS1EXT2.typeind);
		printf("              seqno      : dec %d, hex %02x\n", 
		       info->f1[j].DS1EXT2.seqno, info->f1[j].DS1EXT2.seqno);
		printf("              llimit     : hex %04x%04x " \
		       "(cyl %d, trk %d)\n", 
		       info->f1[j].DS1EXT2.llimit.cc, 
		       info->f1[j].DS1EXT2.llimit.hh,
		       info->f1[j].DS1EXT2.llimit.cc, 
		       info->f1[j].DS1EXT2.llimit.hh);
		printf("              ulimit     : hex %04x%04x " \
		       "(cyl %d, trk %d)\n", 
		       info->f1[j].DS1EXT2.ulimit.cc, 
		       info->f1[j].DS1EXT2.ulimit.hh,
		       info->f1[j].DS1EXT2.ulimit.cc, 
		       info->f1[j].DS1EXT2.ulimit.hh);
		printf("DS1EXT3     : hex %02x%02x%04x%04x%04x%04x\n",
		       info->f1[j].DS1EXT3.typeind,   
		       info->f1[j].DS1EXT3.seqno,
		       info->f1[j].DS1EXT3.llimit.cc, 
		       info->f1[j].DS1EXT3.llimit.hh,
		       info->f1[j].DS1EXT3.ulimit.cc, 
		       info->f1[j].DS1EXT3.ulimit.hh);
		printf("              typeind    : dec %d, hex %02x\n", 
		       info->f1[j].DS1EXT3.typeind, 
		       info->f1[j].DS1EXT3.typeind);
		printf("              seqno      : dec %d, hex %02x\n", 
		       info->f1[j].DS1EXT3.seqno, info->f1[j].DS1EXT3.seqno);
		printf("              llimit     : hex %04x%04x " \
		       "(cyl %d, trk %d)\n", 
		       info->f1[j].DS1EXT3.llimit.cc, 
		       info->f1[j].DS1EXT3.llimit.hh,
		       info->f1[j].DS1EXT3.llimit.cc, 
		       info->f1[j].DS1EXT3.llimit.hh);
		printf("              ulimit     : hex %04x%04x " \
		       "(cyl %d, trk %d)\n", 
		       info->f1[j].DS1EXT3.ulimit.cc, 
		       info->f1[j].DS1EXT3.ulimit.hh,
		       info->f1[j].DS1EXT3.ulimit.cc, 
		       info->f1[j].DS1EXT3.ulimit.hh);
		printf("DS1PTRDS    : %04x%04x%02x " \
		       "(cyl %d, trk %d, blk %d)\n", 
		       info->f1[j].DS1PTRDS.cc, info->f1[j].DS1PTRDS.hh, 
		       info->f1[j].DS1PTRDS.b,  info->f1[j].DS1PTRDS.cc, 
		       info->f1[j].DS1PTRDS.hh, info->f1[j].DS1PTRDS.b);
	}  
}

static void
dasdview_print_vtoc_f4(dasdview_info_t *info)
{
        int i;

	printf("\n--- VTOC format 4 label ----------------------" \
	       "---------------------------------\n");

	if (info->f4c < 1)
	{
	        printf("This VTOC doesn't contain a format 4 label.\n");
		return;
	}

	printf("DS4KEYCD    : ");
	for (i=0; i<44; i++) printf("%02x", info->f4.DS4KEYCD[i]);
	printf("\nDS4IDFMT    : dec %d, hex %02x\n", 
	       info->f4.DS4IDFMT, info->f4.DS4IDFMT);
	printf("DS4HPCHR    : %04x%04x%02x " \
	       "(cyl %d, trk %d, blk %d)\n", 
	       info->f4.DS4HPCHR.cc, info->f4.DS4HPCHR.hh, 
	       info->f4.DS4HPCHR.b,  info->f4.DS4HPCHR.cc, 
	       info->f4.DS4HPCHR.hh, info->f4.DS4HPCHR.b);
	printf("DS4DSREC    : dec %d, hex %04x\n", 
	       info->f4.DS4DSREC, info->f4.DS4DSREC);
	printf("DS4HCCHH    : %04x%04x (cyl %d, trk %d)\n", 
	       info->f4.DS4HCCHH.cc, info->f4.DS4HCCHH.hh, 
	       info->f4.DS4HCCHH.cc, info->f4.DS4HCCHH.hh);
	printf("DS4NOATK    : dec %d, hex %04x\n", 
	       info->f4.DS4NOATK, info->f4.DS4NOATK);
	printf("DS4VTOCI    : dec %d, hex %02x\n", 
	       info->f4.DS4VTOCI, info->f4.DS4VTOCI);
	printf("DS4NOEXT    : dec %d, hex %02x\n", 
	       info->f4.DS4NOEXT, info->f4.DS4NOEXT);
	printf("DS4SMSFG    : dec %d, hex %02x\n", 
	       info->f4.DS4SMSFG, info->f4.DS4SMSFG);
	printf("DS4DEVAC    : dec %d, hex %02x\n", 
	       info->f4.DS4DEVAC, info->f4.DS4DEVAC);
	printf("DS4DSCYL    : dec %d, hex %04x\n", 
	       info->f4.DS4DEVCT.DS4DSCYL, info->f4.DS4DEVCT.DS4DSCYL);
	printf("DS4DSTRK    : dec %d, hex %04x\n", 
	       info->f4.DS4DEVCT.DS4DSTRK, info->f4.DS4DEVCT.DS4DSTRK);
	printf("DS4DEVTK    : dec %d, hex %04x\n", 
	       info->f4.DS4DEVCT.DS4DEVTK, info->f4.DS4DEVCT.DS4DEVTK);
	printf("DS4DEVI     : dec %d, hex %02x\n", 
	       info->f4.DS4DEVCT.DS4DEVI, info->f4.DS4DEVCT.DS4DEVI);
	printf("DS4DEVL     : dec %d, hex %02x\n", 
	       info->f4.DS4DEVCT.DS4DEVL, info->f4.DS4DEVCT.DS4DEVL);
	printf("DS4DEVK     : dec %d, hex %02x\n", 
	       info->f4.DS4DEVCT.DS4DEVK, info->f4.DS4DEVCT.DS4DEVK);
	printf("DS4DEVFG    : dec %d, hex %02x\n", 
	       info->f4.DS4DEVCT.DS4DEVFG, info->f4.DS4DEVCT.DS4DEVFG);
	printf("DS4DEVTL    : dec %d, hex %04x\n", 
	       info->f4.DS4DEVCT.DS4DEVTL, info->f4.DS4DEVCT.DS4DEVTL);
	printf("DS4DEVDT    : dec %d, hex %02x\n", 
	       info->f4.DS4DEVCT.DS4DEVDT, info->f4.DS4DEVCT.DS4DEVDT);
	printf("DS4DEVDB    : dec %d, hex %02x\n", 
	       info->f4.DS4DEVCT.DS4DEVDB, info->f4.DS4DEVCT.DS4DEVDB);
	printf("DS4AMTIM    : hex ");
	for (i=0; i<8; i++) printf("%02x", info->f4.DS4AMTIM[i]);
	printf("\nDS4AMCAT    : hex ");
	for (i=0; i<3; i++) printf("%02x", info->f4.DS4AMCAT[i]);
	printf("\nDS4R2TIM    : hex ");
	for (i=0; i<8; i++) printf("%02x", info->f4.DS4R2TIM[i]);
	printf("\nres1        : hex ");
	for (i=0; i<5; i++) printf("%02x", info->f4.res1[i]);	
	printf("\nDS4F6PTR    : hex ");
	for (i=0; i<5; i++) printf("%02x", info->f4.DS4F6PTR[i]);
	printf("\nDS4VTOCE    : hex %02x%02x%04x%04x%04x%04x\n",
	       info->f4.DS4VTOCE.typeind, info->f4.DS4VTOCE.seqno,
	       info->f4.DS4VTOCE.llimit.cc, info->f4.DS4VTOCE.llimit.hh,
	       info->f4.DS4VTOCE.ulimit.cc, info->f4.DS4VTOCE.ulimit.hh);
	printf("              typeind    : dec %d, hex %02x\n", 
	       info->f4.DS4VTOCE.typeind, info->f4.DS4VTOCE.typeind);
	printf("              seqno      : dec %d, hex %02x\n", 
	       info->f4.DS4VTOCE.seqno, info->f4.DS4VTOCE.seqno);
	printf("              llimit     : hex %04x%04x (cyl %d, trk %d)\n", 
	       info->f4.DS4VTOCE.llimit.cc, info->f4.DS4VTOCE.llimit.hh,
	       info->f4.DS4VTOCE.llimit.cc, info->f4.DS4VTOCE.llimit.hh);
	printf("              ulimit     : hex %04x%04x (cyl %d, trk %d)\n", 
	       info->f4.DS4VTOCE.ulimit.cc, info->f4.DS4VTOCE.ulimit.hh,
	       info->f4.DS4VTOCE.ulimit.cc, info->f4.DS4VTOCE.ulimit.hh);
	printf("res2        : hex ");
	for (i=0; i<10; i++) printf("%02x", info->f4.res2[i]);
	printf("\nDS4EFLVL    : dec %d, hex %02x\n", 
	       info->f4.DS4EFLVL, info->f4.DS4EFLVL);
	printf("DS4EFPTR    : hex %04x%04x%02x " \
	       "(cyl %d, trk %d, blk %d)\n", 
	       info->f4.DS4EFPTR.cc, info->f4.DS4EFPTR.hh,
	       info->f4.DS4EFPTR.b,  info->f4.DS4EFPTR.cc, 
	       info->f4.DS4EFPTR.hh, info->f4.DS4EFPTR.b);
	printf("res3        : hex ");
	for (i=0; i<9; i++) printf("%02x", info->f4.res3[i]);
	printf("\n");
}

static void
dasdview_print_vtoc_f5(dasdview_info_t *info)
{
        int i;

	printf("\n--- VTOC format 5 label ----------------------" \
	       "---------------------------------\n");

	if (info->f5c < 1)
	{
	        printf("This VTOC doesn't contain a format 5 label.\n");
		return;
	}

	printf("key identifier\n        DS5KEYID    : ");
	for (i=0; i<4; i++) printf("%02x", info->f5.DS5KEYID[i]);
	printf("\nfirst extent description\n");
	printf("        DS5AVEXT    : %04x%04x%02x " \
	       "(start trk: %d, length: %d cyl, %d trk)\n", 
	       info->f5.DS5AVEXT.t,  info->f5.DS5AVEXT.fc, 
	       info->f5.DS5AVEXT.ft, info->f5.DS5AVEXT.t, 
	       info->f5.DS5AVEXT.fc, info->f5.DS5AVEXT.ft);
	printf("next 7 extent descriptions\n");
	for (i=0; i<7; i++)
        {
	        printf("        DS5EXTAV[%d] : %04x%04x%02x " \
		       "(start trk: %d, length: %d cyl, %d trk)\n", i+2,
		       info->f5.DS5EXTAV[i].t,  info->f5.DS5EXTAV[i].fc, 
		       info->f5.DS5EXTAV[i].ft, info->f5.DS5EXTAV[i].t, 
		       info->f5.DS5EXTAV[i].fc, info->f5.DS5EXTAV[i].ft);
	}
	printf("format identifier\n" \
	       "        DS5FMTID    : dec %d, hex %02x\n", 
	       info->f5.DS5FMTID, info->f5.DS5FMTID);
	printf("next 18 extent descriptions\n");
	for (i=0; i<18; i++)
        {
	        printf("        DS5MAVET[%d] : %04x%04x%02x " \
		       "(start trk: %d, length: %d cyl, %d trk)\n", i+9,
		       info->f5.DS5MAVET[i].t,  info->f5.DS5MAVET[i].fc, 
		       info->f5.DS5MAVET[i].ft, info->f5.DS5MAVET[i].t, 
		       info->f5.DS5MAVET[i].fc, info->f5.DS5MAVET[i].ft);
	}
	printf("pointer to next format 5 label\n" \
	       "        DS5PTRDS    : %04x%04x%02x " \
	       "(cyl %d, trk %d, blk %d)\n", 
	       info->f5.DS5PTRDS.cc, info->f5.DS5PTRDS.hh, 
	       info->f5.DS5PTRDS.b,  info->f5.DS5PTRDS.cc, 
	       info->f5.DS5PTRDS.hh, info->f5.DS5PTRDS.b);
}

static void
dasdview_print_vtoc_f7(dasdview_info_t *info)
{
        int i;

	printf("\n--- VTOC format 7 label ----------------------" \
	       "---------------------------------\n");
	  
	if (info->f7c < 1)
	{
	        printf("This VTOC doesn't contain a format 7 label.\n");
		return;
	}

	printf("key identifier\n        DS7KEYID    : ");
	for (i=0; i<4; i++) printf("%02x", info->f7.DS7KEYID[i]);
	printf("\nfirst 5 extent descriptions\n");
	for (i=0; i<5; i++)
	{
	        printf("        DS7EXTNT[%d] : %08x %08x " \
		       "(start trk %d, end trk %d)\n", i+1, 
		       info->f7.DS7EXTNT[i].a, info->f7.DS7EXTNT[i].b,
		       info->f7.DS7EXTNT[i].a, info->f7.DS7EXTNT[i].b);
	}
	printf("format identifier\n" \
	       "        DS7FMTID    : dec %d, hex %02x\n", 
	       info->f7.DS7FMTID, info->f7.DS7FMTID);
	printf("next 11 extent descriptions\n");
	for (i=0; i<11; i++)
	{
	        printf("        DS7ADEXT[%d] : %08x %08x " \
		       "(start trk %d, end trk %d)\n", i+6,  
		       info->f7.DS7ADEXT[i].a, info->f7.DS7ADEXT[i].b,
		       info->f7.DS7ADEXT[i].a, info->f7.DS7ADEXT[i].b);
	}
	printf("reserved field\n        res1        : ");
	for (i=0; i<2; i++) printf("%02x", info->f7.res1[i]);
	printf("\npointer to next format 7 label\n" \
	       "        DS7PTRDS    : %04x%04x%02x " \
	       "(cyl %d, trk %d, blk %d)\n", 
	       info->f7.DS7PTRDS.cc, info->f7.DS7PTRDS.hh, 
	       info->f7.DS7PTRDS.b, info->f7.DS7PTRDS.cc, 
	       info->f7.DS7PTRDS.hh, info->f7.DS7PTRDS.b);
}


static int
dasdview_print_format1(unsigned int size, char *dumpstr)
{
	unsigned int i;
	char asc[17], ebc[17];

	for (i = 0; i < size; i++)
	{
		if ((i / 16) * 16 == i) { 
			printf("\n|  ");
			strncpy(asc, dumpstr + i, 16);
			strncpy(ebc, dumpstr + i, 16);
			asc[16] = '\0';
			ebc[16] = '\0';
		}
		printf("%02X", dumpstr[i]);
		if (((i + 1) / 4)  * 4  == i + 1) printf(" ");
		if (((i + 1) / 8)  * 8  == i + 1) printf(" ");
		if (((i + 1) / 16) * 16 == i + 1) {
			vtoc_ebcdic_dec(asc, asc, 16);
			dot(asc);
			dot(ebc);
			printf("| %16.16s | %16.16s |", asc, ebc);
		}
	}

	return 0;
}

static int
dasdview_print_format2(unsigned int size, 
		       char *dumpstr,
		       unsigned long long begin)
{
	unsigned int i;
	char asc[17], ebc[17];

	for (i = 0; i < size; i++)
	{
		if ((i / 8) * 8 == i) {
			printf("\n | %13llu | %13llX |  ", 
			       begin + (unsigned long long) i,
			       begin + (unsigned long long) i);

			strncpy(asc, dumpstr + i, 8);
			strncpy(ebc, dumpstr + i, 8);
		}
		printf("%02X", dumpstr[i]);
		if (((i + 1) / 4) * 4 == i + 1) printf("  ");
		if (((i + 1) / 8) * 8 == i + 1) {
			vtoc_ebcdic_dec(asc, asc, 8);
			dot(asc);
			dot(ebc);
			printf("| %8.8s | %8.8s |", asc, ebc);
		}
	}

	return 0;
}

static int 
dasdview_view(dasdview_info_t *info)
{
        char  dumpstr[DUMP_STRING_SIZE];
	unsigned long long i=0, j=0, k=0, count=0;
	int   fd, rc;

	unsigned long long a=0;
	int b=0;

	k = ((info->size) % 16LL);

	if (k != 0) 
	{
		info->size += (16LL - k);
	}

	fd = open(info->device, O_RDONLY);
	if (fd == -1)
	{
		sprintf(error_str, "Unable to open device %s in read-only" \
			"mode!\n", info->device);
	        dasdview_error(open_error);
	}

	j = (info->begin / SEEK_STEP);
	k = (info->begin % SEEK_STEP);

        /* seek in SEEK_STEP steps */
	for (i=1; i <= j; i++)
	{
		rc = lseek64(fd, SEEK_STEP, SEEK_CUR); 
		if (rc == -1) 
		{
			printf("*** rc: %d (%d) ***\n", rc, errno);
			printf("*** j: %llu ***\n", j);
			printf("*** k: %llu ***\n", k);
			printf("*** a: %llu ***\n", a);
			printf("*** b: %d ***\n", b);
			close(fd);
			sprintf(error_str, "Unable to seek in device %s!\n", 
				info->device);
			dasdview_error(seek_error);
		}
		b++;
		a += SEEK_STEP;
	}

	if (k > 0)
	{
		rc = lseek(fd, k, SEEK_CUR); 
		if (rc == -1) 
		{
			close(fd);
			sprintf(error_str, "Unable to seek in device %s!\n", 
				info->device);
			dasdview_error(seek_error);
		}
	}		

	j = info->size / DUMP_STRING_SIZE;
	k = info->size % DUMP_STRING_SIZE;


	if (info->format1)
	{
		printf("+----------------------------------------+" \
		       "------------------+------------------+\n");
		printf("| HEXADECIMAL                            |" \
		       " EBCDIC           | ASCII            |\n");
		printf("|  01....04 05....08  09....12 13....16  |" \
		       " 1.............16 | 1.............16 |\n");
		printf("+----------------------------------------+" \
		       "------------------+------------------+");
	} 
	else if (info->format2)
	{
		printf(" +---------------+---------------+----------------" \
		       "------+----------+----------+\n");
		printf(" |     BYTE      |     BYTE      |     HEXADECIMAL" \
		       "      |  EBCDIC  |  ASCII   |\n");
		printf(" |    DECIMAL    |  HEXADECIMAL  |  1 2 3 4   5 6 " \
		       "7 8   | 12345678 | 12345678 |\n");
		printf(" +---------------+---------------+----------------" \
		       "------+----------+----------+");
	}

	count = info->begin;
	for (i=1; i <= j; i++)
	{
		bzero(dumpstr, DUMP_STRING_SIZE);
		rc = read(fd, &dumpstr, DUMP_STRING_SIZE);
		if (rc != DUMP_STRING_SIZE) 
		{
			close(fd);
			sprintf(error_str, "Unable to read from device %s!\n",
				info->device);
			dasdview_error(read_error);
		}

		if (info->format1)
			dasdview_print_format1(DUMP_STRING_SIZE, dumpstr);
		else if (info->format2)
			dasdview_print_format2(DUMP_STRING_SIZE, dumpstr,
					       count);
		count += DUMP_STRING_SIZE;
	}

	if (k > 0)
	{
		bzero(dumpstr, DUMP_STRING_SIZE);
		rc = read(fd, &dumpstr, k);
		if (rc != k) 
		{
			close(fd);
			sprintf(error_str, "Unable to read from device %s!\n",
				info->device);
			dasdview_error(read_error);
		}

		if (info->format1)
			dasdview_print_format1((unsigned int) k, dumpstr);
		else if (info->format2)
			dasdview_print_format2((unsigned int) k, dumpstr,
					       count);
	}

	close(fd);

	if (info->format1)
	{
		printf("\n+----------------------------------------+" \
		       "------------------+------------------+\n\n");
	}
	else if (info->format2)
	{
		printf("\n +---------------+---------------+----------------" \
		       "------+----------+----------+\n\n");
	}
	
	return 0;
}


int main(int argc, char * argv[]) {

	dasdview_info_t info;
	int oc, index;
	unsigned long long max=0LL;

	char *devno_param_str = NULL;
	char *begin_param_str = NULL;
	char *size_param_str  = NULL;
	char *endptr          = NULL;

	dasdview_init_info(&info);

	opterr=0;
	while (1)
	{
		oc = getopt_long(argc, argv, dasdview_getopt_string,
				 dasdview_getopt_long_options, &index);
        	if (oc==-1) break;

		switch (oc) 
		{
		case '?':
		case 'h':
			dasdview_usage();
			exit(0);
		case ':':
			dasdview_usage();
			exit(1);
		case 'v':
			printf("dasdview version %s\n", DASDVIEW_VERSION);
			exit(0);
		case 'b':
			begin_param_str = optarg;
			info.action_specified = 1;
			info.begin_specified = 1;
			break;
		case 's':
			size_param_str = optarg;
			info.action_specified = 1;
			info.size_specified = 1;
			break;
		case '1':
			info.format1 = 1;
			info.format2 = 0;
			break;
		case '2':
			info.format1 = 0;
			info.format2 = 1;
			break;
		case 'n':
			devno_param_str = optarg;
			info.devno_specified = 1;
			break;
		case 'f':
			strcpy(info.device, optarg);
			info.node_specified = 1;
			break;
		case 'i':
			info.action_specified = 1;
			info.short_info = 1;
			break;
		case 'x':
			info.action_specified = 1;
			info.long_info = 1;
			break;
		case 'j':
			info.action_specified = 1;
			info.volser = 1;
			break;
		case 't':
		        if (strncmp(optarg,"info",4)==0)
		                info.vtoc_info = 1;
		        else if (strncmp(optarg,"f1",2)==0)
		                info.vtoc_f1 = 1;
		        else if (strncmp(optarg,"f4",2)==0)
		                info.vtoc_f4 = 1;
		        else if (strncmp(optarg,"f5",2)==0)
		                info.vtoc_f5 = 1;
		        else if (strncmp(optarg,"f7",2)==0)
		                info.vtoc_f7 = 1;
		        else if (strncmp(optarg,"all",3)==0)
		                info.vtoc_all = 1;
		        else
		        {
			        sprintf(error_str, "%s is no valid option!\n",
					optarg);
				dasdview_error(usage_error);
			}
		        info.vtoc = 1;
			info.action_specified = 1;
			break;
		case 'l':
			info.action_specified = 1;
			info.vlabel_info = 1;
			break;
		default:
			dasdview_usage();
			exit(0);
		}
	}

	if (info.devno_specified)
		PARSE_PARAM_INTO(info.devno, devno_param_str, 16,
				 "device number");

	/* do some tests */
	if (!(info.node_specified+info.devno_specified))
	{
		sprintf(error_str,"Device not specified!");
		dasdview_error(usage_error);
	}

	if ((info.node_specified + info.devno_specified) > 1)
	{
		sprintf(error_str,"Device can only specified once!");
		dasdview_error(usage_error);
	}

	if (info.devno_specified)
	{
		sprintf(info.device, "/dev/dasd/%04x/device", info.devno);
	}

	if ((info.devno_specified) && 
	    ((info.devno < 0x0000)||(info.devno > 0xffff)))
	{
		sprintf(error_str,"Devno '%#04x' is not in range " \
			"0x0000 - 0xFFFF!", info.devno);
		dasdview_error(usage_error);
	}

	dasdview_get_info(&info);

	if (info.begin_specified)
	{
		if (strchr(begin_param_str, '-') != NULL)
		{
			sprintf(error_str,"%s is not a valid begin value!",
				begin_param_str);			
			dasdview_error(usage_error);
		}
		dasdview_parse_input(&info.begin, &info, begin_param_str);
	}	
	else 
		info.begin = DEFAULT_BEGIN;

	max = (unsigned long long) info.geo.cylinders * 
		(unsigned long long) info.geo.heads * 
		(unsigned long long) info.geo.sectors * 
		(unsigned long long) info.blksize;
	if (info.begin > max)
	{
		sprintf(error_str,"'begin' value is not within disk range!");
		dasdview_error(usage_error);
	}

	if (info.size_specified)
	{
		if (strchr(size_param_str, '-') != NULL)
		{
			sprintf(error_str,"%s is not a valid size value!",
				size_param_str);			
			dasdview_error(usage_error);
		}
		dasdview_parse_input(&info.size, &info, size_param_str);
	}	
	else
		info.size = DEFAULT_SIZE;



	if ((info.begin_specified || info.size_specified) && 
	    ((info.begin + info.size) > max             )   ) 
	{
		sprintf(error_str,"'begin' + 'size' is not within " \
			"disk range!");
		dasdview_error(usage_error);
	}

	if ((info.begin_specified || info.size_specified) && 
	    (!info.format1 && !info.format2))
	{
		info.format1 = 1;
	}

	if ((info.format1 || info.format2) && 
	    (!info.size_specified && !info.begin_specified))
	{
		sprintf(error_str,"Options -1 or -2 make only sense with " \
			"options -b or -s!");
		dasdview_error(usage_error);
	}

	/* do the output */

	if (info.begin_specified || info.size_specified)
		dasdview_view(&info);

	if (info.short_info || info.long_info)
		dasdview_print_info(&info);

	if (info.long_info)
		dasdview_print_more_info(&info);

	if (info.volser)
		dasdview_print_volser(&info);

	if (info.vlabel_info)
		dasdview_print_vlabel(&info);

	if (info.vtoc)
	{
		dasdview_read_vtoc(&info);
	}

	if (info.vtoc_info || info.vtoc_all)
	{
		dasdview_print_vtoc_info(&info);
	}

	if (info.vtoc_f4 || info.vtoc_all)
	{
	        dasdview_print_vtoc_f4(&info);
	}

	if (info.vtoc_f5 || info.vtoc_all)
	{
	        dasdview_print_vtoc_f5(&info);
	}

	if (info.vtoc_f7 || info.vtoc_all)
	{
	        dasdview_print_vtoc_f7(&info);
	}

	if (info.vtoc_f1 || info.vtoc_all)
	{
	        dasdview_print_vtoc_f1(&info);
	}

	if (!info.action_specified)
	{
		printf("No action specified.\n");
	}
		
	return 0;
}


















































