#
/* Format and interpret the error log file */

#define araysz(x)	((sizeof(x)/sizeof(x[0]))-1)
#define PAD 9
#define NSP 8
#define NF 0
#define MAXLEN 65
#define PGLEN 60

/* space allowances for report sections */

#define SNEED 10
#define TNEED 7
#define DNEED 5
#define ANEED 12
#define BNEED 5
#define CNEED 6
#define ONE 1

/* true major device numbers */

#define RK	0
#define RP	1
#define RF	2
#define TM	3
#define TC	4
#define HP	5
#define HT	6
#define HS	7



/* error record header */

struct emsghd {
	char e_type;
	char e_fill;
	long e_ctime;
} emsghd;

/* startup record */

struct estart {
	int	es_cpu;
	int	es_mmr3;
	char	es_nbdev;
	char	es_ncdev;
	int	es_bconf;
	int	es_cconf;
}estart;

/* time change record */

struct etchg {
	long	e_ntime;
} etchg;

struct iostat {
	long io_ops;
	long io_misc;
	int io_unlog;
};
/* block device error record */

struct eblock {
	char d_minor;
	char d_major;
	struct	iostat e_stat;
	int	e_bacty;
	int	e_cacty;
	char	e_rtry;
	char	e_nreg;
	int	e_rloc;
	int	eb_bflg;
	int	eb_wcnt;
	long	eb_maddr;
	int	eb_bno;
} eblock;

/* RP03 minor device starting cylinder numbers */

int rpoffst[] {
		0,
		203,
		0,
		360,
		0,
		78,
		0,
		328
};

/* RP04 minor device starting cylinder numbers */

int hpoffst[] {
	0,
	44,
	201,
	358,
	0,
	100,
	201,
	300,
	0,
	44,
	202,
	360,
	408,
	566,
	724,
	44,
	123,
	202,
	281,
	380,
	408,
	487,
	566,
	645,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0
};

int col;
int file;
int tab[6] {0,8,16,40,51,5};
int drvregs[30];

char *cbuf;
char *htime[20];
char *header "UNIX SYSTEM ERROR REPORT";
char *hd1 "UNIX System Error Report - Selected Items";
char *hd2 "UNIX Summary Error Report";
struct inode {
	int dev;
	int inum;
	int flags;
	char nlink;
	char uid;
	char gid;
	char size0;
	int size;
	int ptr[8];
	int atime[2];
	int mtime[2];
	};
char *dev[] {
	"RK05",
	"RP03",
	"RF11",
	"TU10",
	"TC11",
	"RP04/5",
	"TU16",
	"RS03/4",
	0
};
char *rkregs[] {
	"RKDS",
	"RKER",
	"RKCS",
	"RKWC",
	"RKBA",
	"RKDA",
	"RKDB",
	0
};
char *rpregs[] {
	"RPDS",
	"RPER",
	"RPCS",
	"RPWC",
	"RPBA",
	"RPCA",
	"RPDA",
	"RPM1",
	"RPM2",
	"RPM3",
	"SUCA",
	0
};
char*rfregs[] {
	"RFCS",
	"RFWC",
	"RFBA",
	"RFDA",
	"RFDAE",
	"RFDB",
	"RFMA",
	"RFADS",
	0
};
char *tmregs [] {
	"TMER",
	"TMCS",
	"TMBC",
	"TMBA",
	"TMDB",
	"TMRD",
	0
};
char *tcregs [] {
	"TCCSR",
	"TCCM",
	"TCWC",
	"TCBA",
	"TCDT",
	0
};
char *hpregs[] {
	"HPCS1",
	"HPWC",
	"HPBA",
	"HPDA",
	"HPCS2",
	"HPDS",
	"HPER1",
	"HPAS",
	"HPLA",
	"HPDB",
	"HPMR",
	"HPDT",
	"HPSN",
	"HPOF",
	"HPDC",
	"HPCC",
	"HPER2",
	"HPER3",
	"HPEC1",
	"HPEC2",
	"HPBAE",
	"HPCS3",
	0
};
char *htregs [] {
	"HTCS1",
	"HTWC",
	"HTBA",
	"HTFC",
	"HTCS2",
	"HTDS",
	"HTER",
	"HTAS",
	"HTCK",
	"HTDB",
	"HTMR",
	"HTDT",
	"HTSN",
	"HTTC",
	"HTBAE",
	"HTCS3",
	0
};
char *hsregs[] {
	"HSCS1",
	"HSWC",
	"HSBA",
	"HSDA",
	"HSCS2",
	"HSDS",
	"HSER",
	"HSAS",
	"HSLA",
	"HSDB",
	"HSMR",
	"HSDT",
	"HSBAE",
	"HSCS3",
	0
};
int rkblk();
int rpblk();
int rfblk();
int tmblk();
int tcblk();
int hpblk();
int htblk();
int hsblk();

