/*
 * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
 */
#include <lcrash.h>
#include <string.h>
#include <stdio.h>

char namelist[LCRASH_OPT_MAX];
char map[LCRASH_OPT_MAX];
char dump[LCRASH_OPT_MAX];
char outfile[LCRASH_OPT_MAX];
static char *M_val=0, *I_val=0;
char *program, *dumpdev, *dumpdir;
char ql_have_terminal;

FILE *ofp;
int bounds_flag = 0;                    /* bounds flag option                */
int report_flag = 0;                    /* report flag option                */
int save_flag = 0;                      /* save dump flag option             */
int erase_flag = 0;                      /* erase dump flag option             */
int progress_flag = 0;                  /* display progress flag option             */
int bounds = -1;                        /* bounds value with -n option       */
int lcrash_debug = 0;
uint64_t def_iter_threshold = 10000;   /* used when following pointers to */
uint64_t iter_threshold     = 10000;   /* avoid endless loops */

#ifdef ALLOC_DEBUG
extern int alloc_debug;
#endif

#if (ARCH == ia64)
void
*kl_get_ra(void)
{
	return(0);
}
#endif

void
usage(void)
{
	fprintf(stderr, "Usage: %s [-r] [-n bounds] [-H include path] [-M macro path] map dump kerntypes\n"
		"       %s [-r] [-H include path] [-M macro path] [-s <dumpdev> <dumpdir>]\n"
		"       %s [-e <dumpdev>]\n",
		program, program, program);
	exit(1);
}

/* 
 * main()
 */
