Ultrix-3.1/src/cmd/olx/hxx1.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[] = "@(#)hxx1.c	3.0	4/22/86";
/*
 * ULTRIX-11 HX disk exerciser program (hxx).
 *
 * PART 1 - (hxx1.c)
 *
 *	Part 1 does the initial setup and argument processing,
 *	writes the results into a file `hxx_#.arg' (# = drive).
 *	and then calls part 2 of hxx, which is the actual exerciser.
 *	The program is split into two sections to optimize
 *	memory usage.
 *
 * Fred Canter 5/6/83
 * Bill Burns 4/84
 *
 *	********************************************
 *      *                                          *
 *      * This program will not function correctly *
 *      * unless the current unix monitor file is  *
 *      * named "unix".                            *
 *	*					   *
 *      ********************************************
 *
 * This program exercises the RX02 disk
 * via the unix block and raw I/O interfaces, at
 * the user level.
 * It reports the occurrence of hard errors and/or data
 * compare errors on the standard output.
 * The detailed device error information must be obtained
 * the system error log (elp -hx).
 *
 *
 * USAGE:
 *
 *	hxx -h
 *
 *		Print the help message.
 *
 *	hxx [-m#] [-d#] [-s#] [-i] [-n #] [-e #] [-z #]
 *
 *		Exercise the disk(s), using random addresses,
 *		random byte counts, and alternating worst case
 *		and random data patterns.
 *
 *	[-z #] - event flag bit position, used to start/stop
 *		exercisers
 *
 *	[-d#] -	Select the drive to be exercised.
 *		Only one drive may be selected.
 *
 *	[-s#] -	Specify time intervals for periodic I/O statistics printouts.
 *		The time interval (#) is in minutes and can range
 *		from 1 to 720 (12 hours).
 *		The default time interval is 1/2 hour.
 *		If no time interval is specified (-s only),
 *		the I/O statistics are not printed.
 *
 *	[-i]  -	Inhibit the file system status printouts.
 *
 *	[-n #] - Specify the number (#) of data mismatch errors
 *		to be printer per failing block.
 *		The maximum is 256 and the default is 5.
 *
 *	[-e #] - Drop the disk after # hard errors,
 *		 default = 100, maximum = 1000.
 *
 *	[-m#]  - mode select (1=RX01, 2=RX02, default is both).
 *
 *	Below is gone due to event flag usage:
 *	[-r kfn] - kill filename
 *
 *	note  -	The root, swap, error log, and any mounted file
 *		systems are automatically write protected.
 *		The RX02 cannot be anything but mounted !
 *
 * EXAMPLE:
 *		hxx -d1
 *
 *		Exercise drive one.
 *
 *
 */

#include <sys/param.h>	/* Don't matter which one ! */
#include <sys/devmaj.h>
#include <sys/mount.h>
#include <stdio.h>
#include <a.out.h>
#include <signal.h>
#include <sgtty.h>

/*
 * Structure for accessing symbols in the unix kernel
 * via the nlist subroutine and the /dev/mem driver.
 */

struct nlist nl[] =
{
	{ "_rootdev" },
	{ "_swapdev" },
	{ "_swplo" },
	{ "_nswap" },
	{ "_el_dev" },
	{ "_el_sb" },
	{ "_el_nb" },
	{ "_cputype" },
	{ "_nmount" },
	{ "_usermem" },
	{ "_nhx" },
	{ "_mount" },
	{ "ova" },
	{ "" },
};

/*
 * The following are the symbols who's values are obtained
 * from the unix kernel.
 * THE ORDER MUST NOT BE CHANGED !
 */

int	rootdev;
int	swapdev;
int	swplo;
int	nswap;
int	el_dev;
int	el_sb;
int	el_nb;
int	cputype;
int	nmount;
int	usermem;

/*
 * Text array used by the print file
 * system read only status code.
 */

char	*fsutab[] =
{
	"dummy",
	"root device",
	"swap device",
	"error log device",
	"mounted file system",
	0
};

/*
 * Unit number.
 */

int	dn = -1;

/*
 * Drive types,
 * 0 = NED
 * 1 = RX02
 */
#define	RX02	1
#define RX1	1
#define RX2	2
#define SDEN	0
#define DDEN	2

char	hx_dt[2] = { 1, 1 };

/*
 * drive can be opened flag.
 */

int	hx_opn;

/*
 * File system write read status.
 * zero for write/read access
 * non zero for read only access
 */

int	fswrs;

/*
 * block and raw I/O file name.
 */

char	fn[20];

/*
 * Armument file name
 */

char	afn[] = "hxx_0.arg";

/*
 * Help message.
 */

char *help[]
{
	"\n\n(hxx) - ULTRIX-11 RX02 disk exerciser.",
	"\nUsage:\n",
	"\thxx [-h] [-m#] [-d#] [-s#] [-i] [-n #] [-e #]",
	"\n-h\tPrint this help message",
	"\n-m#\tMode select (1=RX01, 2=RX02, default is both)",
	"\n-d#\tSelect drive number `#' ",
	"\n-s#\tPrint I/O statistics every `#' minutes (default = 30 minutes)",
	"\n-s\tInhibit I/O statistics printout",
	"\n-i\tInhibit file system write/read status printout",
	"\n-n #\tLimit number of data compare error printouts to `#'",
	"\n-e #\tDrop the disk after # errors, default = 100, maximum = 1000",
	"\n\n",
	0
};