/* Device specification functions */
/* Must remain in same order as true major device numbers */
int (*func[]) () {
	&rkblk,
	&rpblk,
	&rfblk,
	&tmblk,
	&tcblk,
	&hpblk,
	&htblk,
	&hsblk,
	0
};
int devregs[] {
	&rkregs,
	&rpregs,
	&rfregs,
	&tmregs,
	&tcregs,
	&hpregs,
	&htregs,
	&hsregs,
	0
};
char *ediag [] {
	"First Error",
	"First Retry",
	"Logging Terminated",
	0
};
struct pos {
	int flg;
	int unit;
	int cyl;
	int trk;
	int sector;
} pos;
char *msg[] {
	"User D Space Enabled",
	"Supervisor D Space Enabled",
	"Kernel D Space Enabled",
	"",
	"22 bit mapping Enabled",
	"UNIBUS MAP relocation Enabled",
	0
};
char *label[]  {
		"ERROR logged at",
		"Physical Device",
		"Logical Device",
		"Device Address",
		"Retry Count",
		"Error Diagnosis",
		"Registers at Error time",
		"Physical Buffer Start Address",
		"Transfer Size in Bytes",
		"Cylinder Requested",
		"Track Requested",
		"Sector Requested",
		"Type of Transfer",
		"Block No. in Logical File System",
		"Statistics on Device",
		"No. of R/W Operations to date",
		"No. of Other Operations",
		"No. of Unrecorded Errors",
		"Simultaneous Bus Activity",
		"I/O Type",
		0
};
int page 1;
int line;
int n 0;
int xflg;
int yflg;
int fout;


