xref: /csrg-svn/sys/vax/stand/format.c (revision 15051)
1*15051Skarels /*	format.c	6.3	83/09/23	*/
211367Ssam 
3*15051Skarels 
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 
57*15051Skarels /*
58*15051Skarels  * Purdue/EE severe burnin patterns.
59*15051Skarels  */
60*15051Skarels unsigned short ppat[] = {
61*15051Skarels 0031463,0070707,0133333,0155555,0161616,0143434,
62*15051Skarels 0107070,0016161,0034343,0044444,0022222,0111111,0125252, 052525,
63*15051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
64*15051Skarels #ifndef	SHORTPASS
65*15051Skarels 0125252,0125252,0125252,0125252,0125252,0125252,0125252,0125252,
66*15051Skarels  052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525,
67*15051Skarels #endif
68*15051Skarels  052525, 052525, 052525, 052525, 052525, 052525, 052525, 052525
69*15051Skarels  };
70*15051Skarels 
71*15051Skarels #define	NPT	(sizeof (ppat) / sizeof (short))
72*15051Skarels int	npat;		/* subscript to ppat[] */
73*15051Skarels int	severe;		/* nz if running "severe" burnin */
74*15051Skarels int	nbads;		/* subscript for bads */
75*15051Skarels long	bads[MAXBADDESC]; /* Bad blocks accumulated */
76*15051Skarels 
7711367Ssam char	*malloc();
78*15051Skarels int	qcompar();
7911367Ssam char	*prompt();
8011367Ssam extern	int end;
8111367Ssam 
8211367Ssam main()
8311367Ssam {
8411367Ssam 	register int sector, sn;
85*15051Skarels 	int lastsector, tracksize, rtracksize;
8611367Ssam 	int unit, fd, resid, i, trk, cyl, debug;
8711367Ssam 	struct st st;
8811367Ssam 	struct sector *bp, *cbp;
89*15051Skarels 	char *rbp, *rcbp;
90*15051Skarels 	int pass, maxpass;
9111367Ssam 	char *cp;
9211367Ssam 
9311367Ssam 	printf("Disk format/check utility\n\n");
9411367Ssam 
9511367Ssam again:
96*15051Skarels 	nbads = 0;
97*15051Skarels 	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");
110*15051Skarels 	if (severe)
111*15051Skarels 		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) {
116*15051Skarels 		if (severe) {
117*15051Skarels 			printf("Severe burnin doesn't work with RM80 yet\n");
118*15051Skarels 			exit(1);
119*15051Skarels 		}
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;
125*15051Skarels 	rtracksize = SECTSIZ * st.nsect;
12611367Ssam 	bp = (struct sector *)malloc(tracksize);
127*15051Skarels 	rbp = malloc(rtracksize);
128*15051Skarels 	if (severe) {
129*15051Skarels 		npat = 0;
130*15051Skarels 		maxpass = NPT;
131*15051Skarels 	} else
132*15051Skarels 		maxpass = 1;
133*15051Skarels 	for (pass = 0; pass < maxpass; pass++) {
134*15051Skarels 		if (severe)
135*15051Skarels 			printf("Begin pass %d\n", pass);
136*15051Skarels 		bufinit(bp, tracksize);
137*15051Skarels 		if (severe)
138*15051Skarels 			npat++;
13911367Ssam 		/*
140*15051Skarels 		 * Begin check, for each track,
14111367Ssam 		 *
142*15051Skarels 		 * 1) Write header and test pattern.
143*15051Skarels 		 * 2) Read data.  Hardware checks header and data ECC.
144*15051Skarels 		 *    Read data (esp on Eagles) is much faster when write check.
14511367Ssam 		 */
146*15051Skarels 		lastsector = st.nspc * st.ncyl;
147*15051Skarels 		for (sector = 0; sector < lastsector; sector += st.nsect) {
148*15051Skarels 			cyl = sector / st.nspc;
149*15051Skarels 			trk = (sector % st.nspc) / st.nsect;
150*15051Skarels 			for (i = 0; i < st.nsect; i++) {
151*15051Skarels 				bp[i].header1 =
152*15051Skarels 					(u_short) cyl | HDR1_FMT22 | HDR1_OKSCT;
153*15051Skarels 				bp[i].header2 = ((u_short)trk << 8) + i;
154*15051Skarels 			}
155*15051Skarels 			if (sector && (sector % (st.nspc * 100)) == 0)
156*15051Skarels 				printf("cylinder %d\n", cyl);
157*15051Skarels 			/*
158*15051Skarels 			 * Try and write the headers and data patterns into
159*15051Skarels 			 * each sector in the track.  Continue until such
160*15051Skarels 			 * we're done, or until there's less than a sector's
161*15051Skarels 			 * worth of data to transfer.
162*15051Skarels 			 *
163*15051Skarels 			 * The lseek call is necessary because of
164*15051Skarels 			 * the odd sector size (516 bytes)
165*15051Skarels 			 */
166*15051Skarels 			for (resid = tracksize, cbp = bp, sn = sector;;) {
167*15051Skarels 				int cc;
16811367Ssam 
169*15051Skarels 				lseek(fd, sn * SECTSIZ, 0);
170*15051Skarels 				ioctl(fd, SAIOHDR, (char *)0);
171*15051Skarels 				cc = write(fd, cbp, resid);
172*15051Skarels 				if (cc == resid)
173*15051Skarels 					break;
174*15051Skarels 				/*
175*15051Skarels 				 * Don't record errors during write,
176*15051Skarels 				 * all errors will be found during
177*15051Skarels 				 * writecheck performed below.
178*15051Skarels 				 */
179*15051Skarels 				sn = iob[fd - 3].i_errblk;
180*15051Skarels 				cbp += sn - sector;
181*15051Skarels 				resid -= (sn - sector) * sizeof (struct sector);
182*15051Skarels 				if (resid < sizeof (struct sector))
183*15051Skarels 					break;
184*15051Skarels 			}
18511367Ssam 			/*
186*15051Skarels 			 * Read test patterns.
187*15051Skarels 			 * Retry remainder of track on error until
188*15051Skarels 			 * we're done, or until there's less than a
189*15051Skarels 			 * sector to verify.
19011367Ssam 			 */
191*15051Skarels 			for (resid = rtracksize, rcbp = rbp, sn = sector;;) {
192*15051Skarels 				int cc;
19311367Ssam 
194*15051Skarels 				lseek(fd, sn * SECTSIZ, 0);
195*15051Skarels 				cc = read(fd, rcbp, resid);
196*15051Skarels 				if (cc == resid)
197*15051Skarels 					break;
198*15051Skarels 				sn = iob[fd-3].i_errblk;
199*15051Skarels 				printf("sector %d, read error\n", sn);
200*15051Skarels 				if (recorderror(fd, sn, &st) < 0 && pass > 0)
201*15051Skarels 					goto out;
202*15051Skarels 				/* advance past bad sector */
203*15051Skarels 				sn++;
204*15051Skarels 				rcbp += sn - sector;
205*15051Skarels 				resid -= ((sn - sector) * SECTSIZ);
206*15051Skarels 				if (resid < SECTSIZ)
207*15051Skarels 					break;
208*15051Skarels 			}
20911367Ssam 		}
21011367Ssam 	}
21111367Ssam 	/*
21211367Ssam 	 * Checking finished.
21311367Ssam 	 */
214*15051Skarels out:
215*15051Skarels 	if (severe && nbads) {
216*15051Skarels 		/*
217*15051Skarels 		 * Sort bads and insert in bad block table.
218*15051Skarels 		 */
219*15051Skarels 		qsort(bads, nbads, sizeof (long), qcompar);
220*15051Skarels 		severe = 0;
221*15051Skarels 		for (i = 0; i < nbads; i++) {
222*15051Skarels 			errno = EECC;	/* for now */
223*15051Skarels 			recorderror(fd, bads[i], &st);
224*15051Skarels 		}
225*15051Skarels 		severe++;
226*15051Skarels 	}
22711367Ssam 	if (errors[FE_TOTAL] || errors[FE_SSE]) {
22811367Ssam 		printf("Errors:\n");
22911367Ssam 		for (i = 0; i < NERRORS; i++)
23011367Ssam 			printf("%s: %d\n", errornames[i], errors[i]);
23111367Ssam 		printf("Total of %d hard errors found\n",
23211367Ssam 			errors[FE_TOTAL] + errors[FE_SSE]);
23311367Ssam 		/* change the headers of all the bad sectors */
23411367Ssam 		writebb(fd, errors[FE_SSE], &sstab, &st, SSERR);
23511367Ssam 		writebb(fd, errors[FE_TOTAL], &dkbad, &st, BSERR);
23611367Ssam 	}
23711367Ssam 	while (errors[FE_TOTAL] < MAXBADDESC) {
23811367Ssam 		int i = errors[FE_TOTAL]++;
23911367Ssam 
24011367Ssam 		dkbad.bt_bad[i].bt_cyl = -1;
24111367Ssam 		dkbad.bt_bad[i].bt_trksec = -1;
24211367Ssam 	}
24311367Ssam 	printf("\nWriting bad sector table at sector #%d\n",
24411367Ssam 		st.ncyl * st.nspc - st.nsect);
24511367Ssam 	/* place on disk */
24611367Ssam 	for (i = 0; i < 10; i += 2) {
24711367Ssam 		lseek(fd, SECTSIZ * (st.ncyl * st.nspc - st.nsect + i), 0);
24811367Ssam 		write(fd, &dkbad, sizeof (dkbad));
24911367Ssam 	}
25011367Ssam 	printf("Done\n");
25111367Ssam 	ioctl(fd,SAIONOSSI,(char *)0);
25211367Ssam 	close(fd);
253*15051Skarels /*
254*15051Skarels 	if (severe) {
255*15051Skarels 		asm("halt");
256*15051Skarels 		exit(0);
257*15051Skarels 	}
258*15051Skarels */
25911367Ssam #ifndef JUSTEXIT
26011367Ssam 	goto again;
26111367Ssam #endif
26211367Ssam }
26311367Ssam 
264*15051Skarels qcompar(l1, l2)
265*15051Skarels register long *l1, *l2;
266*15051Skarels {
267*15051Skarels 	if (*l1 < *l2)
268*15051Skarels 		return(-1);
269*15051Skarels 	if (*l1 == *l2)
270*15051Skarels 		return(0);
271*15051Skarels 	return(1);
272*15051Skarels }
273*15051Skarels 
27411367Ssam /*
27511367Ssam  * Write out the bad blocks.
27611367Ssam  */
27711367Ssam writebb(fd, nsects, dbad, st, sw)
27811367Ssam 	int nsects, fd;
27911367Ssam 	struct dkbad *dbad;
28011367Ssam 	register struct st *st;
28111367Ssam {
28211367Ssam 	struct sector bb_buf; /* buffer for one sector plus 4 byte header */
28311367Ssam 	register int i;
28411367Ssam 	int bn, j;
28511367Ssam 	struct bt_bad *btp;
28611367Ssam 
28711367Ssam 	for (i = 0; i < nsects; i++) {
28811367Ssam 		btp = &dbad->bt_bad[i];
28911367Ssam 		if (sw == BSERR) {
29011367Ssam 			bb_buf.header1 = HDR1_FMT22|btp->bt_cyl;
29111367Ssam 			if (SSDEV)
29211367Ssam 				bb_buf.header1 |= HDR1_SSF;
29311367Ssam 		} else
29411367Ssam 			bb_buf.header1 =
29511367Ssam 			       btp->bt_cyl | HDR1_FMT22 | HDR1_SSF | HDR1_OKSCT;
29611367Ssam 		bb_buf.header2 = btp->bt_trksec;
29711367Ssam 		bn = st->nspc * btp->bt_cyl +
29811367Ssam 		     st->nsect * (btp->bt_trksec >> 8) +
29915009Skarels 		     (btp->bt_trksec & 0xff);
30011367Ssam 		lseek(fd, bn * SECTSIZ, 0);
30111367Ssam 		ioctl(fd, SAIOHDR, (char *)0);
30211367Ssam 		write(fd, &bb_buf, sizeof (bb_buf));
30311367Ssam 		if (!SSDEV)
30411367Ssam 			continue;
30511367Ssam 		/*
30611367Ssam 		 * If skip sector, mark all remaining
30711367Ssam 		 * sectors on the track.
30811367Ssam 		 */
30915009Skarels 		for (j = (btp->bt_trksec & 0xff) + 1; j < st->nsect; j++) {
31011367Ssam 			bb_buf.header1 = j | HDR1_FMT22 | HDR1_SSF;
31111367Ssam 			ioctl(fd, SAIOHDR, (char *)0);
31211367Ssam 			write(fd, &bb_buf, sizeof (bb_buf));
31311367Ssam 		}
31411367Ssam 	}
31511367Ssam }
31611367Ssam 
31711367Ssam /*
31811367Ssam  * Record an error, and if there's room, put
31911367Ssam  * it in the appropriate bad sector table.
320*15051Skarels  *
321*15051Skarels  * If severe burnin store block in a list after making sure
322*15051Skarels  * we have not already found it on a prev pass.
32311367Ssam  */
32411367Ssam recorderror(fd, bn, st)
32511367Ssam 	int fd, bn;
32611367Ssam 	register struct st *st;
32711367Ssam {
32811367Ssam 	int cn, tn, sn, strk;
329*15051Skarels 	register i;
33011367Ssam 
331*15051Skarels 
332*15051Skarels 	if (severe) {
333*15051Skarels 		for (i = 0; i < nbads; i++)
334*15051Skarels 			if (bads[i] == bn)
335*15051Skarels 				return(0);	/* bn already flagged */
336*15051Skarels 		if (nbads >= MAXBADDESC) {
337*15051Skarels 			printf("Bad sector table full, burnin terminating\n");
338*15051Skarels 			return(-1);
339*15051Skarels 		}
340*15051Skarels 		bads[nbads++] = bn;
341*15051Skarels 		return(0);
342*15051Skarels 	}
34311367Ssam 	if (errors[FE_TOTAL] >= MAXBADDESC) {
34411367Ssam 		printf("Too many bad sectors\n");
345*15051Skarels 		return(-1);
34611367Ssam 	}
34711367Ssam 	if (errors[FE_SSE] >= MAXBADDESC) {
34811367Ssam 		printf("Too many skip sector errors\n");
349*15051Skarels 		return(-1);
35011367Ssam 	}
35115009Skarels 	if (errno < EBSE || errno > EHER)
352*15051Skarels 		return(0);
35315009Skarels 	errno -= EBSE;
35411367Ssam 	errors[errno]++;
35511367Ssam 	cn = bn / st->nspc;
35611367Ssam 	sn = bn % st->nspc;
35711367Ssam 	tn = sn / st->nsect;
35811367Ssam 	sn %= st->nsect;
35911367Ssam 	if (SSDEV) {		/* if drive has skip sector capability */
36011367Ssam 		int ss = errors[FE_SSE]++;
36111367Ssam 
36211367Ssam 		if (ss)
36311367Ssam 			strk = sstab.bt_bad[ss - 1].bt_trksec >> 8;
36411367Ssam 		else
36511367Ssam 			strk = -1;
36611367Ssam 		if (tn != strk) {	  /* only one skip sector/track */
36711367Ssam 			sstab.bt_bad[ss].bt_cyl = cn;
36811367Ssam 			sstab.bt_bad[ss].bt_trksec = (tn<<8) + sn;
36911367Ssam 			return;
37011367Ssam 		}
37111367Ssam 		cn = -cn;
37211367Ssam 	}
37311367Ssam 	/* record the bad sector address and continue */
37415009Skarels 	dkbad.bt_bad[errors[FE_TOTAL]].bt_cyl = cn;
37511367Ssam 	dkbad.bt_bad[errors[FE_TOTAL]++].bt_trksec = (tn << 8) + sn;
376*15051Skarels 	return(0);
37711367Ssam }
37811367Ssam 
37911367Ssam /*
38011367Ssam  * Allocate memory on a page-aligned address.
38111367Ssam  * Round allocated chunk to a page multiple to
38211367Ssam  * ease next request.
38311367Ssam  */
38411367Ssam char *
38511367Ssam malloc(size)
38611367Ssam 	int size;
38711367Ssam {
38811367Ssam 	char *result;
38911367Ssam 	static caddr_t last = 0;
39011367Ssam 
39111367Ssam 	if (last == 0)
39211367Ssam 		last = (caddr_t)(((int)&end + 511) & ~0x1ff);
39311367Ssam 	size = (size + 511) & ~0x1ff;
39411367Ssam 	result = (char *)last;
39511367Ssam 	last += size;
39611367Ssam 	return (result);
39711367Ssam }
39811367Ssam 
39911367Ssam /*
40011367Ssam  * Prompt and verify a device name from the user.
40111367Ssam  */
40211367Ssam getdevice()
40311367Ssam {
40411367Ssam 	register char *cp;
40511367Ssam 	register struct devsw *dp;
40611367Ssam 	int fd;
40711367Ssam 
40811367Ssam top:
40911367Ssam 	cp = prompt("Device to format? ");
41011367Ssam 	if ((fd = open(cp, 2)) < 0) {
41111367Ssam 		printf("Known devices are: ");
41211367Ssam 		for (dp = devsw; dp->dv_name; dp++)
41311367Ssam 			printf("%s ",dp->dv_name);
41411367Ssam 		printf("\n");
41511367Ssam 		goto top;
41611367Ssam 	}
417*15051Skarels 	printf("Formatting drive %c%c%d on adaptor %d: ",
418*15051Skarels 		cp[0], cp[1], iob[fd - 3].i_unit % 8, iob[fd - 3].i_unit / 8);
41911367Ssam 	cp = prompt("verify (yes/no)? ");
42011367Ssam 	while (*cp != 'y' && *cp != 'n')
42111367Ssam 		cp = prompt("Huh, yes or no? ");
42211367Ssam 	if (*cp == 'y')
42311367Ssam 		return (fd);
42411367Ssam 	goto top;
42511367Ssam }
42611367Ssam 
42711371Ssam static struct pattern {
42811371Ssam 	long	pa_value;
42911371Ssam 	char	*pa_name;
43011371Ssam } pat[] = {
43111371Ssam 	{ 0xf00ff00f, 	"RH750 worst case" },
43211371Ssam 	{ 0xec6dec6d,	"media worst case" },
43311371Ssam 	{ 0xa5a5a5a5,	"alternate 1's and 0's" },
434*15051Skarels 	{ 0xFFFFFFFF,	"Severe burnin (takes several hours)" },
43511371Ssam 	{ 0, 0 },
43611371Ssam };
43711371Ssam 
43811371Ssam getpattern()
43911371Ssam {
44011371Ssam 	register struct pattern *p;
44111371Ssam 	int npatterns;
44211371Ssam 	char *cp;
44311371Ssam 
44411371Ssam 	printf("Available test patterns are:\n");
44511371Ssam 	for (p = pat; p->pa_value; p++)
44611371Ssam 		printf("\t%d - (%x) %s\n", (p - pat) + 1,
44711371Ssam 		  p->pa_value & 0xffff, p->pa_name);
44811371Ssam 	npatterns = p - pat;
44911371Ssam 	cp = prompt("Pattern (one of the above, other to restart)? ");
45011371Ssam 	pattern = atoi(cp) - 1;
451*15051Skarels 	severe = 0;
452*15051Skarels 	if (pat[pattern].pa_value == -1)
453*15051Skarels 		severe = 1;
45411371Ssam 	return (pattern < 0 || pattern >= npatterns);
45511371Ssam }
45611371Ssam 
45711371Ssam struct xsect {
45811371Ssam 	u_short	hd1;
45911371Ssam 	u_short	hd2;
46011371Ssam 	long	buf[128];
46111371Ssam };
46211371Ssam 
46311371Ssam /*
46411371Ssam  * Initialize the buffer with the requested pattern.
46511371Ssam  */
46611371Ssam bufinit(bp, size)
46711371Ssam 	register struct xsect *bp;
46811371Ssam 	int size;
46911371Ssam {
47011371Ssam 	register struct pattern *pptr;
47111371Ssam 	register long *pp, *last;
47211371Ssam 	register struct xsect *lastbuf;
473*15051Skarels 	int patt;
47411371Ssam 
47511371Ssam 	size /= sizeof (struct sector);
47611371Ssam 	lastbuf = bp + size;
477*15051Skarels 	if (severe) {
478*15051Skarels 		patt = ppat[npat] | ((long)ppat[npat] << 16);
479*15051Skarels 		printf("Write pattern 0x%x\n", patt&0xffff);
480*15051Skarels 	} else {
481*15051Skarels 		pptr = &pat[pattern];
482*15051Skarels 		patt = pptr->pa_value;
483*15051Skarels 	}
48411371Ssam 	while (bp < lastbuf) {
48511371Ssam 		last = &bp->buf[128];
48611371Ssam 		for (pp = bp->buf; pp < last; pp++)
487*15051Skarels 			*pp = patt;
48811371Ssam 		bp++;
48911371Ssam 	}
49011371Ssam }
49111371Ssam 
49211367Ssam char *
49311367Ssam prompt(msg)
49411367Ssam 	char *msg;
49511367Ssam {
49611367Ssam 	static char buf[132];
49711367Ssam 
49811367Ssam 	printf("%s", msg);
49911367Ssam 	gets(buf);
50011367Ssam 	return (buf);
50111367Ssam }
502