xref: /csrg-svn/sys/vax/stand/format.c (revision 17426)
1*17426Skarels /*	format.c	6.4	84/11/27	*/
211367Ssam 
315051Skarels 
411367Ssam /*
511367Ssam  * Standalone program to do media checking
611367Ssam  * and record bad block information on any
715009Skarels  * disk with the appropriate driver and RM03-style headers.
811367Ssam  */
911367Ssam #include "../h/param.h"
1011367Ssam #include "../h/fs.h"
1111367Ssam #include "../h/inode.h"
1211367Ssam #include "../h/dkbad.h"
1311367Ssam #include "../h/vmmac.h"
1411367Ssam 
1511367Ssam #include "saio.h"
1611367Ssam #include "savax.h"
1711367Ssam 
1811367Ssam #define MAXBADDESC	126		/* size of bad block table */
1911367Ssam #define CHUNK		48		/* max # of sectors/io operation */
2011367Ssam #define SECTSIZ		512		/* standard sector size */
2111367Ssam #define HDRSIZ		4		/* number of bytes in sector header */
2211367Ssam 
2311367Ssam #define SSERR		0
2411367Ssam #define BSERR		1
2511367Ssam 
2611367Ssam #define SSDEV		((ioctl(iob[fd-3], SAIOSSDEV, (char *)0) == 0))
2711367Ssam 
2811367Ssam struct sector {
2911367Ssam 	u_short	header1;
3011367Ssam 	u_short header2;
3111367Ssam 	char	buf[SECTSIZ];
3211367Ssam };
3311367Ssam 
3411367Ssam struct	dkbad dkbad;		/* bad sector table */
3511367Ssam struct	dkbad sstab;		/* skip sector table */
3611367Ssam 
3711367Ssam #define	NERRORS		6
3811371Ssam static char *
3911371Ssam errornames[NERRORS] = {
4015009Skarels #define	FE_BSE		0
4115009Skarels 	"Bad sector",
4215009Skarels #define	FE_WCE		1
4311367Ssam 	"Write check",
4411367Ssam #define	FE_ECC		2
4511367Ssam 	"ECC",
4611367Ssam #define	FE_HARD		3
4711367Ssam 	"Other hard",
4811367Ssam #define	FE_TOTAL	4
4911367Ssam 	"Total",
5011367Ssam #define	FE_SSE		5
5111367Ssam 	"Skip sector",
5211367Ssam };
5311367Ssam 
5411367Ssam int	errors[NERRORS];	/* histogram of errors */
5511371Ssam int	pattern;
5611367Ssam 
5715051Skarels /*
5815051Skarels  * Purdue/EE severe burnin patterns.
5915051Skarels  */
6015051Skarels unsigned short ppat[] = {
61*17426Skarels 0xf00f, 0xec6d, 0031463,0070707,0133333,0155555,0161616,0143434,
6215051Skarels 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525,
6315051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
6415051Skarels #ifndef	SHORTPASS
6515051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
6615051Skarels  052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525,
6715051Skarels #endif
6815051Skarels  052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525
6915051Skarels  };
7015051Skarels 
7115051Skarels #define	NPT	(sizeof (ppat) / sizeof (short))
72*17426Skarels int	maxpass, npat;	/* subscript to ppat[] */
7315051Skarels int	severe;		/* nz if running "severe" burnin */
7415051Skarels int	nbads;		/* subscript for bads */
7515051Skarels long	bads[MAXBADDESC]; /* Bad blocks accumulated */
7615051Skarels 
7711367Ssam char	*malloc();
7815051Skarels int	qcompar();
7911367Ssam char	*prompt();
8011367Ssam extern	int end;
8111367Ssam 
8211367Ssam main()
8311367Ssam {
8411367Ssam 	register int sector, sn;
8515051Skarels 	int lastsector, tracksize, rtracksize;
8611367Ssam 	int unit, fd, resid, i, trk, cyl, debug;
8711367Ssam 	struct st st;
8811367Ssam 	struct sector *bp, *cbp;
8915051Skarels 	char *rbp, *rcbp;
90*17426Skarels 	int pass;
9111367Ssam 	char *cp;
9211367Ssam 
9311367Ssam 	printf("Disk format/check utility\n\n");
9411367Ssam 
9511367Ssam again:
9615051Skarels 	nbads = 0;
9715051Skarels 	cp = prompt("Enable debugging (0=none, 1=bse, 2=ecc, 3=bse+ecc)? ");
9811367Ssam 	debug = atoi(cp);
9911367Ssam 	if (debug < 0)
10011367Ssam 		debug = 0;
10111367Ssam 	for (i = 0; i < NERRORS; i++)
10211367Ssam 		errors[i] = 0;
10311367Ssam 	fd = getdevice();
10411367Ssam 	ioctl(fd, SAIODEVDATA, &st);
10511367Ssam 	printf("Device data: #cylinders=%d, #tracks=%d, #sectors=%d\n",
10611367Ssam 	  st.ncyl, st.ntrak, st.nsect);
10711371Ssam 	if (getpattern())
10811367Ssam 		goto again;
10911367Ssam 	printf("Start formatting...make sure the drive is online\n");
11015051Skarels 	if (severe)
11115051Skarels 		ioctl(fd, SAIOSEVRE, (char *) 0);
11211367Ssam 	ioctl(fd, SAIONOBAD, (char *)0);
11311367Ssam 	ioctl(fd, SAIOECCLIM, (char *)0);
11411367Ssam 	ioctl(fd, SAIODEBUG, (char *)debug);
11511367Ssam 	if (SSDEV) {
11615051Skarels 		if (severe) {
11715051Skarels 			printf("Severe burnin doesn't work with RM80 yet\n");
11815051Skarels 			exit(1);
11915051Skarels 		}
12011367Ssam 		ioctl(fd, SAIOSSI, (char *)0);	/* set skip sector inhibit */
12111367Ssam 		st.nsect++;
12211367Ssam 		st.nspc += st.ntrak;
12311367Ssam 	}
12411367Ssam 	tracksize = sizeof (struct sector) * st.nsect;
12515051Skarels 	rtracksize = SECTSIZ * st.nsect;
12611367Ssam 	bp = (struct sector *)malloc(tracksize);
12715051Skarels 	rbp = malloc(rtracksize);
128*17426Skarels 	pass = 0;
129*17426Skarels 	npat = 0;
130*17426Skarels more:
131*17426Skarels 	for (; pass < maxpass; pass++) {
13215051Skarels 		if (severe)
13315051Skarels 			printf("Begin pass %d\n", pass);
13415051Skarels 		bufinit(bp, tracksize);
13515051Skarels 		if (severe)
13615051Skarels 			npat++;
13711367Ssam 		/*
13815051Skarels 		 * Begin check, for each track,
13911367Ssam 		 *
14015051Skarels 		 * 1) Write header and test pattern.
14115051Skarels 		 * 2) Read data.  Hardware checks header and data ECC.
142*17426Skarels 		 *    Read data (esp on Eagles) is much faster than write check.
14311367Ssam 		 */
14415051Skarels 		lastsector = st.nspc * st.ncyl;
14515051Skarels 		for (sector = 0; sector < lastsector; sector += st.nsect) {
14615051Skarels 			cyl = sector / st.nspc;
14715051Skarels 			trk = (sector % st.nspc) / st.nsect;
14815051Skarels 			for (i = 0; i < st.nsect; i++) {
14915051Skarels 				bp[i].header1 =
15015051Skarels 					(u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
15115051Skarels 				bp[i].header2 = ((u_short)trk << 8) + i;
15215051Skarels 			}
15315051Skarels 			if (sector && (sector % (st.nspc * 100)) == 0)
15415051Skarels 				printf("cylinder %d\n", cyl);
15515051Skarels 			/*
15615051Skarels 			 * Try and write the headers and data patterns into
15715051Skarels 			 * each sector in the track.  Continue until such
15815051Skarels 			 * we're done, or until there's less than a sector's
15915051Skarels 			 * worth of data to transfer.
16015051Skarels 			 *
16115051Skarels 			 * The lseek call is necessary because of
16215051Skarels 			 * the odd sector size (516 bytes)
16315051Skarels 			 */
16415051Skarels 			for (resid = tracksize, cbp = bp, sn = sector;;) {
16515051Skarels 				int cc;
16611367Ssam 
16715051Skarels 				lseek(fd, sn * SECTSIZ, 0);
16815051Skarels 				ioctl(fd, SAIOHDR, (char *)0);
16915051Skarels 				cc = write(fd, cbp, resid);
17015051Skarels 				if (cc == resid)
17115051Skarels 					break;
17215051Skarels 				/*
17315051Skarels 				 * Don't record errors during write,
17415051Skarels 				 * all errors will be found during
17515051Skarels 				 * writecheck performed below.
17615051Skarels 				 */
17715051Skarels 				sn = iob[fd - 3].i_errblk;
17815051Skarels 				cbp += sn - sector;
17915051Skarels 				resid -= (sn - sector) * sizeof (struct sector);
18015051Skarels 				if (resid < sizeof (struct sector))
18115051Skarels 					break;
18215051Skarels 			}
18311367Ssam 			/*
18415051Skarels 			 * Read test patterns.
18515051Skarels 			 * Retry remainder of track on error until
18615051Skarels 			 * we're done, or until there's less than a
18715051Skarels 			 * sector to verify.
18811367Ssam 			 */
18915051Skarels 			for (resid = rtracksize, rcbp = rbp, sn = sector;;) {
19015051Skarels 				int cc;
19111367Ssam 
19215051Skarels 				lseek(fd, sn * SECTSIZ, 0);
19315051Skarels 				cc = read(fd, rcbp, resid);
19415051Skarels 				if (cc == resid)
19515051Skarels 					break;
19615051Skarels 				sn = iob[fd-3].i_errblk;
19715051Skarels 				printf("sector %d, read error\n", sn);
19815051Skarels 				if (recorderror(fd, sn, &st) < 0 && pass > 0)
19915051Skarels 					goto out;
20015051Skarels 				/* advance past bad sector */
20115051Skarels 				sn++;
20215051Skarels 				rcbp += sn - sector;
20315051Skarels 				resid -= ((sn - sector) * SECTSIZ);
20415051Skarels 				if (resid < SECTSIZ)
20515051Skarels 					break;
20615051Skarels 			}
20711367Ssam 		}
20811367Ssam 	}
20911367Ssam 	/*
21011367Ssam 	 * Checking finished.
21111367Ssam 	 */
21215051Skarels out:
213*17426Skarels 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
214*17426Skarels 		printf("Errors:\n");
215*17426Skarels 		for (i = 0; i < NERRORS; i++)
216*17426Skarels 			printf("%s: %d\n", errornames[i], errors[i]);
217*17426Skarels 		printf("Total of %d hard errors found\n",
218*17426Skarels 			errors[FE_TOTAL] + errors[FE_SSE]);
219*17426Skarels 	}
220*17426Skarels 	if (severe && maxpass < NPT) {
221*17426Skarels 		cp = prompt("More passes? (0 or number) ");
222*17426Skarels 		maxpass = atoi(cp);
223*17426Skarels 		if (maxpass > 0) {
224*17426Skarels 			maxpass += pass;
225*17426Skarels 			goto more;
226*17426Skarels 		}
227*17426Skarels 	}
22815051Skarels 	if (severe && nbads) {
22915051Skarels 		/*
23015051Skarels 		 * Sort bads and insert in bad block table.
23115051Skarels 		 */
23215051Skarels 		qsort(bads, nbads, sizeof (long), qcompar);
23315051Skarels 		severe = 0;
234*17426Skarels 		errno = 0;
235*17426Skarels 		for (i = 0; i < nbads; i++)
23615051Skarels 			recorderror(fd, bads[i], &st);
23715051Skarels 		severe++;
23815051Skarels 	}
23911367Ssam 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
24011367Ssam 		/* change the headers of all the bad sectors */
24111367Ssam 		writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
24211367Ssam 		writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
24311367Ssam 	}
24411367Ssam 	while (errors[FE_TOTAL] < MAXBADDESC) {
24511367Ssam 		int i = errors[FE_TOTAL]++;
24611367Ssam 
24711367Ssam 		dkbad.bt_bad[i].bt_cyl = -1;
24811367Ssam 		dkbad.bt_bad[i].bt_trksec = -1;
24911367Ssam 	}
25011367Ssam 	printf("\nWriting bad sector table at sector #%d\n",
25111367Ssam 		st.ncyl * st.nspc - st.nsect);
25211367Ssam 	/* place on disk */
25311367Ssam 	for (i = 0; i < 10; i += 2) {
25411367Ssam 		lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
25511367Ssam 		write(fd, &dkbad, sizeof (dkbad));
25611367Ssam 	}
25711367Ssam 	printf("Done\n");
25811367Ssam 	ioctl(fd,SAIONOSSI,(char *)0);
25911367Ssam 	close(fd);
26011367Ssam #ifndef JUSTEXIT
26111367Ssam 	goto again;
26211367Ssam #endif
26311367Ssam }
26411367Ssam 
26515051Skarels qcompar(l1, l2)
26615051Skarels register long *l1, *l2;
26715051Skarels {
26815051Skarels 	if (*l1 < *l2)
26915051Skarels 		return(-1);
27015051Skarels 	if (*l1 == *l2)
27115051Skarels 		return(0);
27215051Skarels 	return(1);
27315051Skarels }
27415051Skarels 
27511367Ssam /*
27611367Ssam  * Write out the bad blocks.
27711367Ssam  */
27811367Ssam writebb(fd, nsects, dbad, st, sw)
27911367Ssam 	int nsects, fd;
28011367Ssam 	struct dkbad *dbad;
28111367Ssam 	register struct st *st;
28211367Ssam {
28311367Ssam 	struct sector bb_buf; /* buffer for one sector plus 4 byte header */
28411367Ssam 	register int i;
28511367Ssam 	int bn, j;
28611367Ssam 	struct bt_bad *btp;
28711367Ssam 
28811367Ssam 	for (i = 0; i < nsects; i++) {
28911367Ssam 		btp = &dbad->bt_bad[i];
29011367Ssam 		if (sw == BSERR) {
29111367Ssam 			bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
29211367Ssam 			if (SSDEV)
29311367Ssam 				bb_buf.header1 |= HDR1_SSF;
29411367Ssam 		} else
29511367Ssam 			bb_buf.header1 =
29611367Ssam 			       btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
29711367Ssam 		bb_buf.header2 = btp->bt_trksec;
29811367Ssam 		bn = st->nspc * btp->bt_cyl +
29911367Ssam 		     st->nsect * (btp->bt_trksec >> 8) +
30015009Skarels 		     (btp->bt_trksec & 0xff);
30111367Ssam 		lseek(fd, bn * SECTSIZ, 0);
30211367Ssam 		ioctl(fd, SAIOHDR, (char *)0);
30311367Ssam 		write(fd, &bb_buf, sizeof (bb_buf));
30411367Ssam 		if (!SSDEV)
30511367Ssam 			continue;
30611367Ssam 		/*
30711367Ssam 		 * If skip sector, mark all remaining
30811367Ssam 		 * sectors on the track.
30911367Ssam 		 */
31015009Skarels 		for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) {
31111367Ssam 			bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF;
31211367Ssam 			ioctl(fd, SAIOHDR, (char *)0);
31311367Ssam 			write(fd, &bb_buf, sizeof (bb_buf));
31411367Ssam 		}
31511367Ssam 	}
31611367Ssam }
31711367Ssam 
31811367Ssam /*
31911367Ssam  * Record an error, and if there's room, put
32011367Ssam  * it in the appropriate bad sector table.
32115051Skarels  *
32215051Skarels  * If severe burnin store block in a list after making sure
32315051Skarels  * we have not already found it on a prev pass.
32411367Ssam  */
32511367Ssam recorderror(fd, bn, st)
32611367Ssam 	int fd, bn;
32711367Ssam 	register struct st *st;
32811367Ssam {
32911367Ssam 	int cn, tn, sn, strk;
33015051Skarels 	register i;
33111367Ssam 
33215051Skarels 
33315051Skarels 	if (severe) {
33415051Skarels 		for (i = 0; i < nbads; i++)
33515051Skarels 			if (bads[i] == bn)
33615051Skarels 				return(0);	/* bn already flagged */
33715051Skarels 		if (nbads >= MAXBADDESC) {
33815051Skarels 			printf("Bad sector table full, burnin terminating\n");
33915051Skarels 			return(-1);
34015051Skarels 		}
34115051Skarels 		bads[nbads++] = bn;
342*17426Skarels 		if (errno < EBSE || errno > EHER)
343*17426Skarels 			return(0);
344*17426Skarels 		errno -= EBSE;
345*17426Skarels 		errors[errno]++;
34615051Skarels 		return(0);
34715051Skarels 	}
348*17426Skarels 	if (errno >= EBSE && errno <= EHER) {
349*17426Skarels 		if (errors[FE_TOTAL] >= MAXBADDESC) {
350*17426Skarels 			printf("Too many bad sectors\n");
351*17426Skarels 			return(-1);
352*17426Skarels 		}
353*17426Skarels 		if (errors[FE_SSE] >= MAXBADDESC) {
354*17426Skarels 			printf("Too many skip sector errors\n");
355*17426Skarels 			return(-1);
356*17426Skarels 		}
357*17426Skarels 		errno -= EBSE;
358*17426Skarels 		errors[errno]++;
35911367Ssam 	}
36011367Ssam 	cn = bn / st->nspc;
36111367Ssam 	sn = bn % st->nspc;
36211367Ssam 	tn = sn / st->nsect;
36311367Ssam 	sn %= st->nsect;
36411367Ssam 	if (SSDEV) {		/* if drive has skip sector capability */
36511367Ssam 		int ss = errors[FE_SSE]++;
36611367Ssam 
36711367Ssam 		if (ss)
36811367Ssam 			strk = sstab.bt_bad[ss - 1].bt_trksec >> 8;
36911367Ssam 		else
37011367Ssam 			strk = -1;
37111367Ssam 		if (tn != strk) {	  /* only one skip sector/track */
37211367Ssam 			sstab.bt_bad[ss].bt_cyl = cn;
37311367Ssam 			sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
37411367Ssam 			return;
37511367Ssam 		}
37611367Ssam 		cn = -cn;
37711367Ssam 	}
37811367Ssam 	/* record the bad sector address and continue */
37915009Skarels 	dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn;
38011367Ssam 	dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
38115051Skarels 	return(0);
38211367Ssam }
38311367Ssam 
38411367Ssam /*
38511367Ssam  * Allocate memory on a page-aligned address.
38611367Ssam  * Round allocated chunk to a page multiple to
38711367Ssam  * ease next request.
38811367Ssam  */
38911367Ssam char *
39011367Ssam malloc(size)
39111367Ssam 	int size;
39211367Ssam {
39311367Ssam 	char *result;
39411367Ssam 	static caddr_t last = 0;
39511367Ssam 
39611367Ssam 	if (last == 0)
39711367Ssam 		last = (caddr_t)(((int)&end + 511) & ~0x1ff);
39811367Ssam 	size = (size + 511) & ~0x1ff;
39911367Ssam 	result = (char *)last;
40011367Ssam 	last += size;
40111367Ssam 	return (result);
40211367Ssam }
40311367Ssam 
40411367Ssam /*
40511367Ssam  * Prompt and verify a device name from the user.
40611367Ssam  */
40711367Ssam getdevice()
40811367Ssam {
40911367Ssam 	register char *cp;
41011367Ssam 	register struct devsw *dp;
41111367Ssam 	int fd;
41211367Ssam 
41311367Ssam top:
41411367Ssam 	cp = prompt("Device to format? ");
41511367Ssam 	if ((fd = open(cp, 2)) < 0) {
41611367Ssam 		printf("Known devices are: ");
41711367Ssam 		for (dp = devsw; dp->dv_name; dp++)
41811367Ssam 			printf("%s ",dp->dv_name);
41911367Ssam 		printf("\n");
42011367Ssam 		goto top;
42111367Ssam 	}
42215051Skarels 	printf("Formatting drive %c%c%d on adaptor %d: ",
42315051Skarels 		cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8);
42411367Ssam 	cp = prompt("verify (yes/no)? ");
42511367Ssam 	while (*cp != 'y' && *cp != 'n')
42611367Ssam 		cp = prompt("Huh, yes or no? ");
42711367Ssam 	if (*cp == 'y')
42811367Ssam 		return (fd);
42911367Ssam 	goto top;
43011367Ssam }
43111367Ssam 
43211371Ssam static struct pattern {
43311371Ssam 	long	pa_value;
43411371Ssam 	char	*pa_name;
43511371Ssam } pat[] = {
43611371Ssam 	{ 0xf00ff00f, 	"RH750 worst case" },
43711371Ssam 	{ 0xec6dec6d,	"media worst case" },
43811371Ssam 	{ 0xa5a5a5a5,	"alternate 1's and 0's" },
439*17426Skarels 	{ 0xFFFFFFFF,	"Severe burnin (up to 48 passes)" },
44011371Ssam 	{ 0, 0 },
44111371Ssam };
44211371Ssam 
44311371Ssam getpattern()
44411371Ssam {
44511371Ssam 	register struct pattern *p;
44611371Ssam 	int npatterns;
44711371Ssam 	char *cp;
44811371Ssam 
44911371Ssam 	printf("Available test patterns are:\n");
45011371Ssam 	for (p = pat; p->pa_value; p++)
45111371Ssam 		printf("\t%d - (%x) %s\n", (p - pat) + 1,
45211371Ssam 		  p->pa_value & 0xffff, p->pa_name);
45311371Ssam 	npatterns = p - pat;
45411371Ssam 	cp = prompt("Pattern (one of the above, other to restart)? ");
45511371Ssam 	pattern = atoi(cp) - 1;
456*17426Skarels 	if (pattern < 0 || pattern >= npatterns)
457*17426Skarels 		return(1);
45815051Skarels 	severe = 0;
459*17426Skarels 	maxpass = 1;
460*17426Skarels 	if (pat[pattern].pa_value == -1) {
46115051Skarels 		severe = 1;
462*17426Skarels 		cp = prompt("How many passes (up to 48)? ");
463*17426Skarels 		maxpass = atoi(cp);
464*17426Skarels 		if (maxpass > NPT)
465*17426Skarels 			maxpass = NPT;
466*17426Skarels 	}
467*17426Skarels 	return (0);
46811371Ssam }
46911371Ssam 
47011371Ssam struct xsect {
47111371Ssam 	u_short	hd1;
47211371Ssam 	u_short	hd2;
47311371Ssam 	long	buf[128];
47411371Ssam };
47511371Ssam 
47611371Ssam /*
47711371Ssam  * Initialize the buffer with the requested pattern.
47811371Ssam  */
47911371Ssam bufinit(bp, size)
48011371Ssam 	register struct xsect *bp;
48111371Ssam 	int size;
48211371Ssam {
48311371Ssam 	register struct pattern *pptr;
48411371Ssam 	register long *pp, *last;
48511371Ssam 	register struct xsect *lastbuf;
48615051Skarels 	int patt;
48711371Ssam 
48811371Ssam 	size /= sizeof (struct sector);
48911371Ssam 	lastbuf = bp + size;
49015051Skarels 	if (severe) {
49115051Skarels 		patt = ppat[npat] | ((long)ppat[npat] << 16);
49215051Skarels 		printf("Write pattern 0x%x\n", patt&0xffff);
49315051Skarels 	} else {
49415051Skarels 		pptr = &pat[pattern];
49515051Skarels 		patt = pptr->pa_value;
49615051Skarels 	}
49711371Ssam 	while (bp < lastbuf) {
49811371Ssam 		last = &bp->buf[128];
49911371Ssam 		for (pp = bp->buf; pp < last; pp++)
50015051Skarels 			*pp = patt;
50111371Ssam 		bp++;
50211371Ssam 	}
50311371Ssam }
50411371Ssam 
50511367Ssam char *
50611367Ssam prompt(msg)
50711367Ssam 	char *msg;
50811367Ssam {
50911367Ssam 	static char buf[132];
51011367Ssam 
51111367Ssam 	printf("%s", msg);
51211367Ssam 	gets(buf);
51311367Ssam 	return (buf);
51411367Ssam }
515