Ultrix-3.1/src/cmd/el/elp1.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

static char Sccsid[] = "@(#)elp1.c	3.0	4/21/86";
/*
 * ULTRIX-11 error log report program (elp) - PART 1
 * Fred Canter 3/16/83
 * Chung-Wu Lee 2/15/85  -  add tk50
 *
 * USAGE: elp [-h] [-s] [-f] [-b] [-r] [-u] [-d sd ed] [-et[#]] [file]
 *
 * The input for the report is taken from the current error
 * log on /dev/errlog or from [file].
 *
 * PART 1 is the main() of elp, which does the following:
 *
 * 1.	Prints the help message, if requested.
 *
 * 2.	Processes the argument list.
 *
 * 3.	Find the location and size of the error log and
 *	open it for reading.
 *
 * 4.	Calls the ersum() function (elp2.c) for the summary report.
 *
 * 5.	Calls the erfull() function (elp4.c) for the
 *	full report, unless only a summary was requested.
 *
 */

#include "elp.h"	/* must be first (param.h) */
#include <sys/errlog.h>
#include <sys/devmaj.h>
#include <sys/ra_info.h>
#include <a.out.h>
#include <stdio.h>

/*
 * System error log information,
 * obtained from unix via the errlog system call (EL_INFO).
 */
struct	el_data	el_data;
daddr_t	el_sb;		/* error log start block number */
int	el_nb;		/* error log length in blocks */
int	nblkdev;	/* maximum number of block devices */
int	nchrdev;	/* maximum number of character devices */


/* Name of error type, for selective */

char	etn[3];

/*
 * The el_info structure is used throughout elp,
 * it contains all data, or pointers to it, needed
 * to describe each type of error and is set up so that
 * if something like the order of the major device numbers
 * is changed, only a recompile of elp should be required.
 *
 * Not all error types use all of the info in el_data,
 * for pointers 0 denotes unused, and for all other data
 * types -1 indicates that they should be ignored.
 *
 */

struct el_info elc[] =
{
	"dummy",0,-1,0,0,-1,-1,0,0,0,-1,

	"su",		/* error type name */
	E_SU,		/* index to header message, et_head[] */
	-1,		/* index to device name, dntab[] */
	0,		/* pointer to device reg. control, ??_rbp */
	0,		/* pointer to device reg name text, ??_reg */
	-1,		/* BLOCK major device number */
	-1,		/* RAW major device number */
	0,		/* total error count */
	0,		/* pointer to hard error count */
	0,		/* pointer to soft error count */
	-1,		/* error retry count */

	"sd",E_SD,-1,0,0,-1,-1,0,0,0,-1,
	"tc",E_TC,-1,0,0,-1,-1,0,0,0,-1,
	"si",E_SI,-1,0,0,-1,-1,0,0,0,-1,
	"sv",E_SV,-1,0,0,-1,-1,0,0,0,-1,
	"mp",E_MP,-1,0,0,-1,-1,0,0,0,-1,

