Ultrix-3.1/src/cmd/olx/rkx1.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[] = "@(#)rkx1.c	3.0	4/22/86";
/*
 * ULTRIX-11 RK disk exerciser program (rkx).
 *
 * PART 1 - (rkx1.c)
 *
 *	Part 1 does the initial setup and argument processing,
 *	writes the results into a file `rkx_#.arg' (# = drive).
 *	and then calls part 2 of rkx, which is the actual exerciser.
 *	The program is split into two sections to optimize
 *	memory usage.
 *
 * Fred Canter 3/2/83
 * Bill Burns 4/84
 *
 *	********************************************
 *      *                                          *
 *      * This program will not function correctly *
 *      * unless the current unix monitor file is  *
 *      * named "unix".                            *
 *	*					   *
 *      ********************************************
 *
 * This program exercises the RK05 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 -rk).
 *
 *
 * USAGE:
 *
 *	rkx -h
 *
 *		Print the help message.
 *
 *	rkx [-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.
 *
 *
 *	note  -	The root, swap, error log, and any mounted file
 *		systems are automatically write protected.
 *
 * EXAMPLE:
 *		rkx -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>

/*
 * 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" },
	{ "_rk_dt" },
	{ "_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 = RK05
 */
#define	RK05	1

char	rk_dt[8];

/*
 * drive can be opened flag.
 */

int	rk_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[] = "rkx_0.arg";

/*
 * Help message.
 */

char *help[]
{
	"\n\n(rkx) - ULTRIX-11 RK05 disk exerciser.",
	"\nUsage:\n",
	"\trkx [-h] [-d#] [-s#] [-i] [-n #] [-e #]",
	"\n-h\tPrint this help message",
	"\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;

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

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,"\nrkx: 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();
#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,"rkx: detaching... type \"sysxstop\" to stop\n");
			fflush(stderr);
		}
		if((i = fork()) == -1) {
			printf("rkx: 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, "\nrkx: must select drive\n");
		exit(1);
		}

/*
 * Attempt to open the selected drive,
 * if successful attempt to read first block on the drive.
 * This is done in order to force the disk driver to update
 * the rk_dt[] array with the drive type of each available unit.
 * This should not cause any errors to be logged.
 */

	sprintf(&fn, "/dev/rk%o", dn);		/* file name */
	if((fd = open(fn, 0)) >= 0)
		if(read(fd, (char *) &argbuf, 512) == 512)
			rk_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 drive type */
			continue;
		if(nl[i].n_type == 0) {
		      fprintf(stderr,"\nrkx: Can't access namelist in /unix\n");
			exit(1);
			}
		}
	if(nl[10].n_type == 0) {
		fprintf(stderr, "\nrkx: /unix not configured for RK05\n");
		exit(1);
		}
	if((mem = open("/dev/mem", 0)) < 0) {
		fprintf(stderr,"\nrkx: 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);
		}
/*
 * Get the drive types.
 */

	lseek(mem, (long)nl[10].n_value, 0);
	read(mem, (char *)&rk_dt, sizeof(rk_dt));
/*
 * 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(rk_dt[dn] == RK05)
		printf("RK05 - ");
	if(rk_dt[dn] && rk_opn) {
		printf("accessible");
		j++;
	} else if(rk_dt[dn] && !rk_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 = (RK_BMAJ << 8) | dn;	/* maj/min device */
		for(mtp = &argbuf, j=0; j<nmount; mtp++, j++)
			if((mtp->m_bufp != NULL) && (mtp->m_dev == i)) {
				fswrs = 4;	/* file system mounted */
				break;
				}
	}
/*
 * Unless the iflag is set, print the list
 * of read only file systems.
 */
	if(!iflag && fswrs)
	{
		if(rk_dt[dn] == RK05)
			printf("\nRK05");
		printf(" unit %d is read only - %s\n", dn, fsutab[fswrs]);
	}
/*
 * Write needed date into a file `rkx_#.arg' (# = drive),
 * and call part 2 of the RK exerciser (rkxr).
 */

	ap = &argbuf;
	*ap++ = dn;
	*ap++ = ndep;
	*ap++ = ndrop;
	*ap++ = sflag;
	*ap++ = istime;
	*ap++ = bufsiz;
	*ap++ = bcmask;
	*ap++ = fswrs;
#ifdef EFLG
	*ap++ = zflag;
#endif
	p = ap;
	n = &rk_dt;
	for(i=0; i<sizeof(rk_dt); i++)
		*p++ = *n++;
	if((fd = creat(afn, 0644)) < 0) {
		fprintf(stderr, "\nrkx: Can't create %s file\n", afn);
		exit(1);
		}
	if(write(fd, (char *)&argbuf, 512) != 512) {
		fprintf(stderr, "\nrkx: %s write error\n", afn);
		exit(1);
		}
	close(fd);
	fflush(stdout);
	signal(SIGQUIT, SIG_IGN);
#ifdef EFLG
	if(zflag)
		execl("rkxr", "rkxr", afn, efbit, efids, (char *)0);
	else
		execl("rkxr", "rkxr", afn, (char *)0);
#else
	execl("rkxr", "rkxr", afn, killfn, (char *)0);
#endif
	fprintf(stderr, "\nrkx: Can't exec rkxr\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 == RK_BMAJ) && (dev == (rootdev & 0377)))
		return(1);
	if((sm == RK_BMAJ) && (dev == (swapdev & 0377)))
		return(2);
	if((em == RK_RMAJ) && (dev == (el_dev & 0377)))
		return(3);
	return(0);
}

stop()
{
	exit(0);
}