Annotation of coherent/d/etc/badscan.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.