	"rk",E_BD,0,&rk_rbp,&rk_reg,RK_BMAJ,RK_RMAJ,0,&rk_hec,&rk_sec,10,
	"rp",E_BD,1,&rp_rbp,&rp_reg,RP_BMAJ,RP_RMAJ,0,&rp_hec,&rp_sec,10,
/* rx, rd, and rc get converted to ra ! */
	"ra",E_BD,2,&ra_rbp,&ra_reg,RA_BMAJ,RA_RMAJ,0,0,0,2,
	"rl",E_BD,3,&rl_rbp,&rl_reg,RL_BMAJ,RL_RMAJ,0,&rl_hec,&rl_sec,10,
/* rx changed to hx because of RX50 */
	"hx",E_BD,4,&rx_rbp,&rx_reg,HX_BMAJ,HX_RMAJ,0,&rx_hec,&rx_sec,10,
	"tm",E_BD,5,&tm_rbp,&tm_reg,TM_BMAJ,TM_RMAJ,0,&tm_hec,&tm_sec,9,
/* tc changed to dt because of time change */
	"tk",E_BD,6,&tk_rbp,&tk_reg,TK_BMAJ,TK_RMAJ,0,&tk_hec,&tk_sec,2,
	"ts",E_BD,7,&ts_rbp,&ts_reg,TS_BMAJ,TS_RMAJ,0,&ts_hec,&ts_sec,9,
	"ht",E_BD,8,&ht_rbp,&ht_reg,HT_BMAJ,HT_RMAJ,0,&ht_hec,&ht_sec,9,
/*
 * erp & ernp are zero for HP because it has three
 * drive types to contend with, RP RM ML.
 * The code in elp4.c checks the drive type register
 * and sets the correct values into erp & ernp.
 */
	"hp",E_BD,9,/*&hp_rbp*/ 0,/*&hp_reg*/ 0,HP_BMAJ,HP_RMAJ,0,&hp_hec,&hp_sec,28,
	"hm",E_BD,10,/*&hp_rbp*/ 0,/*&hp_reg*/ 0,HM_BMAJ,HM_RMAJ,0,&hm_hec,&hm_sec,28,
	"hj",E_BD,13,/*&hp_rbp*/ 0,/*&hp_reg*/ 0,HJ_BMAJ,HJ_RMAJ,0,&hj_hec,&hj_sec,28,
	"hk",E_BD,11,&hk_rbp,&hk_reg,HK_BMAJ,HK_RMAJ,0,&hk_hec,&hk_sec,28,
/*
 * The following are the character devices.
 * They are not real error types, these entries are
 * only used to map to the device name array dntab[].
 * Their values are changed dynamically.
 */
	"console",E_EOF,0,0,-1,-1,CO_RMAJ,0,0,0,-1,
	"pc",E_EOF,1,0,-1,-1,-1,0,0,0,-1,
	"lp",E_EOF,2,0,-1,-1,LP_RMAJ,0,0,0,-1,
	"dc",E_EOF,3,0,-1,-1,DC_RMAJ,0,0,0,-1,
	"dh",E_EOF,4,0,-1,-1,DH_RMAJ,0,0,0,-1,
	"dp",E_EOF,5,0,-1,-1,DP_RMAJ,0,0,0,-1,
	"uh",E_EOF,6,0,-1,-1,UH_RMAJ,0,0,0,-1,
	"dn",E_EOF,7,0,-1,-1,DN_RMAJ,0,0,0,-1,
	"dz",E_EOF,8,0,-1,-1,DZ_RMAJ,0,0,0,-1,
	"du",E_EOF,9,0,-1,-1,DU_RMAJ,0,0,0,-1,
	0
};

/*
 * This is the help message text.
 */

char	*help[] =
{
	"\n\n(elp) - ULTRIX-11 error log report generator.",
	"\nThis command formats and prints error reports based",
	"on the error data captured by the error logger.",
	"\nUsage:\n",
	"\telp [-h] [-s] [-f] [-b] [-r] [-u] [-d sd ed] [-et[#]] [file]",
	"\nelp\tWith no arguments,",
	"\ta summary of all errors is printed followed",
	"\tby a detailed report on each error.",
	"\n-h\tPrint this help message.",
	"\n-s\tPrint only the error summary report.",
	"\n-f\tPrint only the detailed error report.",
	"\n-b\tPrint only breif decsriptions of each error.",
	"\n-r\tFor block device errors, print only recovered errors.",
	"\n-u\tFor block device errors, print only unrecovered errors.",
	"\n-d\tPrint only the errors within the specified",
	"\tdate/time range.",
	"\n\t(sd) -\tStarting date/time (yymmddhhmmss).",
	"\t(ed) -\tEnding date/time (yymmddhhmmss).",
	"\n\tnote -\tAll digits must be present in date/time.",
	"\n-et[#]\tPrint only the error for the specified error type.",
	"\tOnly one error type may be specified.",
	"\t`#' - optional unit number for block device errors only.",
	"\nfile\tTake the input from the specified file",
	"\tinstead of the current error log.",
	0
};

