static char sccsid[] = "@(#)errpt.c	2.1	";
/* Format and interpret the error log file */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#ifdef vax
#include <sys/mba.h>
#endif
#include <sys/map.h>
#include <sys/elog.h>
#include <sys/err.h>
#include <sys/erec.h>
#include <time.h>

#ifdef vax
#define   PNEED   25      /* Space needed for each block device detail report */
#else
#define   PNEED   24
#endif
#define dysize(x)	(((x)%4)? 365: 366)
#define writout()	((mode==PRINT) && (page<=limit))
#define major(x)	(int)((unsigned)(x>>8)&0377)
#define minor(x)	((int)x&0377)
#define araysz(x)	((sizeof(x)/sizeof(x[0]))-2)
#define readrec(x)	(fread((char*)&recrd,\
			(e_hdr.e_len - sizeof(struct errhdr)), 1, x) )
#define recrd		ercd.ebb.block
#define erp		ercd.parity
#define erm		ercd.memory

#define GDRP04	020
#define GDRP05	021
#define GDRP06	022
#define GDRM03	024
#define GDRM80	026
#define GDRM05	027
#define GDRP07	042
#define GTTM03	050		/* (tu16) */
#define GTTM02	010
#define GTTM78	0100

#ifdef vax
#define FORM "%.8X"
#define FORM2 "\t%.8X\n"
#define DRIVE_REG 6
#else
#define FORM "%.6o"
#define FORM2 "%16lo\n"
#define DRIVE_REG 11
#endif
#define DRIVE_TYPE	ercd.ebb.reginf[DRIVE_REG] & 0777

#ifdef m68k
#define PACKET_LENGTH	ercd.ebb.reginf[1] >> 8
#define U_DEV_NUM    	ercd.ebb.reginf[1] &  077
#endif

char Nl [1];
#define NUL4	Nl,Nl,Nl,Nl
#define NUL8	Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl
#define NULS	Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl,Nl

#define INAUG "0301080077"	/* start of error logging [mmddhhmmyy] */
#define WDLEN 16
#define MINREC 8
#define MAXREC 74
#define DEVADR ((physadr)(0160000))
#define MAXLEN 66
#define MAXSTR 40

#ifdef m68k
#define NMAJOR 2
#define NMINOR 8
#else
#define NMAJOR 12
#define NMINOR 8
#endif

#define PGLEN 60
#define MBAREG 5
#define INT  15

#define MEM  14
#define YES 1
#define NO 0
#define PRINT 1
#define NOPRINT 0
#define DSEC 3	/* 2**DSEC is the number of logical partitions on RP03/4/5/6 */
#define USAGE1 "errpt [-a] [-d devlist] [-s date]"
#define USAGE2 "\n [-e date] [-p n] [-f] [files]"

/* NMAJOR devices of NMINOR possible logical units */
struct sums {
	long	soft;
	long	hard;
	long	totalio;
	long	misc;
	long	missing;
#ifdef vax
	int	contr;
	int	slave;
#endif
	char	*drvname;
} sums[NMAJOR][NMINOR];
struct tb_sums {
	long	totalio;
	long	misc;
	long	missing;
};

/* structure for maintaining totals across multiple error files: */
struct tb_sums tot_sums[NMAJOR][NMINOR];
struct tb_sums base_sums[NMAJOR][NMINOR];

union ercd {
	struct  estart start;
	struct	eend end;
	struct	etimchg timchg;
	struct	econfchg confchg;
	struct	estray stray;
	struct	eparity parity;
	struct	ememory memory;
	struct  eb {
		struct	eblock block;
		unsigned short reginf [30];
	} ebb;
} ercd;

struct errhdr e_hdr;

