1
0
Files
2022-09-29 17:59:04 +03:00

550 lines
12 KiB
C

#ident "$Header: "
#include <stdio.h>
#include <sys/types.h>
#include <klib/klib.h>
#include "icrash.h"
/* Global variables
*/
static FILE *errorfp = stderr; /* error outfile used during startup */
FILE *ofp; /* icrash output file */
char namelist[BUFSIZ]; /* name list (normally /unix) */
char corefile[BUFSIZ]; /* core file (live = /dev/mem) */
char indexname[BUFSIZ]; /* name of index file */
char outfile[256] = "stdout"; /* name of global output file */
char icrashdef[256] = ""; /* name of file containing icrashdef */
char fromfile[256]; /* name of global command file */
char execute_cmd[256]; /* name of command to execute */
char *program; /* program name (argv[0]) */
int prog; /* program type (icrash or fru) */
int bounds_flag = 0; /* bounds flag option */
int pager_flag = 0; /* turns on use of page with output */
int write_flag = 0; /* write option flag */
int full_flag = 0; /* full option flag */
int force_flag = 0; /* force FRU analysis flag */
int all_flag = 0; /* all option flag (error dumpbuf) */
int err_flag = 0; /* error flag */
int report_flag = 0; /* Generate report output */
int report_level = 0; /* Determines level of report output */
int availmon = 0; /* availability report flag */
char availmonfile[256] = "stdout"; /* name of availmon output file */
int cleardump = 0; /* flag to clear dump */
int bounds = -1; /* bounds value with -n option */
int version = 0; /* flag to print version number */
int ignoreos = 0; /* ignore OS level in utsname struct */
int writeflag = 0; /* flag to determine if writing out */
int icrashdef_flag = 0; /* flag to read in icrashdef info */
int fromflag = 0; /* flag to specify from commands */
int execute_flag = 0; /* next arg is a command to execute */
int suppress_flag = 0; /* suppress opening text */
/*
* usage()
*/
void
usage()
{
if (prog == FRU_PROGRAM) {
fprintf(errorfp, "Usage: %s [-a] [-n bounds ] namelist corefile\n",
program);
}
else {
fprintf(errorfp,
"Usage: %s: [-f cmdfile] [-r] [-v] [-w outfile] [-n bounds] "
"[-e cnd] [-S] namelist corefile\n", program);
}
}
/*
* bad_option()
*/
void
bad_option(char *p, char c)
{
fprintf(errorfp, "%s: invalid command line option -- %c\n", p, c);
}
/*
* main()
*/
main(int argc, char **argv)
{
int i, c, errflg = 0;
command_t cb;
/* getopt() variables.
*/
extern char *optarg;
extern int optind;
extern int opterr;
/* Set opterr to zero to suppress getopt() error messages
*/
opterr = 0;
/* Initialize a few default variables.
*/
indexname[0] = '\0';
sprintf(corefile, "/dev/mem");
sprintf(namelist, "/unix");
/* Get the name of the program (e.g., "icrash" or "fru")
*/
if (program = strstr(argv[0], "icrash")) {
prog = ICRASH_PROGRAM;
}
else if (program = strstr(argv[0], "fru")) {
prog = FRU_PROGRAM;
}
else {
/* For now, if we don't know if the program is icrash or fru,
* assume it is icrash.
*/
program = argv[0];
prog = ICRASH_PROGRAM;
}
/* Grab all of the command line arguments.
*/
while ((c = getopt(argc, argv, "n:f:w:r:ca:vd:ie:I:S")) != -1) {
switch (c) {
case '?':
/* If there was an error in an argument, see if it is a
* situation that can be worked around. Or, check to see
* if it is an argument with a different meaning for icrash
* and fru.
*/
switch (optopt) {
case 'd':
/* If no debug level was specified, then set it
* equal to one (1).
*/
klib_debug = 1;
break;
case 'f':
if (prog == FRU_PROGRAM) {
full_flag++;
}
else {
fprintf(errorfp, "icrash: No from file was "
"specified\n");
errflg++;
}
break;
case 'a':
if (prog == FRU_PROGRAM) {
all_flag++;
}
else {
fprintf(errorfp, "icrash: Availmon file not "
"specified\n");
errflg++;
}
break;
case 'r':
if (prog == FRU_PROGRAM) {
bad_option(program, optopt);
errflg++;
break;
}
/* If report level wasn't specified, just break. It
* is set to one by default.
*/
break;
default:
bad_option(program, optopt);
errflg++;
break;
}
break;
case 'a':
/* Availability information
*
* This option has to be used in conjunction with
* the -r option, and should normally specify the
* file location.
*
* If the program is fru, then set all_flag if -a
* is included on the command line. If the program
* is icrash, then it's an error.
*/
if (((char*)optarg)[0] == '-') {
if (prog == FRU_PROGRAM) {
all_flag++;
optind--;
}
else {
fprintf(errorfp, "icrash: Availmon file not "
"specified\n");
errflg++;
}
}
else {
sprintf(availmonfile, "%s", optarg);
availmon++;
}
break;
case 'c':
/* Clear dump out. This only works in specific cases.
*/
if (prog == FRU_PROGRAM) {
bad_option(program, c);
errflg++;
}
else {
cleardump++;
}
break;
case 'd':
/* This is a non-documented command line option. It
* provides a way to set the internal debug message level.
* If no value has been included on the command line, then
* set debug equal to one (1).
*
* Note that there is no easy way to tell if the next
* argument is actually a valid debug level (except
* when the next argument starts with a '-,' which
* would be the case when it is the next command line
* option. If atoi returns a value less than zero, the
* assume it's not a valid level and set debug equal
* to one (1).
*/
if (((char*)optarg)[0] == '-') {
klib_debug = 1;
optind--;
}
else {
klib_debug = strtoull(optarg, (char **)NULL, 0);
if (klib_debug < 1) {
klib_debug = 1;
optind--;
}
}
break;
case 'f':
if (((char*)optarg)[0] == '-') {
if (prog == FRU_PROGRAM) {
full_flag++;
optind--;
}
else {
fprintf(errorfp, "icrash: From file was not "
"specified\n");
errflg++;
}
}
else {
if (prog == FRU_PROGRAM) {
bad_option(program, c);
errflg++;
}
else {
sprintf(fromfile, "%s", optarg);
fromflag++;
}
}
break;
case 'i':
/* Ingore OS flag (undocumented)
*/
ignoreos++;
break;
case 'n':
/* unix/vmcore file extentison
*/
if (((char*)optarg)[0] == '-') {
fprintf(errorfp, "%s: Bounds was not specified\n", program);
errflg++;
}
else {
bounds = atoi(optarg);
bounds_flag++;
}
break;
case 'r':
/* If a report level isn't specified, it defaults to 1.
*/
if (prog == FRU_PROGRAM) {
bad_option(program, c);
errflg++;
}
else {
if (((char*)optarg)[0] == '-') {
report_level = 0;
report_flag++;
optind--;
}
else {
report_level = atoi(optarg);
if (report_level < 1) {
report_level = 1;
optind--;
}
report_flag++;
}
}
break;
case 'e':
if (prog == FRU_PROGRAM) {
bad_option(program, c);
errflg++;
}
else {
sprintf(execute_cmd, "%s", optarg);
execute_flag++;
}
break;
case 'v':
/* Version information
*/
version++;
break;
case 'w':
/* Set the output file
*/
if (((char*)optarg)[0] == '-') {
fprintf(errorfp,
"%s: Outfile was not specified\n", program);
errflg++;
}
else {
sprintf(outfile, "%s", optarg);
writeflag++;
}
break;
case 'I':
/* Set the icrashdef file (undocumented)
*/
if (((char*)optarg)[0] == '-') {
fprintf(errorfp,
"%s: icrashdef file was not specified\n", program);
errflg++;
}
else {
sprintf(icrashdef, "%s", optarg);
icrashdef_flag++;
}
break;
case 'S':
suppress_flag++;
break;
default:
bad_option(program, c);
errflg++;
break;
}
/* Check to see if there was an error.
*/
if (errflg) {
usage();
exit(1);
}
}
if (!bounds_flag) {
if (optind < argc) {
if ((argc - optind) > 1) {
strcpy(namelist, argv[optind]);
strcpy(corefile, argv[optind+1]);
}
else {
fprintf(errorfp,
"Need to specify both namelist and corefile!\n");
errflg++;
}
}
}
else if (bounds >= 0) {
sprintf(namelist, "unix.%d", bounds);
sprintf(corefile, "vmcore.%d.comp", bounds);
}
else {
fprintf(errorfp,
"Bounds value for -n option needs to be >= 0!\n");
errflg++;
}
if (errflg) {
usage();
exit(1);
}
if ((availmon) && (!report_flag)) {
/*
* Cannot use fatal here.. because KL_ERRORFP
* is not yet defined.
*/
fprintf(errorfp,"You must use the -r option with the -a option.\n");
exit(1);
}
/* If we are trying to clear a vmcore image, we have to make sure
* that /unix and /dev/swap are being used, otherwise, it is an
* error. Yea, yea, it's ugly, but we have to do this because the
* savecore script that runs on boot-up has no other way to clear
* a core dump when 'icrash' fails initially even though there might
* be a dump in /dev/swap to begin with.
*/
if ((cleardump) && (!strcmp(namelist, "/unix")) &&
(!strcmp(corefile, "/dev/swap"))) {
clear_dump();
exit(0);
}
else if (cleardump) {
fprintf(errorfp,
"icrash: the -c option is only valid with /unix and /dev/swap!\n");
exit(1);
}
if (version) {
#ifdef VERSION
fprintf(errorfp, "IRIX Crash, Version %s\n", VERSION);
#else
fprintf(errorfp, "IRIX Crash, Version (Special)\n");
#endif
exit(0);
}
if (writeflag) {
if (!(ofp = fopen(outfile, "a"))) {
fprintf(errorfp, "Cannot open file %s. ", outfile);
fprintf(errorfp, "Output going to stdout.\n");
strcpy(outfile, "stdout");
ofp = stdout;
writeflag = 0;
}
}
else {
ofp = stdout;
writeflag = 0;
}
if ((prog == ICRASH_PROGRAM) && !report_flag && !suppress_flag) {
fprintf(ofp, "corefile = %s, namelist = %s, outfile = %s\n",
corefile, namelist, outfile);
fprintf(ofp, "\nPlease wait...");
if (klib_debug) {
fprintf(ofp, "\n");
}
}
if (init(ofp)) {
exit(1);
}
/* Set up signal handler for SEGV and BUSERR signals so that icrash
* doesn't dump core.
*/
kl_sig_setup();
/* If the program name is "fru," then run the FRU Analyzer. If the
* program name is "icrash," and a report has been requested, dump
* out the information from the core dump. Otherwise, start processing
* commands.
*/
if (prog == FRU_PROGRAM) {
/* XXX -- the fru code isn't working yet!
*/
fprintf(errorfp, "FRU not supported at this time\n");
exit(1);
#ifdef XXX
dofru((full_flag ? C_FULL : 0), ofp);
fflush(ofp);
if (all_flag) {
kl_print_errorbuf(ofp);
fflush(ofp);
}
if (write_flag) {
fclose(ofp);
}
exit(0);
#endif
}
else if (execute_flag) {
command_t cb;
char *t;
char *lasts = (char*)NULL;
#define _SGI_REENTRANT_FUNCTIONS
t = strtok_r(execute_cmd, ";", &lasts);
while (t) {
t += strspn(t, " ");
get_cmd(&cb, t);
if (writeflag) {
cb.ofp = ofp;
}
else {
cb.ofp = stdout;
}
if (!suppress_flag) {
fprintf(ofp, "\n>> %s\n", t);
}
checkrun_cmd(cb, ofp);
t = strtok_r((char*)NULL, ";", &lasts);
}
#undef _SGI_REENTRANT_FUNCTIONS
if (writeflag) {
exit(fclose(ofp));
}
exit(0);
}
else if ((report_flag) || (fromflag)) {
command_t cb;
/* Make sure the command buffer is all NULL before we start
*/
bzero(&cb, sizeof(command_t));
/* The following allows the report_cmd() function to be called
* just like any other command function. This approach is
* likely to change after the command interface gets reworked.
*/
get_cmd(&cb, "report");
if (writeflag) {
cb.ofp = ofp;
}
else {
cb.ofp = stdout;
}
report_cmd(cb);
if (writeflag) {
exit(fclose(ofp));
}
exit(0);
}
else {
process_commands(ofp);
}
exit(0);
}