|
|
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.