int dmsize[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int maj;
int min;
int page=1;
int print;
int mode = NOPRINT;
int line;
int n = 0;
int aflg;
int dflg;
int fflg;
int Unix = 1;
short cputype;
int parsum;
int straysum;
int limit = 10000;		/* page limit */
int optdev = 0;			/* bit map for device-specific reports */
long readerr = 0;		/* input record error count */
FILE	*file;
time_t	atime;
time_t	xtime = 0L;
time_t	etime = 017777777777L;
time_t	fftime = 017777777777L;
time_t	ltime = 0L;
char interp [MAXSTR];
char choice [MAXSTR];
char *strcpy();
char *ctime();
long tloc;
long time();
#ifdef vax
struct vaxreg {
	char *regname;
	char *bitcode [WDLEN*2];
};
int mb_dev;	/* True if device is MBA connected */
#endif
struct regs {
	char *regname;
	char *bitcode [WDLEN];
};

struct regs *regs_ptr;
char htime[20];
char *header = "SYSTEM ERROR REPORT";
char *hd1 = "System Error Report - Selected Items";
char *hd2 = "Summary Error Report";

#ifdef m68k
char *dev[] = {
	"UD0", "WD0",
	0
};
#else
char *dev[] = {
	"RK05","RP03","RF11","TU10",
	"TC11","RP04/5/6","TU16","RS03/4",
	"RL02","TM78","RP05","RP06",
	0
};
#endif

/*
 * Register names and bit mnemonics for each
 * register and bit to be interpreted on detail report.
 */

#ifdef m68k

struct regs udregs9 [] = {     /* 9-byte status packet */
	"$02:PID", NULS,
	"LNG:DNO", NULS,
	"CMD:STY", NULS,
	"STATUS ", NULS,
	"$03:---", NULS,
	"Z ", NULS,
	"Z ", NULS,
	"Z ", NULS,
	"Z ", NULS,
	"Z ", NULS,
	0
};

struct regs udregs13 [] = {     /* 13-byte status packet */
	"$02:PID", NULS,
	"LNG:DNO", NULS,
	"CMD:STY", NULS,
	"STATUS ", NULS,
	"SECT-HI", NULS,
	"SECT-LO", NULS,
	"$03:---", NULS,
	"Z ", NULS,
	"Z ", NULS,
	"Z ", NULS,
	0
};

struct regs udregs15 [] = {     /* 15-byte status packet */
	"$02:PID", NULS,
	"LNG:DNO", NULS,
	"CMD:STY", NULS,
	"STATUS ", NULS,
	"DTY:---", NULS,
	"---:---", NULS,
	"SELFTST", NULS,
	"$03:---", NULS,
	"Z ", NULS,
	"Z ", NULS,
	0
};

struct regs udregs16 [] = {     /* 16-byte status packet */
	"$02:PID", NULS,
	"LNG:DNO", NULS,
	"CMD:STY", NULS,
	"STATUS ", NULS,
	"DTY:---", NULS,
	"---:---", NULS,
	"SELFTST", NULS,
	"cnt:$03", NULS,
	"Z ", NULS,
	"Z ", NULS,
	0
};

struct regs udregs19 [] = {     /* 19-byte status packet */
	"$02:PID", NULS,
	"LNG:DNO", NULS,
	"CMD:STY", NULS,
	"STATUS ", NULS,
	"NUMBLKS", NULS,
	"BLKLENG", NULS,
	"STRT-HI", NULS,
	"STRT-LO", NULS,
	"CHKSUM ", NULS,
	"$03:---", NULS,
	0
};

struct regs wdregs [] = {
	0
};

#else

struct regs rkregs [] = {
	"DS",NUL4,Nl,"WPS",Nl,Nl,Nl,"SIN","DRU",NUL4,Nl,
	"ER","WCE","CSE","","","","NXS","NXC","NXD","TE","DLT",
		"NXM","PGE","SKE","WLO","OVR","DRE",
	"CS",NULS,
	"WC",NULS,
	"BA",NULS,
	"DA",NULS,
	0
};
struct regs rk2regs [] = {
	"CS1",NULS,
	"WC",NULS,
	"BA",NULS,
	"DA",NULS,
	"CS2",NULS,
	"DS",NULS,
	"ER",NULS,
	"ASOF",NULS,
	"DC",NULS,
	"Z   ",NULS,
	"DB",NULS,
	"MR1",NULS,
	"ECPS",NULS,
	"ECPT",NULS,
	"MR2",NULS,
	"MR3",NULS,
	0
};
struct regs rpregs[] = {
	"DS",NUL8,Nl,"SUFU",Nl,"SUSI","HNF",Nl,Nl,Nl,
	"ER","DSKERR","EOP","NXME","WCE","TIMEE","CSME",
		"WPE","LPE","MODE","FMTE","PROG","NXS","NXT","NXC","FUV","WPV",
	"CS",NULS,
	"WC",NULS,
	"BA",NULS,
	"CA",NULS,
	"DA",NULS,
	0
};
struct regs rfregs[] = {
	"CS",NUL8,Nl,"MXF","WLO","NED","DPE","WCE",Nl,Nl,
	"WC",NULS,
	"BA",NULS,
	"DA",NULS,
	"DAE",NUL4,Nl,"DAOVFL",Nl,"DRL",Nl,Nl,"NEM",
		"CTER","BTER","ATER","APE",Nl,
	0
};
struct regs tmregs [] = {
	"ER",Nl,Nl,"WRL",NUL4,"NXM","BTE","RLE","EOT",
		"BGL","PAE","CRE",Nl,"ILL",
	"CS",NULS,
	"BC",NULS,
	"BA",NULS,
	"Z   ",NULS,
	"Z   ",NULS,
	0
};
struct regs tcregs [] = {
	"CSR",NUL8,"NEX","DATM","BLKM","SELE","ILO","MTE","PAR",Nl,
	"CM",NULS,
	"WC",NULS,
	"BA",NULS,
	"Z   ",NULS,
	0
};
#ifdef vax
struct regs hpregs[] = {
	"CS1","GO","F0","F1","F2","F3","F4",Nl,Nl,NUL8,
	"DS",NUL4,Nl,Nl,"VV","DRY","DPR",Nl,Nl,Nl,"MOL","PIP","ERR","ATA",
	"ER1","ILF","ILR","RMR","PAR","FER","WCF","ECH","HCE",
		"HCRC","AOE","IAE","WLE","DTE","OPI","UNS","DCK",
	"MR",NULS,
	"AS","ATA0","ATA1","ATA2","ATA3","ATA4","ATA5","ATA6","ATA7",NUL8,
	"DA",NULS,
	"DT",NULS,
	"LA",NULS,
	"Z   ",NULS,
	"OF",NULS,
	"DC",NULS,
	"CC",NULS,
	"ER2",NULS,
	"ER3",NULS,
	"EC1",NULS,
	"EC2",NULS,
	0
};
struct regs hp2regs[] = {		/* RM02/3/5/80 Registers */
	"CS1","GO","F0","F1","F2","F3","F4",Nl,Nl,NUL8,
	"DS",NUL4,Nl,Nl,"VV","DRY","DPR",Nl,Nl,Nl,"MOL","PIP","ERR","ATA",
	"ER1","ILF","ILR","RMR","PAR","FER","WCF","ECH","HCE",
		"HCRC","AOE","IAE","WLE","DTE","OPI","UNS","DCK",
	"MR1",NULS,
	"AS","ATA0","ATA1","ATA2","ATA3","ATA4","ATA5","ATA6","ATA7",NUL8,
	"DA",NULS,
	"DT",NULS,
	"LA",NULS,
	"Z   ",NULS,
	"OF",NULS,
	"DC",NULS,
	"HR",NULS,
	"MR2",NULS,
	"ER2",NULS,
	"EC1",NULS,
	"EC2",NULS,
	0
};
struct regs htregs[] = {
	"CS1","GO","F0","F1","F2","F3","F4",NUL4,Nl,"DVA",NUL4,
	"DS","SLA","BOT","TM","IDB","SDWN","PES","SSC","DRY",
		"DPR",Nl,"EOT","WRL","MOL","PIP","ERR","ATA",
	"ER1","ILF","ILR","RMR","CPAR","FMT","DPAR","INC/VPE",
		"PER/LRC","NSG","FCE","CS/ITM","NEF","DTE","OPI","UNS",
		"COR/CRC",
	"MR",NULS,
	"AS","ATA0","ATA1","ATA2","ATA3","ATA4","ATA5","ATA6","ATA7",NUL8,
	"FC",NULS,
	"DT",NUL8,Nl,Nl,"SPR",NUL4,Nl,
	"CK",NULS,
	"SN",NULS,
	"TC","SS0","SS1","SS2","EVPAR","FMT0","FMT1","FMT2",
		"FMT3","DEN0","DEN1","DEN2",Nl,"EAODTE","TCW","FCS","ACCL",
	0
};

struct regs ht2regs[] = {	/* TM78 registers: */
	"CSR","GO",NUL8,Nl,Nl,"DVA",NUL4,
	"DTC",NUL8,"DPR",NUL4,Nl,Nl,Nl,
	"FM",NUL8,NUL4,Nl,Nl,Nl,"SER",
	"MR1",NULS,
	"AS",NULS,
	"FC",NULS,
	"DT",NUL8,Nl,"WCS",Nl,"DMB",Nl,Nl,"TAP","NSA",
	"DS",NUL4,"DSE",Nl,"SHR","AVL","FPT","EOT","BOT","PE","REW",
		"ONL","PRES","RDY",
	"SN",NULS,
	"MR2",NULS,
	"MR3",NULS,
	"NDC",NULS,
	"NDT0",NULS,
	"NDT1",NULS,
	"NDT2",NULS,
	"NDT3",NULS,
	0
};
struct vaxreg mbareg[] = {
	"MBACSR",NULS,NUL4,Nl,"OT","PU","PD",Nl,Nl,
		"XMTFLT","MT",Nl,"URD","WS","SBIPE",
	"MBACR","INIT","ABRT","IE","MM",NUL8,NUL4,NULS,
	"MBASR","RDTO","ISTO","RDS","ERCON","INVMAP","MAPPE","MDPE",
		"MBEXC","MXF","WCLE","WCUE","DLT","DTABT","DTCMP",Nl,
		Nl,"ATTN","MCPE","NFD","PGE",NUL8,Nl,"CRD","NRC","DTB",
	"MBAVAR",NULS,NULS,
	"MBABCR",NULS,NULS,
	0
};

struct vaxreg mem780[] = {
	"SBIER", Nl, "NBSY", "MLTERR", "IBERR", "IBTO0", "IBTO1", "IBTOS",
		"IBRDS", "CPERR", Nl, "CPTOS0", "CPTOS1", "CPTO", "RDS",
		"CRD", "RDSEN", NULS,
	"MCRC", NULS, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl,
		"ELOGRQ", "HERR", "INHCRD", Nl,
	0
};
struct vaxreg mem750[] = {
	"CSR0", NULS, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl,
		"CRD", "INL", "UERRF",
	0
};
struct regs tsregs[] = {	/* ts11 tape drive */
	"Z   ",NULS,
	"Z   ",NULS,
	"RBPCR",NULS,
	"XS0","EOT","BOT","WLK",Nl,Nl,"IE","ONL",Nl,"ILA",
		"ILC",Nl,"WLE","RLL","LET","RLS","TMK",
	"XS1","MTE","UNC",NUL4,Nl,Nl,Nl,"SCK",Nl,"TIG",Nl,Nl,Nl,"DLT",
	"XS2",NUL8,"DTP",Nl,"WCF",Nl,Nl,"BPE","SIP","OPM",
	"XS3","RIB",NUL4,"REV","OPI",Nl,NUL8,
	"TSSR",NUL4,"FC0","FC1",NUL8,Nl,"SC",
	0
};
#else
struct regs hpregs[] = {
	"CS1",NUL8,NUL4,Nl,"MCPE","TRE",Nl,
	"WC",NULS,
	"BA",NULS,
	"DA",NULS,
	"CS2",NUL8,"MDPE","MXF","PGE","NEM","NED","PE","WCE","DLT",
	"DS",NUL8,Nl,Nl,Nl,"WRL","MOL",Nl,Nl,Nl,
	"ER1","ILF","ILR","RMR","PAR","FER","WCF","ECH","HCE",
		"HCRC","AOE","IAE","WLE","DTE","OPI","UNS","DCK",
	"AS",NULS,
	"Z   ",NULS,
	"DB",NULS,
	"MR",NULS,
	"DT",NULS,
	"Z   ",NULS,
	"OF",NULS,
	"DC",NULS,
	"CC",NULS,
	"ER2",NULS,
	"ER3",NULS,
	"EC1",NULS,
	"EC2",NULS,
	"BAE",NULS,
	"CS3",NUL8,NUL4,Nl,Nl,Nl,"APE",
	0
};
struct regs hp2regs[] = {		/* RM02/3/5/80 Registers */
	"CS1",NUL8,NUL4,Nl,"MCPE","TRE",Nl,
	"WC",NULS,
	"BA",NULS,
	"DA",NULS,
	"CS2",NUL8,"MDPE","MXF","PGE","NEM","NED","PE","WCE","DLT",
	"DS",NUL8,Nl,Nl,Nl,"WRL","MOL",Nl,Nl,Nl,
	"ER1","ILF","ILR","RMR","PAR","FER","WCF","ECH","HCE",
		"HCRC","AOE","IAE","WLE","DTE","OPI","UNS","DCK",
	"AS",NULS,
	"Z   ",NULS,
	"DB",NULS,
	"MR1",NULS,
	"DT",NULS,
	"Z   ",NULS,
	"OF",NULS,
	"DC",NULS,
	"HR",NULS,
	"MR2",NULS,
	"ER2",NULS,
	"EC1",NULS,
	"EC2",NULS,
	"BAE",NULS,
	"CS3",NUL8,NUL4,Nl,Nl,Nl,"APE",
	0
};
struct regs htregs [] = {
	"CS1",NUL8,NUL4,Nl,"MCPE","TRE",Nl,
	"WC",NULS,
	"BA",NULS,
	"FC",NULS,
	"CS2",NUL8,"MDPE","MXF","PGE","NEM","NED","PE","WCE","DLT",
	"DS",Nl,"BOT",NUL8,"EOT","WRL","MOL",Nl,Nl,Nl,
	"ER","ILF","ILR","RMR","CPAR","FMT","DPAR",
		"INC/VPE","PEF/LRC","NSG","FCE","CS/ITM","NEF",
		"DTE","OPI","UNS","COR/CRC",
	"AS",NULS,
	"CK",NULS,
	"DB",NULS,
	"MR",NULS,
	"DT",NULS,
	"Z   ",NULS,
	"TC",NUL8,Nl,"NRZ","PE",NUL4,Nl,
	"BAE",NULS,
	"CS3",NUL8,NUL4,Nl,Nl,Nl,"APE",
	0
};
struct regs ht2regs[] = {
	"CS1","GO",NUL4,Nl,"IE","RDY",Nl,Nl,"PSEL","DVA",Nl,"MCPE","TRE","SC",
	"WC",NULS,
	"BA",NULS,
	"BCR",NULS,
	"CS2",Nl,Nl,Nl,"BAI","PAT","CLR","IR","OR","MDPE","MXF","PGE","NEM",
		"NED","UPE","WCE","DLT",
	"DTC",NUL8,"DPR",NUL4,Nl,Nl,Nl,
	"FM",NULS,
	"AS",NULS,
	"DS",NUL4,"DSE",Nl,"SHR","AVL","FPT","EOT","BOT",Nl,"REW","PRES","RDY",
	"DB",NULS,
	"MR1",NULS,
	"DT",NUL8,Nl,"WCS",Nl,"DMB",Nl,Nl,"TAP","NSA",
	"SN",NULS,
	"MR2",NULS,
	"MR3",NULS,
	"NDC",NULS,
	"NDT0",NULS,
	"NDT1",NULS,
	"NDT2",NULS,
	"NDT3",NULS,
	0
};
#endif
struct regs hsregs[] = {
	"CS1",NUL8,NUL4,Nl,"MCPE","TRE","SC",
	"WC",NULS,
	"BA",NULS,
	"DA",NULS,
	"CS2",NUL8,"MDPE","MXF","PGE","NEM","NED","PE","WCE","DLT",
	"DS",NUL8,Nl,Nl,Nl,"WRL","MOL",Nl,Nl,Nl,
	"ER","ILF","ILR","RMR","PAR",Nl,Nl,Nl,Nl,Nl,"AO",
		"IAE","WLE","DTE","OPI","UNS","DCK",
	"AS",NULS,
	"Z   ",NULS,
	"DB",NULS,
	"MR",NULS,
	"Z   ",NULS,
	"BAE",NULS,
	"CS3",NUL8,NUL4,Nl,Nl,Nl,"APE",
	0
};
struct regs rlregs[] = {
	"CS",NUL8,Nl,Nl,"OPI","CRC","DLT/HNF","NXM","DE",Nl,
	"BA",NULS,
	"DA",NULS,
	"MP",Nl,Nl,Nl,"BH","HO","CO","HS",Nl,"DSE","VC","WGE","SPE",
		"SKTO","WL","CHE","WDE",
	0
};

#endif

#ifdef m68k
int udblk();
int wdblk();
#else
int rkblk();
int rpblk();
int rfblk();
int tmblk();
int tcblk();
int gdblk();
int hsblk();
int rlblk();
#endif

/* Device specification functions */
/* Must remain in same order as true major device numbers */

#ifdef m68k
int (*func[]) () = {
	udblk,
	wdblk,
	0
};
struct regs  *devregs[] = {
	udregs9,
	wdregs,
	0
};

#else
int (*func[]) () = {
	rkblk,
	rpblk,
	rfblk,
	tmblk,
	tcblk,
	gdblk,
	gdblk,
	hsblk,
	rlblk,
	gdblk,
	gdblk,
	gdblk,
	0
};
struct regs  *devregs[] = {
	rkregs,
	rpregs,
	rfregs,
	tmregs,
	tcregs,
	hpregs,
	htregs,
	hsregs,
	rlregs,
	hpregs,
	hpregs,
	hpregs,
	0
};
#endif

struct pos {
	unsigned flg;
	unsigned unit;
#ifdef vax
	unsigned controller;	/* massbus controller number */
	unsigned slave;		/* for multiple tape drives on formater */
#endif
	unsigned cyl;
	unsigned trk;
	unsigned sector;
} pos;
/* Array order directed by MMR3 */
char *msg[] = {
	"User D Space Enabled",
	"Supervisor D Space Enabled",
	"Kernel D Space Enabled",
	Nl,
	"22 bit mapping Enabled",
	"UNIBUS MAP relocation Enabled",
	0
};

char *lines [] = {
/* 0*/	"\n",
/* 1*/	"%s\tError Logged On   %s\n",
/* 2*/	"\tPhysical Device\t\t\t%u\n",
/* 3*/	"\tLogical Device\t\t\t%d (%2.2o)\n",
/* 4*/	"\tDevice Address\t\t\t",
/* 5*/	"\tRetry Count\t\t\t%u\n",
/* 6*/	"\tError Diagnosis\t\t\t%s\n",
/* 7*/	"\tSimultaneous Bus Activity\t",
/* 8*/	"\tRegisters at Error time\n",
/* 9*/	"\t\t%s\t",
/*10*/	"\tPhysical Buffer Start Address\t",
/*11*/	"\tTransfer Size in Bytes\t\t%16u\n",
/*12*/	"\tType of Transfer\t\t\t%8s\n",
/*13*/	"\tBlock No. in Logical File System\t%8ld\n",
/*14*/	"\tI/O Type\t\t\t\t%8s\n",
/*15*/	"\tCylinder\t\t\t\t%8u\n",
/*16*/	"\tTrack\t\t\t\t\t%8u\n",
/*17*/	"\tSector\t\t\t\t\t%8u\n",
/*18*/	"\tStatistics on Device to date:\n",
/*19*/	"\t\tR/W Operations\t\t%16ld\n",
/*20*/	"\t\tOther Operations\t%16ld\n",
/*21*/	"\t\tUnrecorded Errors\t%16u\n",
/*9b*/	"%o      ",
/*23*/	"\tSector Requested\t\t%u\n",
/*24*/  "\tUnibus Map Utilization?\t\t\t%3.3s\n",
#ifdef vax
/*2a*/	"\tController\t\t\t%d\n",
/*2b*/	"\tPhysical Device\t\t\t%u\t\tSlave\t%u\n",
#endif
	0
};

char *xlines [] = {
/* 0*/  "\n\nDEVICE CONFIGURATION CHANGE   - %s\n",
/* 1*/	"\tDEVICE: %s - %s\n",
/* 2*/	"\n\nSTRAY INTERRUPT on %s\n",
/* 3*/  "\tFor Controller at - ",
/* 4*/	"\tAt Location\t",
#ifdef pdp11
/* 5*/	"\n\nMEMORY PARITY ERROR at %s\n",
/* 6*/	"\tMemory Address of Error - %lo (cycle %d)\n\n",
/* 7*/	"\t\tMSER\t%.6o",
/* 8*/	"\t\tMSCR\t%.6o",
#else
/* 5*/	"\n\nMEMORY ECC on %s\n",
/* 6*/	"\tError Address (%s)\t%.5X\n",
/* 7*/	"\tError Syndrome\t\t\t%.2X\n",
/* 8*/	0,
#endif
/* 9*/	"\n\nTIME CHANGE ***** FROM %s",
/*10*/  "\t\t   TO  %s \n\n\n\n",
/*11*/  "\nERROR LOGGING SYSTEM SHUTDOWN - %s\n\n\n",
/*12*/	"\nERROR LOGGING SYSTEM STARTED - %s \n",
/*13*/	"\n\n\tSystem Profile:\n\n",
/*14*/	"\t     11/%d  Processor\n",
/*15*/	"\t     System Memory Size - %ld Bytes\n",
/*16*/	Nl,
/*17*/	"\t     UNIX/%s  Operating System (%s)\n",
/*18*/  "\t     %s \n",
	0
};

char *sumlines [] = {
/* 0*/	"\n\n",
#ifdef vax
/* 1*/	"%s\tUnit  %d\t Controller %d\n",
#else
/* 1*/	"%s\tUnit  %d\n",
#endif
/* 2*/	"\tHard Errors\t\t- %10ld\n",
/* 3*/	"\tSoft Errors\t\t- %10ld\n",
/* 4*/	"\tTotal I/O Operations    - %10ld\n",
/* 5*/	"\tTotal Misc. Operations  - %10ld\n",
/* 6*/	"\tErrors Missed\t\t- %10ld\n",
/* 7*/	"\tTotal Read Errors\t\t-   %ld\n",
/* 8*/	"\tTotal Memory Parity Errors\t-   %d\n",
/* 9*/	"\tTotal Stray Interrupts\t\t-   %d\n",
/*10*/	"\tDate of Earliest Entry: %s",
/*11*/	"\tDate of Latest   Entry: %s",
/*12*/  "\tError Types: %s\n",
/*13*/  "\tLimitations: ",
/*14*/  "\t\t",
#ifdef vax
/*15*/	"%s\tUnit  %d\t Slave  %d\t Controller %d\n",
#endif
0
};


/* Correspondence of input requests to major device defines */
struct tab {
	char *devname ;
	int devnum;
};

#ifdef m68k
struct tab dtab[] = {
	"ud", UD0,	"ud0",UD0,
	"wd", WD0,	"wd0",WD0,
	"mem",MEM,	"int",INT,	0,0
};

#else
struct tab dtab[] = {
	"rk",RK0,	"rk05",RK0,	"tc",TC0,	"rk07",RK0,	"rm80",HP0,
	"rp",RP0,	"rp03",RP0,	"rf",RF0,	"rf11",RF0,
	"tm",TM0,	"tu",TM0,	"mt",TM0,	"tu10",TM0,	"ts11",TM0,
	"tc11",TC0,	"hp",HP0,	"rp04",HP0,	"rp05",HP0,
	"rp07",HP0,	"rm05",HP0,	"rp06",HP0,	"ht",HT0,	"te16",HT0,
	"tm78",HT0,	"tu78",HT0,	"tu16",HT0,	"hs",HS0,
	"rs03",HS0,	"rs04",HS0,	"rs",HS0,	"rl",RL0,
	"rl01",RL0,	"mem",MEM,	"int",INT,	0,0
};
#endif

main (argc,argv)
char *argv[];
int argc;
{
	register i,j;
	print = NO;
	while (--argc>0 && **++argv =='-') {
		switch (*++*argv) {
		case 's':	/* starting at a specified time */
			header = hd1;
			if((--argc <=0) || (**++argv == '-'))
			error("Date required for -s option",(char *)NULL);
			if(gtime(&xtime,*argv))
				error("Invalid Start time",*argv);
			break;
		case 'e':	/* ending at a specified time */
			header = hd1;
			if((--argc<=0) || (**++argv =='-'))
				error("Date required for -e option\n",(char *)NULL);
			if(gtime(&etime,*argv))
				error("Invalid End time.",(char *)NULL);
			break;
		case 'a':	/* print all devices*/
			aflg++;
			mode = PRINT;
			break;
		case 'p':	/* limit total no. of pages */
			if((--argc<=0) || (**++argv == '-'))
				error("Page limit not supplied.\n",(char *)NULL);
			limit = atoi(*argv);
			break;
		case 'f':	/* fatal errors */
			header = hd1;
			fflg++;
			break;

		default:
			if(j=encode(*argv)) {
				optdev = (optdev |= j);
				dflg++;
				header = hd1;
				mode = PRINT;
				if(strlen(choice)) concat(",",choice);
				concat(*argv,choice);
				}
			else
			(void) fprintf(stderr,"%s?\n",argv);
		}
	}
	for(i = 0;i < NMAJOR;i++) {
		for(j = 0; j < NMINOR; j++) {
			sums[i][j].hard = 0;
			sums[i][j].soft = 0;
			sums[i][j].totalio = 0;
			sums[i][j].misc = 0;
			sums[i][j].missing = 0;
#ifdef vax
			sums[i][j].contr = 0;
			sums[i][j].slave = 0;
#endif
			tot_sums[i][j].totalio = 0;
			tot_sums[i][j].misc = 0;
			tot_sums[i][j].missing = 0;
			base_sums[i][j].totalio = 0;
			base_sums[i][j].misc = 0;
			base_sums[i][j].missing = 0;
		}
	}

	parsum=0;
	straysum=0;
	if(gtime(&atime,INAUG)) error("Invalid INAUG time",INAUG);
	if (argc ==0)
		report("/usr/adm/errfile");
	else while(argc--) 
		report(*argv++);
	printsum();
	putft();
	exit(0);
}

/* Associate typed name with a specific bit in "optdev" */
encode(p)
char  *p;
{
	register struct tab *q;
	int lower();

	lower (p); /* convert device name to lower case */
	for(q=dtab;q->devname;q++) {
		if (!strcmp(q->devname,p)) {
#ifdef m68k
			return(1<<(q->devnum));
#else
			if (q->devnum != HP0)
				return(1<<(q->devnum));
			else
				return (1<<HP0 | 1<<HP1 | 1<<HP2 | 1<<HP3);
#endif
		}
	}
	return(0);
}

report(fp)
char *fp;
{
	register int i, j;

	if ((file = fopen(fp, "r")) == NULL)
		error("cannot open", fp);
	inithdng();
	if (writout())
		puthead(header);
	putdata();
	if (writout())
		putft();
	for(i = 0; i < NMAJOR; i++)
		for(j = 0; j < NMINOR; j++)
			if(sums[i][j].totalio)
				adjustsum(i, j);
}
putdata()
{
	while(fread((char*)&e_hdr.e_type, sizeof(struct errhdr), 1, file)) {
newtry:
		switch(e_hdr.e_type) {
		
		case E_GOTS:
			setime();
			up();
			break;

		case E_GORT:
			setime();
			up();
			break;

		case E_STOP:
			setime();
			down();
			break;

		case E_TCHG:
			setime();
			timecg();
			break;

		case E_BLK:
			setime();
			blk();
			break;
		
		case E_STRAY:
			setime();
			stray();
			break;

		case E_PRTY:
			setime();
			party();
			break;

		case E_CCHG:
			cconfig();
			setime();
			break;
		default:
			fprintf(stderr, "%d\n", e_hdr.e_len);
			fprintf(stderr, "%d\n", e_hdr.e_type);
			readerr++;
			if (recov())
				goto newtry;
			fprintf (stderr, "Unrecovered read error.\n");
		}
	}

}
/* System Startup Record */

#define est	ercd.start
up()
{
register int i;

	if (!readrec(file)) {
		fprintf(stderr, "at up = %o\n", est.e_cpu);
		fprintf(stderr, "%o\n", est.e_mmr3);
		fprintf(stderr, "%ld\n", est.e_name.release);
		fprintf(stderr,
			"%s %s\n", est.e_name.release, est.e_name.sysname);
		readerr++;
		return;
	}
	cputype = est.e_cpu;
	if (writout()) {
		need(13+araysz(msg));
		printf(xlines[12], ctime(&e_hdr.e_time));
		printf(xlines[13]);
		printf(xlines[17], est.e_name.release, est.e_name.sysname);
		printf(xlines[14], est.e_cpu);
		if (est.e_syssize)
			printf(xlines[15], est.e_syssize);
		else
			line--;
		for(i = 0; i <= araysz(msg) + 1; i++)
			if (est.e_mmr3 & (1 << i))
				printf(xlines[18], msg[i]);
			else
				line--;
		printf(lines[0]);
	}
}
/* System Shutdown Record */

down()
{
	if (writout()) {
		need(5);
		printf(xlines[11], ctime(&e_hdr.e_time));
	}
}
/* Time Change Record */

timecg()
{
	if (!readrec(file)) {
		readerr++;
		return;
	}
	if (writout()) {
		need(8);
		printf(xlines[9], ctime(&e_hdr.e_time));
		printf(xlines[10], ctime(&ercd.timchg.e_ntime));
	}
}
/* Handle a MERT configuration change */
cconfig() 
{

	if (!readrec(file)) {
		readerr++;
		return;
	}
	if (writout()) {
		need(7);
		printf(xlines[0], ctime(&e_hdr.e_time));
		printf(lines[0]);
		printf(xlines[1], dev[ercd.confchg.e_trudev],
			ercd.confchg.e_cflag ? "Attached" : "Detached");
		printf(lines[0]);
	}
}

/* Stray Interrupt Record */

#define estr	ercd.stray
stray()
{
	if (!readrec(file)) {
		readerr++;
		return;
	}
	if (!wanted())
		return;
	if (print == YES) {
		need(6);
		if (page <= limit) {
			printf(xlines[2], ctime(&e_hdr.e_time));
			if (estr.e_saddr < DEVADR)
				printf(xlines[4]);
			else
				printf(xlines[3]);
			printf(FORM, estr.e_saddr);
			printf(lines[0]);
			printf(lines[7]);
			if (estr.e_sbacty == 0)
				printf("None\n");
			else
				afix(araysz(dev)+1,
					(unsigned) estr.e_sbacty, dev);
		}
	}
	straysum++;
}

/* Memory Parity Record */
party()
{
#ifndef m68k
	register struct vaxreg *q;
#endif
	char *ctime();

	if (!readrec(file)) {
		readerr++;
		return;
	}
	if (!wanted())
		return;
	if (print == YES) {
#ifdef pdp11
		need(9);
#else
		need(11);
#endif
		if (page > limit)
			return;
		printf(xlines[5], ctime(&e_hdr.e_time));
#ifdef pdp11
		printf(xlines[6],(((long)(erp.e_parreg[1]&077))<<WDLEN) +
			((long)((unsigned) erp.e_parreg[0])),
			(erp.e_parreg[1]>>14)&03);
		printf(lines[0]);
		printf(lines[8]);
		printf(xlines[7], erp.e_parreg[2]);
		printf(lines[0]);
		printf(xlines[8], erp.e_parreg[3]);
#else
#ifdef vax
		printf(lines[0]);
		if (cputype == 780) {
			printf(xlines[6], "Longword",
				(erm.e_memcad & 0X0fffff00) >> 6);
			printf(xlines[7], erm.e_memcad & 0x000000ff);
			printf(lines[0]);
			printf(lines[8]);
			q = mem780;
			printf("\t  %-4.4s\t  ", q->regname);
			printf(FORM, erm.e_sbier);
			afix(WDLEN*2, erm.e_sbier, q->bitcode);
			printf("\t  %-4.4s\t  ", (++q)->regname);
			printf(FORM, erm.e_memcad);
			afix(WDLEN*2, erm.e_memcad, q->bitcode);
		} else {
			--line;
			printf(xlines[6], "within page", erm.e_memcad);
			printf(xlines[7], erm.e_sbier & 0x0000007f);
			printf(lines[0]);
			printf(lines[8]);
			q = mem750;
			printf("\t  %-4.4s\t  ", q->regname);
			printf(FORM, erm.e_sbier);
			afix(WDLEN*2, erm.e_sbier, q->bitcode);
		}
#endif
#endif
	}
	parsum++;
}

/* Device Error Record */

blk()
{
	register union ercd *z;
	register int i;
	register struct sums *p;
	register struct eblock *r;
	int *mbar;
#ifdef vax
	struct vaxreg *q;
#endif
	int ldev;

#ifdef vax
	pos.controller = pos.slave = pos.flg = 0;
#else
	pos.flg = 0;
#endif
	if (!readrec(file)) {
		readerr++;
		return;
	}
	z = &ercd;
	maj = major(recrd.e_dev);
	ldev = min = minor(recrd.e_dev);
	if ((maj > araysz(func)) | maj < 0)
		return;
	if (!wanted())
		return;
	regs_ptr = devregs[maj];

	(*func[maj])();

	/* Increment summary totals */
	
	p = &sums[maj][min];
	r = &recrd;
	if (r->e_bflags & E_ERROR)
		p->hard++;
	else
		p->soft++;
	if (r->e_stats.io_ops < p->totalio)
		adjustsum(maj, min);

	if (!(p->drvname))
		p->drvname = dev[maj];
#ifdef vax
	p->contr = pos.controller;
	p->slave = pos.slave;
#endif
	p->totalio = r->e_stats.io_ops;
	p->misc = r->e_stats.io_misc;
	p->missing = r->e_stats.io_unlog;

	if (print == NO)
		return;

#ifdef vax
	mb_dev = (maj == HP0 || maj == HT0 || maj >= HP1);
	need(PNEED + r->e_nreg + mb_dev * 5 + pos.flg * 5);
#else
	need(PNEED + r->e_nreg + pos.flg * 5);
#endif
	if (page > limit)
		return;
	printf(lines[0]);
	printf(lines[1], p->drvname, ctime(&e_hdr.e_time));
#ifdef vax
	if (pos.slave)
		printf(lines[26], pos.unit, pos.slave);
	else
		printf(lines[2], pos.unit);
	printf(lines[25], p->contr);
#else
	printf(lines[2], pos.unit);
#endif
	printf(lines[3], ldev, ldev);
	printf(lines[4]);
	printf(FORM, r->e_regloc);
	printf(lines[0]);
	printf(lines[5], r->e_rtry);
	printf(lines[6], r->e_bflags & E_ERROR ?
		"Unrecovered" : "Recovered");
	printf(lines[7]);
	if (r->e_bacty == 0)
		printf("None\n");
	else
		afix(WDLEN, (unsigned) r->e_bacty, dev);
	printf(lines[0]);
	printf(lines[8]);
#ifdef vax
	if (mb_dev) {
		mbar = ((int *) &z->ebb.block.e_mba);
		q = mbareg;
		for(i = 0; i < MBAREG; i++, mbar++, q++) {
			printf("\t  %-6.6s   %.8X", q->regname, *mbar);
			afix(WDLEN*2, *mbar, q->bitcode);
		}
	}
#endif

#ifdef m68k
	for(i = 0; i < r->e_nreg; i++, regs_ptr++) {
		if (*regs_ptr->regname != 'Z') {
			printf("\t  %-7.7s\t   ", regs_ptr->regname);
			printf("%4.4x", ercd.ebb.reginf[i]);
			afix(WDLEN, ercd.ebb.reginf[i], regs_ptr->bitcode);
		} else
			line--;	/* adjust page-position counter */
	}
#else
	for(i = 0; i < r->e_nreg; i++, regs_ptr++) {
		if (*regs_ptr->regname != 'Z') {
			printf("\t  %-4.4s\t   ", regs_ptr->regname);
			printf("%8.6o", ercd.ebb.reginf[i]);
			afix(WDLEN, ercd.ebb.reginf[i], regs_ptr->bitcode);
		} else
			line--;	/* adjust page-position counter */
	}
#endif

	printf(lines[0]);
	printf(lines[10]);
	printf(FORM2, r->e_memadd);
	printf(lines[11], r->e_bytes);
	i = r->e_bflags;
	printf(lines[12],
		(i & E_NOIO) ? "No-op" : ((i & E_READ) ? "Read" : "Write"));
	printf(lines[13], r->e_bnum);
	if (Unix)
		printf(lines[14], i & E_PHYS ? "Physical" : "Buffered");
	else
		line--;
	printf(lines[0]);
#ifdef m68k
	if (pos.flg) {
		printf(lines[0]);
		line--;
		printf(lines[16], pos.trk);
		printf(lines[17], pos.sector);
		printf(lines[0]);
	}
#else
	if (pos.flg) {
		printf(lines[0]);
		if (maj != HS0)
			printf(lines[15], pos.cyl);
		else line--;
		printf(lines[16], pos.trk);
		if (maj == HS0)
			printf(lines[23], pos.sector, pos.sector+n);
		else
			printf(lines[17], pos.sector);
		printf(lines[0]);
	}
#endif
	printf(lines[0]);
	printf(lines[18]);
	printf(lines[19], tot_sums[maj][min].totalio+r->e_stats.io_ops);
	printf(lines[20], tot_sums[maj][min].misc+r->e_stats.io_misc);
	printf(lines[21], tot_sums[maj][min].missing+r->e_stats.io_unlog);
	printf(lines[0]);
}

#ifdef m68k

udblk()
{

	pos.unit = U_DEV_NUM;

	switch (PACKET_LENGTH)  {

	case 9:
		break;
	case 13:
		regs_ptr = udregs13;
		break;
	case 15:
		regs_ptr = udregs15;
		break;
	case 16:
		regs_ptr = udregs16;
		break;
	case 19:
		regs_ptr = udregs19;
		break;
	default:
		fprintf (stderr, "Invalid block device number.\n");

	}
}

wdblk()
{
}

#else

rkblk()
{
	register int m;
	register daddr_t d;
	register int track, sect;

	pos.flg = 1;
	m = min - 7;
	if (m <= 0) {
		d = recrd.e_bnum;
		pos.unit = min;
	}
	else {
		d = recrd.e_bnum / m;
		pos.unit =  recrd.e_bnum % m;
	}
	if (recrd.e_nreg > 8) {
		sums[maj][pos.unit].drvname = (ercd.ebb.reginf[0] & 01000) ?
			"RK06" : "RK07";
		regs_ptr = rk2regs;
		track = 3; sect = 22;
	} else {
		track = 2; sect = 12;
	}
	min = pos.unit;
	pos.cyl = d / (track * sect);
	pos.trk = d % (track * sect) / sect;
	pos.sector = d % (track * sect) % sect;
}
rpblk()
{

	pos.flg = 1;
	min = pos.unit = min>>DSEC;
	pos.cyl = recrd.e_cyloff;
	pos.cyl += recrd.e_bnum / (20 * 10);
	pos.trk = (recrd.e_bnum % (20 * 10)) / 10;
	pos.sector = (recrd.e_bnum % (20 * 10)) % 10;
}

rfblk()
{
	pos.flg = 1;
	min = pos.unit = recrd.e_bnum >> 10;
	pos.trk = (recrd.e_bnum % 1024) >> 3;
	pos.cyl = 0;
	pos.sector = (recrd.e_bnum % 1024) % 8;
}
tmblk()
{
	min = pos.unit = min & 03;
#ifdef vax
	if (recrd.e_nreg > 6) {
		regs_ptr = tsregs;
		sums[maj][pos.unit].drvname = "TS11";
	}
	else
		sums[maj][pos.unit].drvname = "TU10";
#endif
}
tcblk()
{
	min = pos.unit = min & 07;
}
gdblk()
{
	register int track, sect, dt;
	register struct eblock *r;
	char *findname();

	dt = DRIVE_TYPE;
	if ( (dt & 0770) == GTTM03 || (dt  & 0770) == GTTM78 || maj == HT0) {
		pos.unit = (min >> 1) & 01;
#ifdef vax
		pos.slave = min & 01;
#endif
		min &= 03;
		regs_ptr = ((dt & 0770) == GTTM78) ? ht2regs : htregs;
	} else {
		switch (dt) {
		case GDRM03:
			sect = 32;
			track = 19;
			regs_ptr = hp2regs;
			break;
		case GDRM05:
			sect = 32;
			track = 19;
			regs_ptr = hp2regs;
			break;
		case GDRM80:
			sect = 32;
			track = 7;
			regs_ptr = hp2regs;
			break;
		case GDRP07:
			sect = 50;
			track = 32;
			break;
		default:	/* RP04/5/6 */
			sect = 22;
			track = 19;
			break;
		}
		pos.flg = 1;
		min = pos.unit = (min & 070) >> DSEC;
		r = &recrd;
		pos.cyl = r->e_cyloff + r->e_bnum / (track * sect);
		pos.trk = (r->e_bnum % (track * sect)) / sect;
		pos.sector = (r->e_bnum % (track * sect)) % sect;
	}
#ifdef vax
	pos.controller = (min >> 6) & 03;
#endif
	sums[maj][min].drvname = findname();
}
hsblk()
{
	register div;

	if (min & 010) {
		div = 32L;
		n = 1;
	}
	else {
		div = 16L;
		n = 3;
	}
	pos.flg = 1;
	pos.cyl = 0;
	min = pos.unit = min & 07;
	pos.trk = recrd.e_bnum / div;
	pos.sector = (recrd.e_bnum % div) * (n + 1);
}
rlblk()
{
	pos.flg = 1;
	pos.unit = min;
	pos.trk = recrd.e_bnum / (20 * 256);
	pos.cyl = ((recrd.e_bnum) % (20 * 256)) / 20;
	pos.sector = ((recrd.e_bnum) % (20 * 256)) % 20;
	pos.sector *= 2;
}

#endif  /* m68k */

cleanse(p, q)
	register char *p;
	register int q;
{
	while(q--)
		*p++ = '\0';
}

afix(a, b, c)
int a;
unsigned b;
char **c;
{
	register i;
	cleanse(interp,MAXSTR);
	for(i = 0; i < a; i++)  {
		if ((b & (1<<i)) && (*c[i])) {
			if ((strlen(c[i]) + strlen(interp)) >= MAXSTR) {
				concat(",", interp);
				printf("\t%s\n\t\t\t", interp);
				line++;
				cleanse(interp,MAXSTR);
			}
			else {
				if (*interp)
					concat(",", interp);
			}
			concat(c[i], interp);
		}
	}
	if (*interp)
		printf("\t%s\n", interp);
	else
		putchar('\n');
}
puthead(h)
char *h;
{
	printf("\n\n   %s   Prepared on %s     Page  %d\n\n\n\n",
		h, htime, page);
	line = 6;
}
inithdng()
{

	char *cbuf;
	time(&tloc);
	cbuf = ctime(&tloc);
	cbuf[16] = '\0';
	strcpy(htime, cbuf + 4);
}
putft()
{
	while (line++ < MAXLEN)
		putchar('\n');
	page++;
}
trnpg()
{
	if ( line >= MAXLEN)
		page++;
	else
		putft();
	if (page <= limit)
		puthead(header);
}
need(a)			/* acts like ".ne" command of nroff */
int a;
{
	if ( line > (PGLEN - a))
		trnpg();
	line += a;
}
gtime(tptr, pt)
char *pt;
time_t	*tptr;
{
	register int i;
	register int y, t;
	int d, h, m;
	long nt;

	t = gpair(pt++);
	if (t < 1 || t > 12)
		return(1);
	pt++;
	d = gpair(pt++);
	if (d < 1 || d > 31)
		return (1);
	pt++;
	h = gpair(pt++);
	if (h == 24) {
		h = 0;
		d++;
	}
	pt++;
	m = gpair(pt++);
	if (m < 0 || m > 59)
		return (1);
	pt++;
	y = gpair(pt++);
	if (y < 0) {
		time(&nt);
		y = localtime(&nt)->tm_year;
	}
	*tptr = 0;
	y += 1900;
	for(i = 1970; i < y; i++)
		*tptr += dysize(i);
	/* Leap year */
	if (dysize(y) == 366 && t >= 3)
		*tptr += 1;
	while(--t)
		*tptr += dmsize[t - 1];
	*tptr += d - 1;
	*tptr = (*tptr * 24) + h;
	*tptr = (*tptr * 60) + m;
	*tptr *= 60;
	*tptr += timezone;
	if (localtime(tptr)->tm_isdst)
		 *tptr -= 60 * 60;
	return(0);

}
gpair(pt)
char *pt;
{
	register int c, d;
	register char *cp;

	cp = pt;
	if (*cp == 0)
		return(-1);
	c = (*cp++ - '0') * 10;
	if (c < 0 || c > 100)
		return(-1);
	if (*cp == 0)
		return(-1);
	if ((d = *cp++ - '0') < 0 || d > 9)
		return(-1);
	return (c + d);
}

wanted ()
{
	/* Starting - ending limitations? */
	if (e_hdr.e_time < xtime ) {
		if (e_hdr.e_type != E_BLK)
			return 0;
		(*func[maj])();
		base_sums[maj][min].totalio = recrd.e_stats.io_ops;
		base_sums[maj][min].misc = recrd.e_stats.io_misc;
		base_sums[maj][min].missing = recrd.e_stats.io_unlog;
		return (0);
	}
	if (e_hdr.e_time > etime)
		return (0);
	/* Only fatal error flag? */
	if ((fflg) && (e_hdr.e_type == E_BLK) &&
	    !(recrd.e_bflags & E_ERROR))
		return(0);
	/* Stray interrupts or parity errors to be considered */
	if ((aflg) || ((e_hdr.e_type == E_STRAY) && (optdev & (1 << INT))) ||
		((e_hdr.e_type == E_PRTY) && (optdev & (1 << MEM)))) {
		print = YES;
		return (1);
	}
	/* Device chosen for consideration or printing? */
	if (dflg == 0) {
		print = NO;
		return(1);
		}
	if ((1 << maj) & optdev) {
		print = YES;
		return(1);
		}
	print = NO;
	return(0);
}
error(s1, s2)
char *s1, *s2;
{
	fprintf(stderr, "errpt: %s %s \n", s1, s2);
	exit(16);
}

recov()
{
	struct errhdr *p,*q;
	int i;
	for(;;) {
		p = q = &e_hdr;
		q++;
		for(i = 0; i < ((sizeof(struct errhdr) / 2) - 1); i++)
			*p++ = *q++;
		fread(p, 2, 1, file);
		if (feof(file))
			return(0);
		if (valid())
			return (1);
	}
}
valid()
{
	switch(e_hdr.e_type) {
		default:
			return(0);
		case E_GOTS:
		case E_GORT:
		case E_STOP:
		case E_TCHG:
		case E_BLK:
		case E_STRAY:
		case E_CCHG:
		case E_PRTY:
			if ((e_hdr.e_len < MINREC) ||
				 (e_hdr.e_len > MAXREC) )
				return (0);
			if ((e_hdr.e_time < atime) ||
				 (e_hdr.e_time > tloc))
				return(0);
			return (1);
	}
}
lower(str_ptr)
char *str_ptr;
{
	for(; *str_ptr; str_ptr++)
		*str_ptr = tolower(*str_ptr);
}

char *
findname()
{
	switch (DRIVE_TYPE){
	case GDRP04:
		return "RP04";
	case GDRP05:
		return "RP05";
	case GDRP06:
		return "RP06";
	case GDRP07:
		return "RP07";
	case GDRM03:
		return "RM03";
	case GDRM05:
		return "RM05";
	case GDRM80:
		return "RM80";
	default:
		switch (DRIVE_TYPE & 0770){
		case GTTM78:
			return "TM78";
		case GTTM02:
		case GTTM03:
#ifdef pdp11
			return "TU16";
#else
			return "TE16";
#endif
		default:
			return "UNKNOWN";
		}
	}
}
concat(a, b)
	register char *a,*b;
{
	while (*b) b++;
	while (*b++ = *a++);
}
setime()
{
	if (e_hdr.e_time < fftime)
	fftime = e_hdr.e_time;
	if (e_hdr.e_time > ltime)
	ltime = e_hdr.e_time;
}

adjustsum(i, j)
register int i, j;
{
	tot_sums[i][j].totalio += sums[i][j].totalio;
	tot_sums[i][j].misc += sums[i][j].misc;
	tot_sums[i][j].missing += sums[i][j].missing;
	sums[i][j].totalio = 0;
	sums[i][j].misc = 0;
	sums[i][j].missing = 0;
	if (base_sums[i][j].totalio &&
	    base_sums[i][j].totalio < sums[i][j].totalio) {
		tot_sums[i][j].totalio -= base_sums[i][j].totalio;
		tot_sums[i][j].misc -= base_sums[i][j].misc;
		tot_sums[i][j].missing -= base_sums[i][j].missing;
		base_sums[i][j].totalio = 0;
		base_sums[i][j].misc = 0;
		base_sums[i][j].missing = 0;
	}
}
printsum()
{
	int i;
	header = hd2;
	page = 1;
	puthead(header);
	need(11);
	printf(sumlines[12], choice[0] ? choice : "All");
	printf(sumlines[13]);
	if (xtime) {
		printf("On or after %s", ctime(&xtime));
		printf(sumlines[14]);
	}
	else
		line--;
	if (etime != 017777777777L) {
		printf("On or before %s", ctime(&etime));
		printf(sumlines[14]);
	}
	else
		line--;
	if (fflg) {
		printf("Only fatal errors are printed.\n");
		printf(sumlines[14]);
	}
	else
		line--;
	if (limit != 10000)
		printf("Printing suppressed after page %d.\n", limit);
	else
		line--;
	printf(lines[0]);
	printf(sumlines[10], ctime(&fftime));
	printf(sumlines[11], ctime(&ltime));
	printf(lines[0]);
	if (readerr)
		printf(sumlines[7], readerr);
	else
		printf(lines[0]);
	printf(lines[0]);
	if ((optdev & (1 << INT)) || !(dflg) || (aflg)) {
		need(3);
		printf(lines[0]);
		printf(sumlines[9], straysum);
		printf(lines[0]);
	}
	if ((optdev & (1 << MEM)) || !(dflg) || (aflg)) {
		need(3);
		printf(lines[0]);
		printf(sumlines[8], parsum);
		printf(lines[0]);
	}
	if ((dflg == 0) || aflg)
		for(i = 0; i < NMAJOR; i++)
			prsum(i);
	else
		for(i = 0; i < NMAJOR; i++)
			if (optdev & (1<<i))
				prsum(i);
	if (line == 7)
		printf("No errors for this report\n");
}

prsum(i)
register int i;
{
	register int j;

	for(j = 0; j < NMINOR; j++) {
		if (tot_sums[i][j].totalio || sums[i][j].totalio) {
			need(10);
#ifdef vax
			if (sums[i][j].slave)
				printf(sumlines[15], sums[i][j].drvname,
					(j >> 1) & 01, sums[i][j].slave,
					sums[i][j].contr);
			else
				printf(sumlines[1], sums[i][j].drvname,
					j, sums[i][j].contr);
#else
			printf(sumlines[1], sums[i][j].drvname, j);
#endif
			printf(sumlines[0]);
			printf(sumlines[2], sums[i][j].hard);
			printf(sumlines[3], sums[i][j].soft);
			printf(sumlines[4], tot_sums[i][j].totalio);
			printf(sumlines[5], tot_sums[i][j].misc);
			printf(sumlines[6], tot_sums[i][j].missing);
			printf(sumlines[0]);
		}
	}
}
