Ultrix-3.1/src/cmd/el/elp1.c
/**********************************************************************
* 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);
}