main (argc,argv)
char *argv[];
int argc;
{
	int i;
	char c;
	argc--;
	argv++;
	while (argc>1&&(**argv)=='-') {
		for (;(**argv);*++*argv)
		switch (**argv) {
		case 'x':
			xflg++;
			header = hd1;
			printf("Currently not implemented\n");
			break;
		case 'y':
			yflg++;
			header = hd2;
			printf("Currently not implemented\n");
			break;
		default:
			printf("%c?\n",**argv);
		}
	}
	fout = dup (1);
	if (argc ==0)
		report("/usr/adm/errfile");
	else while(argc--) 
		report(*argv++);
	flush ();
	exit(0);
}
report(fp)
char *fp;
{

	if((file = open(fp,0))<0) {
		printf("Cannot open %s\n",fp);
		return;
	}
	inithdng();
	puthead(header);
	putdata();
	putft();
	close (file);
	return;
}
putdata()
{
int m;

	while(m=read(file,&emsghd,sizeof(emsghd)) ==sizeof(emsghd)) {
		switch(emsghd.e_type) {
		
		case 010:
			getstart();
			break;

		case 011:
			getdown();
			break;

		case 012:
			getime();
			break;

		case 020:
		case 021:
		case 022:
			getblk();
			break;
		
		case 060:
			printf("CPU error\n");
			line++;
			break;

		case 040:
			printf("Character device error\n");
			line++;
			break;
		default:
			printf("Unrecognizable data\n");
			line++;
			flush();
			exit(8);
		}
	}

	return;
}
getdown()
{
	need(DNEED);
	printf("\nERROR LOGGING SYSTEM SHUTDOWN - %s\n\n\n",
			ctime(&emsghd.e_ctime));
}
getime()
{
int p;
	need(TNEED);
	printf("\n\n	********** TIME CHANGE ***** FROM %s",
			ctime(&emsghd.e_ctime));
	if(p=read(file,&etchg,sizeof(etchg))!=sizeof(etchg)) {
		need(ONE);
		printf("Time change record read error\n");
		return;
		}
	printf("\t\t\t\t      TO  %s \n\n\n\n",ctime(&etchg.e_ntime));
}
getblk()
{
register int i,j;
register char **p;

	pos.flg = 0;
	if(j=read(file,&eblock,sizeof(eblock))!=sizeof(eblock)) {
		need(ONE);
		printf("Block device entry record error\n");
		return;
	}
	if(eblock.d_major > araysz(func)) return;
	(*func[eblock.d_major])();
	col=0;

	need(ANEED);
	format(NSP,tab[1],"\n",tab[1],dev[eblock.d_major]);
	format(NF,tab[5],label[0],tab[3],"%s",ctime(&emsghd.e_ctime));
	format(NF,tab[1],label[1],tab[3],"%d",pos.unit);
	format(NF,tab[1],label[2],tab[3],"%d",eblock.d_minor);
	format(NF,tab[1],label[3],tab[3],"%o",eblock.e_rloc);
	printf("\n");
	format(NF,tab[1],label[4],tab[3],"%d",eblock.e_rtry);
	format(NF,tab[1],label[5],tab[3],"%s",ediag[emsghd.e_type&07]);
	format(NSP,tab[1],label[18],tab[3],"%s","");
	if(eblock.e_bacty == 0) printf("%s","None");
	else
	for(i=0;i<araysz(dev);i++) {
		if((eblock.e_bacty) & (1<<i))
		printf("%s   ",dev[i]);
		}
	format(NF,tab[2],"\n\n",tab[1],label[6],tab[0]);
	if(j=read(file,drvregs,eblock.e_nreg<<1)<=0) {
		printf("Register read error\n");
		flush();
		exit(8);
	}
	i=0;
	for(p=devregs[eblock.d_major];*p;p++) {
		need(ONE);
		format(PAD,tab[2],*p,tab[3],"%o",drvregs[i++]);
	}

	need(CNEED);
	format(NF,tab[1],label[7],tab[4],"%8O",eblock.eb_maddr);
	format(NF,tab[1],label[8],tab[4],"%8d",eblock.eb_wcnt*-2);
	format(NF,tab[1],label[12],tab[4],"%8s",
		eblock.eb_bflg&01?"READ":"WRITE");
	format(NF,tab[1],label[13],tab[4],"%8l",eblock.eb_bno);
	format(NF,tab[1],label[19],tab[4],"%8s",
		eblock.eb_bflg&020? "Physical":"Buffered");
	printf("\n");

	if(pos.flg) {
	need(BNEED);
	putchar('\n');
	format(NF,tab[1],label[9],tab[3],"%d",pos.cyl);
	if(pos.unit!=HS)
	format(NF,tab[1],label[10],tab[3],"%d",pos.trk);
	format(eblock.d_major,tab[1],
		label[11],tab[3],eblock.d_major==HS?"%d,%d":"%d",pos.sector);
	putchar('\n');
	}

	need(CNEED);
	putchar('\n');
	format(NF,tab[1],label[14],tab[0],"%s","");
	format(NF,tab[2],label[15],tab[4],"%11D",eblock.e_stat.io_ops);
	format(NF,tab[2],label[16],tab[4],"%11D",eblock.e_stat.io_misc);
	format(NF,tab[2],label[17],tab[4],"%11d",eblock.e_stat.io_unlog);
	putchar('\n');
	return;
}
getstart()
{
	register int i,j;

	need(SNEED);
	printf("\nERROR LOGGING SYSTEM STARTED - %s \n",ctime(&emsghd.e_ctime));
	if (j=read(file,&estart,sizeof(estart))!=sizeof(estart))  {
		need[ONE];
		printf("Error on estart record.\n");
		return;
		}
	printf("\n\nSystem Profile:\n\n");
	printf("     11/%d  Processor\n",estart.es_cpu);
	for(i=araysz(msg);i>=0;i--) {
			if(estart.es_mmr3 & (1<<i)){
			need(ONE);
			printf("\t %s \n",msg[i]);
			}
	}
	printf("\nConfigured with:   ");
	for (i=0; i<araysz(dev);i++) {
		if(estart.es_bconf & (1<<i))
			printf("%8s",dev[i]);
		}
	putchar ('\n');
}
rkblk()
{
	register int d,m;
	extern ldivr;

	pos.flg = 1;
	m = eblock.d_minor - 7;
	if(m<=0) {
		d = eblock.eb_bno;
		pos.unit = eblock.d_minor;
	}
	else {
		d = ldiv(0,eblock.eb_bno,m);
		pos.unit =  ldivr;
		}
	pos.cyl = d/24;
	d =% 24;
	pos.trk = d/12;
	pos.sector = d%12;
}
rpblk()
{
	extern ldivr;

	pos.flg=1;
	pos.unit = (eblock.d_minor>>3);
	pos.cyl=rpoffst[eblock.d_minor&07];
	pos.cyl =+ ldiv(0,eblock.eb_bno,10*20);
	pos.trk = ldiv(0,ldivr,10);
	pos.sector = ldivr;
}