int
main(int argc, char **argv)
{
	int i;
	int rl_init(char *, int, int);
	void rl_register_complete_func(rl_complete_func_t);

	program = argv[0];
	ofp = stdout;

	/* Grab all of the command line arguments.
	 */
	bzero(map, 256);
	bzero(dump, 256);
	bzero(namelist, 256);
	bzero(outfile, 256);
	for (i = 1; i < argc; i++) {
		if ((argv[i][0] == '-') && (strlen(argv[i]) == 1)) {
			usage();
		}
		switch (argv[i][0]) {
			case '-':
				switch (argv[i][1]) {
					case 'r':
						report_flag++;
						break;
					case 'P':
						progress_flag++;
						break;
					case 'd':
						if (i + 1 == argc) {
							usage();
						}
						i++;
						lcrash_debug = atoi(argv[i]);
						break;
					case 'n':
						if (i + 1 == argc) {
							usage();
						}
						i++;
						bounds = atoi(argv[i]);
						bounds_flag++;
						break;
					case 'M':
						if (i + 1 == argc) {
							usage();
						}
						i++;
						M_val=argv[i];
						break;
					case 'I':
						if (i + 1 == argc) {
							usage();
						}
						i++;
						I_val=argv[i];
						break;
					case 'o':
						if (i + 1 == argc) {
							usage();
						}
						i++;
						strncpy(outfile, argv[i],
							LCRASH_OPT_MAX);
						break;
					case 's':
						if (i + 2 >= argc) {
							usage();
						}
						if (argv[i+1][0] == '-') {
							usage();
						}
						if (argv[i+2][0] == '-') {
							usage();
						}
						save_flag++;
						dumpdev = argv[i+1];
						dumpdir = argv[i+2];
						i += 2;
						break;
					case 'e':
						if (i + 1 >= argc) {
							usage();
						}
						if (argv[i+1][0] == '-') {
							usage();
						}
						erase_flag++;
						dumpdev = argv[i+1];
						break;
					default:
						usage();
				}
				break;

			default:
				if (bounds_flag) {
					usage();
				}

				/* make sure we aren't going past the end */
				if (!map[0]) {
					sprintf(map, "%s", argv[i]);
				} else if (!dump[0]) {
					sprintf(dump, "%s", argv[i]);
				} else if (!namelist[0]) {
					sprintf(namelist, "%s", argv[i]);
				} else {
					usage();
				}
		}
	}

	/* make sure we have a proper outfile */
	if (outfile[0] == 0) {
		strcpy(outfile, "stdout");
	}

	if (bounds_flag) {
		if (bounds < 0) {
			fprintf(stderr,
				"Error: Argument for -n must be >= 0!\n");
			usage();
		}
		if (save_flag) {
			fprintf(stderr,
				"Error: -n and -s are invalid together!\n");
			usage();
		}
		if (erase_flag) {
			fprintf(stderr,
				"Error: -n and -e are invalid together!\n");
			usage();
		}
		sprintf(map, "map.%d", bounds);
		sprintf(dump, "dump.%d", bounds);
		sprintf(namelist, "kerntypes.%d", bounds);
	}

	if ((report_flag) && (save_flag)) {
		fprintf(stderr,
			"Error: -r and -s are invalid together!\n");
		usage();
	}
	if ((report_flag) && (erase_flag)) {
		fprintf(stderr,
			"Error: -r and -e are invalid together!\n");
		usage();
	}
	if ((save_flag) && (erase_flag)) {
		fprintf(stderr,
			"Error: -s and -e are invalid together!\n");
		usage();
	}

	if (save_flag) {
		if ((map[0] != 0) || (dump[0] != 0) || (namelist[0] != 0)) {
			fprintf(stderr,
				"Error: map, dump, and kerntypes should "
				"not be specified with -s!\n");
			usage();
		}

		/*
		 * Passing lcrash_debug (-d flag) down as local_debug so
		 * that the magic number in the dump header on the swap 
		 * partition  isn't zapped with deadbeef while we are debuging.
		 */
		exit(kl_dump_retrieve(dumpdev, dumpdir, progress_flag, lcrash_debug));
	}
	
	if (erase_flag) {
		exit(kl_dump_erase(dumpdev));
	}

	if ((!map[0]) && (!dump[0]) && (!namelist[0])) {
		strcpy(map, "/boot/System.map");
		strcpy(namelist, "/boot/Kerntypes");
		strcpy(dump, "/dev/mem");
	}

	if (!report_flag) {
		fprintf(ofp, "map = %s, dump = %s, outfile = %s", 
			map, dump, outfile);
		if (namelist[0]) {
			fprintf(ofp, ", kerntypes = %s\n", namelist);
		} else {
			fprintf(ofp, "\n");
		}
		fprintf(ofp, "\nPlease wait...");
		fflush(ofp);
	}

	/* Set up signal handler to handle SIGINT and to prevent lcrash
	 * from dumping core on SEGV and BUSERR signals.
	 */
	if(setjmp(klib_jbuf)){
		exit(1);
	}
	kl_sig_setup();

	kl_init_klib(map, dump, namelist, report_flag);
	if (KL_ERROR) {
		if (!report_flag) {
			fprintf(KL_ERRORFP, "\n");
		}
		if (KL_ERROR & (KLE_OPEN_ERROR|KLE_DUMP)) {
			fprintf(KL_ERRORFP, "%s: ", dump);
		} else if (KL_ERROR & 
			(KLE_OPEN_ERROR|KLE_MAP_FILE|KLE_BAD_MAP_FILE)) {
			fprintf(KL_ERRORFP, "%s: ", map);
		}
		kl_print_error();
		exit(1);
	}
	if (!STP) {
		exit(1);
	}
	init_liballoc(0, 0, 0);
	register_cmds(cmdset);
	arch_init(ofp);
	if (lcrash_debug) {
		/* XXX -- until we have debug classes, this lets us turn 
		 * the level of testing on and off.
		 */
#ifdef ALLOC_DEBUG
		alloc_debug = 1;
#endif
	}

	/* run the report here */
	if (report_flag) {
		do_report(0, ofp);
		exit(0);
	}
	
	/* check if we are connected to a terminal */
	if ((isatty(1) == 0) || (isatty(0) == 0)) {
		ql_have_terminal = 0;
	}
	else {
		ql_have_terminal = 1;
		/* initialise the rl functions */
		if(!rl_init(">> ", 0, 0)) {
			exit(1);
		}
		/* register sub-commands-line completion fuction */
		rl_register_complete_func(complete_cmds);
	}
	
	/* fire up sial interpreter and load macros */
	init_sial(M_val, I_val);
	
	process_cmds();
	free_temp_blocks();
	exit(0);
}