/*
 * Error messages
 */

char	*errmsg[] =
{
	"arg count",
	"bad arg",
	"bad error type",
	"bad date limit",
	0,
};


char	sflag;	/* Summary report only */
char	fflag;	/* Full report, skip summary */
char	dflag;	/* Date selective option specified */
char	etflag;	/* Error type selective option specified */
char	fnflag;	/* Input is from specified file, not error log device */

char	*cbp;

int	et;
int	etdn = -1;
int	etct = -1;
int	etcn = -1;

int	timl[6];	/* sec		start date limit */
			/* min */
			/* hour */
			/* day */
			/* month */
			/* year */
int	timh[6];	/* sec		end date limit */
			/* min */
			/* hour */
			/* day */
			/* month */
			/* year */
int	elrtim[6];	/* sec		time from error log record */
			/* min */
			/* hour */
			/* day */
			/* month */
			/* year */

struct	nlist	nl[] =
{
	{ "_ra_ctid" },
	{ "" },
};
char	ra_ctid[MAXUDA];

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

	register int i, j;
	register char *p;
	char *filen;
	char *n;
	int mem, fi;

/*
 * Get the error log start block, length
 * and the number of block devices
 * from /unix kernel via the errlog system call.
 */
	errlog(EL_INFO, &el_data);
	el_sb = el_data.el_sb;
	el_nb = el_data.el_nb;
	nblkdev = el_data.nblkdev;
	if(nblkdev > MAXNBD)
		nblkdev = MAXNBD;

/*
 * Set up the character device name index
 */
	nchrdev = 0;
	for(i=(E_BD+nblkdev); elc[i].et; i++) {
		j = elc[i].edn + nblkdev;
		elc[i].edn = j;
		nchrdev++;
		}


	if(argc > 9)
		emsg(0);	/* arg count */