/*
 * Time buffers.
 */

int	istime = 30;

char	argbuf[512];

int	sflag, iflag;
int	ndep = 5;
int	ndrop = 100;
int	mflag;

#ifdef EFLG
char	*efbit;
char	*efids;
int	zflag;
#else
char	*killfn = "hxx.kill";
#endif

int	errno;
int	sys_nerr;
char	*sys_errlist[];

main(argc, argv)
char *argv[];
int argc;
{
	int	stop(), intr();
	register struct mount *mtp;
	register char *p;
	register int i;
	int *ap;
	int j, k;
	int fd;
	char *n;
	char *mp;
	int mem;
	int	bufsiz;
	int	bcmask;

	setpgrp(0, 31111);
	signal(SIGTTOU, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
	signal(SIGQUIT, stop);
	if(argc < 2)
		goto aderr;
	for(i=1; i < argc; i++) {	/* decode arg's */
		p = argv[i];
		if(*p++ != '-') {
		aderr:
			fprintf(stderr,"\nhxx: bad arg\n");
			exit(1);
			}
		switch(*p) {
		case 'h':	/* print help message */
			for(j=0; help[j]; j++)
				fprintf(stderr,"\n%s",help[j]);
			exit();
		case 'm':	/* mode select */
			p++;
			if((*p != '1') && (*p != '2'))
				goto aderr;
			mflag = *p - '0';
			break;
#ifdef EFLG
		case 'z':
			zflag++;
			i++;
			efbit = argv[i++];
			efids = argv[i];
			break;
#else
		case 'r':	/* kill filename */
			i++;
			killfn = argv[i];
			break;
#endif
		case 'd':	/* select drive */
			p++;
			if(*p < '0' || *p > '7')
				goto aderr;
			dn = *p - '0';
			afn[4] = *p;	/* argument file name */
			break;
		case 'n':	/* # of data errors to print */
			i++;
			ndep = atoi(argv[i]);
			if((ndep <= 0) || (ndep > 256))
				ndep = 5;
			break;
		case 'e':	/* drop disk after # errors */
			i++;
			ndrop = atoi(argv[i]);
			if((ndrop <= 0) || (ndrop > 1000))
				ndrop = 100;
			break;
		case 'i':	/* Inhibit file system status printouts */
			iflag++;
			break;
		case 's':
			sflag++;
			p++;
			if(*p < '0' || *p >'9')
				break;
			sflag = 0;
			istime = atoi(p);
			if(istime <= 0)
				istime = 30;
			if(istime > 720)
				istime = 720;
			break;
		default:	/* bad argument */
			goto aderr;
		}
	}
	if(!zflag) {
		if(isatty(2)) {
			fprintf(stderr, "hxx: detaching... type \"sysxstop\" to stop\n");
			fflush(stderr);
		}
		if((i = fork()) == -1) {
			printf("hxx: Can't fork new copy !\n");
			exit(1);
		}
		if(i != 0)
			exit(0);
	}
	setpgrp(0, 31111);
/*
 * Check for invalid option combinatons & defaults.
 */

	if(dn < 0) {
		fprintf(stderr, "\nhxx: must select drive\n");
		exit(1);
		}

/*
 * Attempt to open the selected drive,
 * if successful attempt to read first block on the drive.
 * Must format the drive first to insure correct density.
 * This should not cause any errors to be logged.
 */

	if(mflag == 1)
		rxfmt(SDEN);
	else
		rxfmt(DDEN);
	if(mflag == 1)
		i = 0;
	else
		i = 2;
	sprintf(&fn, "/dev/hx%o", dn+i);		/* file name */
	if((fd = open(fn, 0)) >= 0)
		if(read(fd, (char *) &argbuf, 512) == 512)
			hx_opn++;
	close(fd);

/*
 * Use the nlist subroutine & /dev/mem to set the values
 * to obtain needed data from the unix kernel.
 */

	nlist("/unix", nl);
	for(i=0; i<12; i++) {
		if(i == 10)	/* don't check nhx */
			continue;
		if(nl[i].n_type == 0) {
		      fprintf(stderr,"\nhxx: Can't access namelist in /unix\n");
			exit(1);
			}
		}
	if(nl[10].n_type == 0) {
		fprintf(stderr, "\nhxx: /unix not configured for RX02\n");
		exit(1);
		}
	if((mem = open("/dev/mem", 0)) < 0) {
		fprintf(stderr,"\nhxx: Can't open /dev/mem\n");
		exit(1);
		}
	mp = &rootdev;
	for(i=0; i<10; i++) {
		lseek(mem, (long)nl[i].n_value, 0);
		read(mem, (char *)mp, sizeof(int));
		mp += sizeof(int);
		}
/*
 * Set the write and read buffer sizes
 * and transfer size limits, based on
 * the amount of user memory.
 */
	if(usermem >= 4096) {	/* 256 kb */
		bufsiz = 8192;
		bcmask = 037776;
	} else {
		bufsiz = 4096;
		bcmask = 017776;
		}
/*
 * Print the status of drive.
 */

	j = 0;
	printf("\nUnit %d - ", dn);
	if(hx_dt[dn] == RX02)
		printf("RX02 - ");
	if(hx_dt[dn] && hx_opn) {
		printf("accessible");
		j++;
	} else if(hx_dt[dn] && !hx_opn)
		printf("not accesible");
	else
		printf("non existent\n\n");
	if(j == 0)
		exit(1);

/*
 * Initialize the file system write/read status.
 * Mark the drive read only if it is the root, swap,
 * error log device or is mounted.
 */

	/*
	 * Read the mount table from /unix.
	 *
	 * New stuff - mount table is now consistent between
	 * kernels (ov and sep I&D)  -  Bill Burns 8/13/84
	 */
	mtp = nl[12].n_value;
	lseek(mem, (long)mtp, 0);
	for(i=0; i<nmount; i++, mtp++) {
		p = &argbuf;
		p += (sizeof(struct mount) * i);
		read(mem, (char *)p, sizeof(struct mount));
	}
	close(mem);
	fswrs = cfs(dn);	/* check file system status */
	if(fswrs == 0)		/* root, swap, error log ? */
	{			/* no, check if mounted */
		i = (HX_BMAJ << 8) | dn;	/* maj/min device */
		k = (HX_BMAJ << 8) | (dn+2);
		for(mtp = &argbuf, j=0; j<nmount; mtp++, j++)
			if((mtp->m_bufp != NULL ) &&
			    ((mtp->m_dev==i) || (mtp->m_dev==k))) {
				fswrs = 4;	/* file system mounted */
				break;
				}
	}
/*
 * Unless the iflag is set, print the list
 * of read only file systems.
 */
	if(!iflag && fswrs)
	{
		if(hx_dt[dn] == RX02)
			printf("\nRX02");
		printf(" unit %d is read only - %s\n", dn, fsutab[fswrs]);
	}
/*
 * Write needed date into a file `hxx_#.arg' (# = drive),
 * and call part 2 of the HX exerciser (hxxr).
 */

	ap = &argbuf;
	*ap++ = dn;
	*ap++ = ndep;
	*ap++ = ndrop;
	*ap++ = sflag;
	*ap++ = istime;
	*ap++ = bufsiz;
	*ap++ = bcmask;
	*ap++ = fswrs;
	*ap++ = mflag;
#ifdef EFLG
	*ap++ = zflag;
#endif
	p = ap;
	n = &hx_dt;
	for(i=0; i<sizeof(hx_dt); i++)
		*p++ = *n++;
	if((fd = creat(afn, 0644)) < 0) {
		fprintf(stderr, "\nhxx: Can't create %s file\n", afn);
		exit(1);
		}
	if(write(fd, (char *)&argbuf, 512) != 512) {
		fprintf(stderr, "\nhxx: %s write error\n", afn);
		exit(1);
		}
	close(fd);
	fflush(stdout);
	signal(SIGQUIT, SIG_IGN);
#ifdef EFLG
	if(zflag)
		execl("hxxr", "hxxr", afn, efbit, efids, (char *)0);
	else
		execl("hxxr", "hxxr", afn, (char *)0);
#else
	execl("hxxr", "hxxr", afn, killfn, (char *)0);
#endif
	fprintf(stderr, "\nhxx: Can't exec hxxr\n");
	exit(1);
}

/*
 * Check file system and return 0 if it is writable,
 * otherwise return 1 if it is the root file system,
 * 2 if it is the swap file system, and 3 if it
 * is the error log file system.
 */

cfs(dev)
{

	register int rm, sm, em;

	rm = (rootdev >> 8) & 0377;
	sm = (swapdev >> 8) & 0377;
	em = (el_dev >> 8) & 0377;
	if((rm == HX_BMAJ) && (dev == (rootdev & 0377)))
		return(1);
	if((sm == HX_BMAJ) && (dev == (swapdev & 0377)))
		return(2);
	if((em == HX_RMAJ) && (dev == (el_dev & 0377)))
		return(3);
	return(0);
}

stop()
{
	exit(0);
}
/*
 * Format RX02 diskette
 * den = 2 for double, 0 for single density
 */

struct sgttyb sgttyb = 010;


rxfmt(den)
{
	register int i, j;

	sprintf(&fn, "/dev/rhx%d", dn+den);
	i = open(&fn, 2);
	if(i < 0) {
		fprintf(stderr, "\nhxx: Can't open %s\n", fn);
		exit(1);
	}
	j = ioctl(i, TIOCSETP, &sgttyb);
	if(j != 0) {
		fprintf(stderr, "\nFormat of %s FAILED", fn);
		if(errno < sys_nerr)
			fprintf(stderr, ": %s\n", sys_errlist[errno]);
		else
			fprintf(stderr, "Unknown error\n");
		exit(1);
	}
	close(i);
}