rfblk()
{
	extern ldivr;

	pos.flg=1;
	pos.unit=ldiv(0,eblock.eb_bno,1024);
	pos.cyl=ldiv(0,ldivr,8);
	pos.trk=0;
	pos.sector=ldivr;
}
tmblk()
{
	pos.unit = (eblock.d_minor&03);
}
tcblk()
{
	pos.unit = (eblock.d_minor&07);
}
hpblk()
{
	extern ldivr;

	pos.flg = 1;
	pos.unit=(eblock.d_minor>>5)&0377;
	pos.cyl = hpoffst[eblock.d_minor&037];
	pos.cyl =+ ldiv(0,eblock.eb_bno,19*22);
	pos.trk = ldiv(0,ldivr,22);
	pos.sector=ldivr;
}
htblk()
{
	pos.unit=(eblock.d_minor&03);
}
hsblk()
{
	extern ldivr;

	pos.flg = 1;
	pos.trk=0;
	pos.unit=eblock.d_minor&07;
	pos.cyl = ldiv(0,eblock.eb_bno,eblock.d_minor&010?32:16);
	pos.sector = ldivr;
}
nextcol(nextab)		/* position to next tab */
int nextab;
{
	 int i,df;

	df = (nextab>>3) - (col>>3);
	if(df<0)  {
		df = (nextab>>3);
		col = 0;
		}
	for(i=0;i<df;i++) {
		putchar('\t');
		col = (col&(~07)) + 8;
	}

	df = nextab - col;
	for(i=0;i<df;i++) {
		putchar(' ');
		col++;
	}
}
format(ct,t1,s1,t2,s2,s3,s4)	/* print a formatted line of label and data */
int t1,t2,ct;
{
	nextcol(t1);
	printf(s1);
	col =+ count(s1);
	nextcol(t2);
	if(ct==PAD)  {
		n=0;
		pad(s3);
		}
	if(ct==NSP) 
		printf(s2,s3,s4);
	else {
		printf(s2,s3,s4);
		putchar('\n');
		col=0;
	}
}
count(x)		/* determine size of a character string */
	register char *x;
{
	register int c;
	
	for(c=0;(*x++);c++);
	return(c);
}
puthead(h)
char *h;
{
	printf("\n\n        %s     Prepared on %s     Page  %d\n\n\n\n",
		h,htime,page);
	line = 6;
}
inithdng()
{
struct inode sbuf;
char *p;
	fstat(file,&sbuf);
	p = ctime(sbuf.mtime);
	p[16] = '\0';
	strcpy(p+4,htime);
}
putft()
{
	while (line<=MAXLEN) {
		putchar('\n');
		line++;
		}
	page++;
}
trnpg()
{
	if( line >= MAXLEN) {

		page++;
		puthead(header);
		return;
		}
	putft();
	puthead(header);
	return;
}
need(a)			/* acts like ".ne" command of nroff */
int a;
{
	if( line>(PGLEN-a)) trnpg();
	line =+ a;
return;
}
pad(nm)			/* fill out an address with zeros */
int nm;
{
int i;

	if((i=(nm>>3))&&(n<6)) {
		n++;
		pad(i);
		}
	for(;n<5;n++)
	putchar('0');
	return;
}
strcpy(a,b)		/* copy a string */
	char *a,*b;
{
	while(*b++ = *a++);
}
