|
|
1.1 root 1: /*
2: * badscan.c
3: * 2/7/91
4: * Usage: badscan [-v] [-o proto] [-b boot] device count
5: * device device to be scanned (e.g. /dev/rat0a)
6: * count size of file system to be scanned
7: * sdev master boot record for device size info (e.g. /dev/at0x)
8: * Options:
9: * -b boot use "boot" for boot in prototype file (default: /conf/boot)
10: * -o proto output file name for prototype file (default: stdout)
11: * -v verbose messages as to the percentage of file system scanned
12: *
13: * Due to Inetco's braindamaged notion of removing stdio from everything, this
14: * does not #include <stdio.h> and uses sys write() calls to fd 1 and fd 2 in
15: * lieu of stdout and stderr. This should be fixed when someone gets the urge.
16: *
17: * $Log: /newbits/etc/badscan.c,v $
18: * Revision 1.6 91/02/22 12:14:25 bin
19: * updated version provided by stevesf for v311
20: *
21: * Revision 1.7 91/02/07 12:36:00 bin
22: * steve 2/7/91
23: * Following norm's suggestion, SCSI badscan now issues warning but
24: * the continues with block-by-block scan of device.
25: *
26: * Revision 1.6 91/02/07 09:58:21 bin
27: * steve 2/7/91
28: * Added include of <sys/devices.h>, changed explicitly declared floppy
29: * and hard disk major device manifest constants accordingly.
30: * Added check for major==SCSI; if so, print "SCSI devices do not require
31: * badscan" and exit successfully.
32: * Added "badscan:" at start of fatal() messages.
33: * Added comment moaning about Inetco avoiding stdio.
34: *
35: * Revision 1.5 90/04/20 09:01:50 bin
36: * steve 4/20/90
37: * Previous version failed on floppy disks because HDGETA ioctl only works
38: * on hard disks. Now it checks the major number, does HDGETA to find
39: * tracksize on hard disk and uses tracksize=1 (sector by sector scan)
40: * on floppies. Future: should add FDGETA ioctl to floppy driver and
41: * let badscan (and mkfs) find default floppy size automatically.
42: *
43: * Revision 1.4 90/04/19 14:08:36 bin
44: * steve 4/19/90
45: * Change -v messages slightly for use during install;
46: * use '\r' instead of '\n', overwrite with "Done\n" when finished.
47: *
48: * Revision 1.3 90/03/27 08:33:48 bin
49: * steve 03/27/90
50: * Mark entire bad track as bad rather than reading each sector in track.
51: *
52: * Revision 1.2 90/03/22 09:57:41 root
53: * Find sectors per track with ioctl rather than assuming 17.
54: * Rearranged code, changed fatal error messages, changed screwy spacing.
55: * steve 3/22/90
56: *
57: * 88/03/23 Allan Cornish /usr/src/cmd/etc/badscan.c
58: * Reads are no longer attempted past logical end of partition,
59: * when a logical track straddles the partition boundary.
60: *
61: * 88/01/27 Jim Belton /usr/src/cmd/etc/badscan.c
62: * Fixed bug for counts >= 32K by declaring atol().
63: *
64: * 86/11/03 Joe Iu
65: * Added -o and -b options, where the protofile and the boot file name
66: * can be specified by the user explicitly.
67: *
68: * 85/12/03 Allan Cornish
69: * Multi-sector read algorithm adjusted to ensure track alignment,
70: * even on track 0 where master boot block is not included in partition.
71: *
72: * 85/11/16 Allan Cornish
73: * Added track reads, with block by block retry on error.
74: *
75: * 85/11/13 Allan Cornish
76: * Added estimate of time remaining to each progress report.
77: *
78: * 85/11/06 Allan Cornish
79: * Added -v flag to report progress every 10 percent of scan.
80: *
81: * 88/07/11 Jim Napier
82: * Modified sput() to retry write if returns zero. This was causing an
83: * invalid prototype file to be created when using the Seagate ST-251
84: * hard disk which contains bad blocks.
85: */
86:
87: #include <sys/stat.h>
88: #include <sys/devices.h>
89: #include <sys/fdisk.h>
90: #include <sys/hdioctl.h>
91:
92: #define BUFSIZ 512
93: #define MAXUINT ((unsigned)65535L)
94: #define NULL ((char *)0)
95: #define TRUE (0 == 0)
96:
97: /*
98: * External functions.
99: */
100: extern long atol();
101: extern char *malloc();
102:
103: /*
104: * Forward referenced functions.
105: */
106: void bad();
107: void fatal();
108: void lput();
109: void sput();
110: void usage();
111:
112: /*
113: * Global variables.
114: */
115: char *bfile = "/conf/boot";
116: int bflag;
117: int oflag;
118: struct stat sb;
119: int vflag;
120:
121: /**
122: * main - validate number and type of arguments.
123: * - scan device (arg1) for bad blocks until lim (arg2) reached.
124: * - generate a mkfs prototype file on standard output or the
125: * designated protofile.
126: */
127: main(argc, argv) register int argc; register char *argv[];
128: {
129: register int n;
130: long bno;
131: long incr;
132: long lim;
133: long t0, t1;
134: int percent;
135: int nspt;
136: char *buf;
137: hdparm_t hdparms;
138: unsigned int tracksize;
139: unsigned long base;
140:
141: /*
142: * Read options declared.
143: */
144: while((--argc > 0) && ((*++argv)[0] == '-')) {
145:
146: if((*argv)[2] != '\0')
147: usage();
148:
149: switch((*argv)[1]) {
150:
151: case 'v':
152: if(vflag)
153: usage();
154: vflag = TRUE;
155: break;
156:
157: case 'o':
158: if(oflag || (--argc <= 0))
159: usage();
160: oflag = TRUE;
161:
162: /*
163: * Open protofile to store badscan information.
164: */
165: close(1);
166: if(creat(*++argv, 0644) == -1)
167: fatal("cannot create ", *argv);
168: break;
169:
170: case 'b':
171: if(bflag || (--argc <= 0))
172: usage();
173:
174: bflag = TRUE;
175: /*
176: * Set boot file name.
177: */
178: bfile = *++argv;
179: break;
180:
181: default:
182: usage();
183: break;
184: }
185: }
186:
187: /*
188: * Check to ensure that only arg1 and arg2 are available.
189: */
190: if (argc != 2)
191: usage();
192:
193: /*
194: * The first argument not associated with an option must be a
195: * character or block special file.
196: */
197: if (stat(argv[0], &sb) < 0)
198: fatal("cannot stat: ", argv[0]);
199: sb.st_mode &= S_IFMT;
200: if ((sb.st_mode != S_IFCHR) && (sb.st_mode != S_IFBLK))
201: fatal("not a device special file: ", argv[0]);
202: if ((n = major(sb.st_rdev)) == SCSI_MAJOR)
203: sput(2, "badscan: warning: SCSI devices do not require badscan\n");
204: else if (n != AT_MAJOR && n != FL_MAJOR)
205: fatal("not a disk device: ", argv[0]);
206:
207: /*
208: * Open the special file (arg1).
209: * Find the size of a track.
210: */
211: close(0);
212: if (open(argv[0], 0) == -1)
213: fatal("cannot open: ", argv[0]);
214: if (n == AT_MAJOR) {
215: /* Get hard disk track size with ioctl. */
216: if (ioctl(0, HDGETA, (char *)&hdparms) == -1)
217: fatal("cannot get disk device parameters: ", argv[0]);
218: tracksize = hdparms.nspt;
219: } else {
220: /* Badscan a floppy disk or a SCSI disk. */
221: /* Floppy ioctl FDGETA should be implemented but is not (yet). */
222: #if 0
223: /* Kludge: this code knows floppy minor to tracksize mapping. */
224: n = minor(sb.st_rdev) & 7;
225: if (n < 3) /* minor 0, 1, 2, 8, 9, 10, ... */
226: tracksize = 8;
227: else if (n < 6) /* minor 3, 4, 5, 11, 12, 13, ... */
228: tracksize = 9;
229: else if (n == 6) /* minor 6, 14, ... */
230: tracksize = 15;
231: else /* minor 7, 15, ... */
232: fatal("unsupported minor number", argv[0]);
233: #else
234: /* Scan block by block for now. */
235: tracksize = 1;
236: #endif
237: }
238:
239: /*
240: * Allocate a track buffer.
241: */
242: if (tracksize > MAXUINT/BUFSIZ || (buf = malloc(tracksize * BUFSIZ)) == NULL)
243: fatal("cannot allocate track buffer", "");
244:
245: /*
246: * Validate and evaluate length (arg2)
247: */
248: lim = atol(argv[1]);
249: if (lim <= 0) {
250:
251: register struct hdisk_s *hp;
252: int f2;
253:
254: if ((f2 = open(argv[1], 0)) < 0)
255: fatal("bad size: ", argv[1]);
256: if (read(f2, buf, 512) != 512)
257: fatal("cannot read: ", argv[1]);
258: close(f2);
259: hp = buf;
260: if (hp->hd_sig != HDSIG)
261: fatal("bad partition table: ", argv[1]);
262: lim = hp->hd_partn[ sb.st_rdev & 3 ].p_size;
263: base = hp->hd_partn[ sb.st_rdev & 3 ].p_base;
264: nspt = tracksize - base % tracksize;
265: if (lim <= 0)
266: fatal("null partition: ", argv[1]);
267: }
268:
269: /*
270: * Create header for mkfs prototype file.
271: */
272: sput(1, bfile);
273: sput(1, "\n");
274: lput(1, lim);
275: sput(1, " ");
276: lput(1, (lim/6 + 7) & ~7L); /* ensure ninode is multiple of 8 */
277: percent = 10;
278: incr = lim / 10;
279: time(&t0);
280:
281: /*
282: * Scan for bad blocks.
283: * The first and last tracks may have less than tracksize sectors.
284: */
285: for (bno=0; bno < lim; (bno += nspt), (nspt = tracksize)) {
286:
287: /*
288: * Try a track read first.
289: */
290: lseek(0, bno * BUFSIZ, 0);
291:
292: /*
293: * Avoid reading past end of partition.
294: */
295: if (bno + nspt > lim)
296: nspt = lim - bno;
297:
298: /* Mark each block in a bad track as bad. */
299: if (read(0, buf, (nspt * BUFSIZ)) != (nspt * BUFSIZ))
300: for (n=0; n < nspt; ++n)
301: bad(bno+n);
302:
303: /*
304: * Periodically generate reports
305: */
306: if (vflag && (bno >= incr) && (bno < lim)) {
307:
308: /*
309: * Estimate seconds remaining to next 1/10 minute.
310: */
311: time(&t1);
312: t1 = (t1 - t0) * (100 - percent);
313: t1 += percent - 1;
314: t1 /= percent;
315: t1 += 5;
316:
317: lput(2, (long) percent);
318: sput(2, "% done: ");
319: if (t1 < 6000)
320: sput(2, " ");
321: if (t1 < 600)
322: sput(2, " ");
323: lput(2, t1 / 60);
324: sput(2, ".");
325: lput(2, (t1 % 60) / 6);
326: sput(2, " minutes remaining...\r");
327:
328: percent += 10;
329: incr = (lim * percent) / 100;
330: }
331: }
332: sput(2, "Done. \n");
333: sput(1, "\nd--755 0 0\n$\n");
334: exit(0);
335: }
336:
337: /**
338: * void
339: * bad(n)
340: * long n;
341: * Input: n - bad block location.
342: * Action: Flag block n as being bad.
343: * Return: None.
344: * Note: None.
345: */
346: void
347: bad(n) register long n;
348: {
349: static int nbad = 0;
350: static long last = -1;
351:
352: if ((last+1) != n)
353: nbad = 0;
354: last = n;
355: if ((nbad & 7) == 0)
356: sput(1, "\n%b");
357: sput(1, " ");
358: lput(1, n);
359: ++nbad;
360: }
361:
362: /**
363: * void
364: * fatal(s1, s2)
365: * char * s1, *s2;
366: * Input: s1, s2 - pointer to error message strings.
367: * Action: Print fatal message, terminate with extreme prejudice.
368: * Return: Never return. Always exit.
369: * Note: None.
370: */
371: void
372: fatal(s1, s2) char * s1, * s2;
373: {
374: sput(2, "badscan: ");
375: sput(2, s1);
376: sput(2, s2);
377: sput(2, "\n");
378: exit(1);
379: }
380:
381: /**
382: * void
383: * lput(fd, num)
384: * int fd;
385: * unsigned long num;
386: *
387: * Input: fd - output file descriptor.
388: * num -
389: * Action: Convert long num to ascii string sent to file fd.
390: * Return: None.
391: * Note: None.
392: */
393: void
394: lput(fd, num) int fd; unsigned long num;
395: {
396: register char * cp;
397: static char buf[16];
398:
399: cp = &buf[15];
400:
401: /*
402: * Compute character equivalent value of long num.
403: */
404: do {
405: *--cp = (num % 10) + '0';
406: } while (num /= 10);
407: sput(fd, cp);
408: }
409:
410: /**
411: * void
412: * sput(fd, s)
413: * int fd;
414: * char * s;
415: *
416: * Input: fd - output file descriptor.
417: * s - pointer to character string.
418: * Action: Write string s to file descriptor fd.
419: * Return: None.
420: * Note: None.
421: */
422: void
423: sput(fd, s) int fd; register char * s;
424: {
425: register char * cp;
426: int i,j;
427:
428: /*
429: * Get location of end of string.
430: */
431: for (cp = s; *cp != '\0'; ++cp)
432: ;
433:
434: /* WRITE WITH RETRY IF WRITE() RETURNS 0 */
435: i = cp-s;
436: while ((j = write(fd, s, i)) == 0) ;
437:
438: }
439:
440: /**
441: * void
442: * usage()
443: * Input: None.
444: * Action: Display command format.
445: * return: None.
446: * Note: None.
447: */
448: void
449: usage()
450: {
451: fatal( "Usage: badscan [-v] [-o proto] [-b boot] dev size\n",
452: " badscan [-v] [-o proto] [-b boot] dev sdev");
453: }
454:
455: /* end of badscan.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.