/*
 * Get initial idea of MSCP cntlr types
 * from current kernel ra_ctid[] table.
 * This is needed because to print unlogged errors
 * CDA passes error records to elp, but does not
 * pass any startup records. Without the startup records
 * elp can't tell how many and what type MSCP cntlrs there are.
 */
	nlist("/unix", nl);
	mem = open("/dev/mem", 0);
	if((mem >= 0) && (nl[0].n_value)) {
		lseek(mem, (long)nl[0].n_value, 0);
		read(mem, (char *)&ra_ctid, MAXUDA);
		for(i=0; i<MAXUDA; i++) {
			j = (ra_ctid[i] >> 4) & 017;
			ra_cid[i] = j;
			if(j == 017)
				ra_ctn[i] = "";
			else
				ra_ctn[i] = radntab[j];
		}
	}
	if(argc == 1)		/* no arguments */
		goto elp_go;
	for(i=1; i < argc; i++) {
		p = argv[i];
		if(*p != '-') {	/* arg is a filename */
			fnflag++;
			fi = i;
			continue;
			}
		*p++;			/* skip "-" in front of arg */
		if(strlen(p) > 4)
			emsg(1);	/* bad arg */
		if(strlen(p) >= 2) {	/* arg is an error type */
			etn[0] = *p++;	/* get error type name */
			etn[1] = *p++;
			etn[2] = 0;
			if(*p)
				etdn = atoi(p);	/* get unit number */
			if(etdn >= 64)
				emsg(1);	/* bad arg */
			/*
			 * If the requested error type is rd, rx, or rc
			 * change it to ra, but save the controller type
			 * ID as follows:
			 * ra=0, rc=1, rd=2, rx=3
			 * Can't set the real cntlr ID yet, because it is
			 * not known until after the first startup record
			 * is read in, see setrat().
			 */
			if(etn[0] == 'r') {
				switch(etn[1]) {
				case 'a':
					etct = 0;
					break;
				case 'c':
					etct = 1;
					break;
				case 'd':
					etct = 2;
					break;
				case 'x':
					etct = 3;
					break;
				default:
					etct = -1;
					break;
				}
				if(etct >= 0)
					etn[1] = 'a';
			}
			p = &etn;
			for(j=0; elc[j].et; j++)
				if(strcmp(p, elc[j].et) == 0) {
					et = j;
					etflag++;
					break;
					}
			if(!etflag)
				emsg(2);	/* bad error type */
			if(et < E_BD)
				etdn = -1;
			continue;
			}
		/* arg is a flag */

		if(*p == 'h') {	/* print the help message */
			for(j=0; help[j]; j++)
				printf("\n%s", help[j]);
			printf("\n\n\n");
			exit();
			}
		else if(*p == 's')
			sflag++;
		else if(*p == 'f')
			fflag++;
		else if(*p == 'r')
			rflag++;
		else if(*p == 'u')
			uflag++;
		else if(*p == 'b')
			bflag++;
		else if(*p == 'd') {
			dflag++;
		/* get start/end date from next 2 arg's */

		if((argc - i) < 3)	/* must be min of 2 arg's remaining */
			emsg(3);	/* bad date limit */
		cbp = argv[++i];	/* set up lo date limit */
		timl[5] = gtd();	/* year */
		timl[4] = gtd();	/* month */
		timl[3] = gtd();	/* day */
		timl[2] = gtd();	/* hour */
		timl[1] = gtd();	/* min */
		timl[0] = gtd();	/* sec */
		for(j=0;j<6;j++) {
			if(timl[j] < 0)
				emsg(3);	/* bad date limit */
			}
		timl[5] =+ 1900;	/* add 1900 to year */
		timl[4]--;		/* month - 1 */
		cbp = argv[++i];	/* set up end date limit */
		timh[5] = gtd();
		timh[4] = gtd();
		timh[3] = gtd();
		timh[2] = gtd();
		timh[1] = gtd();
		timh[0] = gtd();
		for(j=0;j<6;j++) {
			if(timh[j] < 0)
				emsg(3);	/* bad date limit */
			}
		timh[5] =+ 1900;
		timh[4]--;
		}
		else
			emsg(1);	/* bad arg */
	}

/*
 * Open the error log device or
 * the optional [file] for reading.
 */

elp_go:
	if(fnflag)
		filen = argv[fi];
	else
		filen = "/dev/errlog";
	if((fi = open(filen, R)) < 0) {
		fprintf(stderr, "\nelp: Can't open %s\n", filen);
		exit(1);
		}

/*
 * This is the mainline of the program.
 */

	ersum(fi, filen);
	if(!sflag)
		erfull(fi, filen);
	close(fi);
	printf("\n\n\n\n\n\n\n\n");
}

/*
 * Get 2 digits from arg & check them 
 */

gtd()
{
	register char c1, c2;
	register char *cp;

	cp = cbp;
	if(*cp == 0)
		return(-1);
	c1 = (*cp++ - '0') * 10;
	if(c1 < 0 || c1 > 100)
		return(-1);
	if(*cp == 0)
		return(-1);
	if((c2 = *cp++ - '0') < 0 || c2 > 9)
		return(-1);
	cbp = cp;
	return(c1 + c2);
}

/*
 * Print an error message and exit.
 */

emsg(m)
{
	fprintf(stderr,"\nelp: ");
	fprintf(stderr,"%s\n", errmsg[m]);
	fprintf(stderr,"\nUsage:");
fprintf(stderr,"\n\telp [-h] [-s] [-f] [-b] [-r] [-u] [-d sd ed] [-et[#]] [file]\n");
	fprintf(stderr,"\nType `elp -h' for help !\n");
	exit(1);
}