date and time created 88/07/22 16:08:01 by bostic
[unix-history] / usr / src / usr.sbin / bad144 / bad144.c
index b0218e2..7e9cd6d 100644 (file)
@@ -1,17 +1,28 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1980,1986,1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+"@(#) Copyright (c) 1980,1986,1988 Regents of the University of California.\n\
  All rights reserved.\n";
 #endif not lint
 
 #ifndef lint
  All rights reserved.\n";
 #endif not lint
 
 #ifndef lint
-static char sccsid[] = "@(#)bad144.c   5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)bad144.c   5.15 (Berkeley) %G%";
 #endif not lint
 
 /*
 #endif not lint
 
 /*
@@ -28,21 +39,32 @@ static char sccsid[] = "@(#)bad144.c        5.1 (Berkeley) %G%";
  * RP06 sectors are marked as bad by inverting the format bit in the
  * header; on other drives the valid-sector bit is cleared.
  */
  * RP06 sectors are marked as bad by inverting the format bit in the
  * header; on other drives the valid-sector bit is cleared.
  */
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/dkbad.h>
 #include <sys/ioctl.h>
 #include <sys/dkbad.h>
 #include <sys/ioctl.h>
+#include <sys/fs.h>
 #include <sys/file.h>
 #include <sys/file.h>
-#include <machine/dkio.h>
 
 #include <stdio.h>
 
 #include <stdio.h>
-#include <disktab.h>
+#include <sys/disklabel.h>
 
 
-int    fflag, add, copy, verbose;
+#define RETRIES        10              /* number of retries on reading old sectors */
+#define        RAWPART "c"             /* disk partition containing badsector tables */
+
+int    fflag, add, copy, verbose, nflag;
 int    compare();
 int    compare();
-struct dkbad dkbad, oldbad;
+int    dups;
+int    badfile = -1;           /* copy of badsector table to use, -1 if any */
+#define MAXSECSIZE     1024
+struct dkbad curbad, oldbad;
+#define        DKBAD_MAGIC     0
+
+char   label[BBSIZE];
 daddr_t        size, getold(), badsn();
 daddr_t        size, getold(), badsn();
-struct disktab *dp;
+struct disklabel *dp;
 char   name[BUFSIZ];
 char   name[BUFSIZ];
+char   *malloc();
+off_t  lseek();
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
@@ -57,9 +79,11 @@ main(argc, argv)
                (*argv)++;
                while (**argv) {
                        switch (**argv) {
                (*argv)++;
                while (**argv) {
                        switch (**argv) {
+#if vax
                            case 'f':
                                fflag++;
                                break;
                            case 'f':
                                fflag++;
                                break;
+#endif
                            case 'a':
                                add++;
                                break;
                            case 'a':
                                add++;
                                break;
@@ -69,58 +93,81 @@ main(argc, argv)
                            case 'v':
                                verbose++;
                                break;
                            case 'v':
                                verbose++;
                                break;
+                           case 'n':
+                               nflag++;
+                               verbose++;
+                               break;
+                           default:
+                               if (**argv >= '0' && **argv <= '4') {
+                                       badfile = **argv - '0';
+                                       break;
+                               }
+                               goto usage;
                        }
                        (*argv)++;
                }
                argc--, argv++;
        }
                        }
                        (*argv)++;
                }
                argc--, argv++;
        }
-       if (argc < 2) {
+       if (argc < 1) {
+usage:
                fprintf(stderr,
                fprintf(stderr,
-                 "usage: bad144 [ -f ] type disk [ snum [ bn ... ] ]\n");
+                 "usage: bad144 [ -f ] disk [ snum [ bn ... ] ]\n");
                fprintf(stderr,
                fprintf(stderr,
-             "to read or overwrite bad-sector table, e.g.: bad144 rk07 hk0\n");
+             "to read or overwrite bad-sector table, e.g.: bad144 hp0\n");
                fprintf(stderr,
                fprintf(stderr,
-                 "or bad144 -a [ -f ] [ -c ] type disk  bn ...\n");
+                 "or bad144 -a [ -f ] [ -c ] disk  bn ...\n");
                fprintf(stderr, "where options are:\n");
                fprintf(stderr, "\t-a  add new bad sectors to the table\n");
                fprintf(stderr, "\t-f  reformat listed sectors as bad\n");
                fprintf(stderr, "\t-c  copy original sector to replacement\n");
                exit(1);
        }
                fprintf(stderr, "where options are:\n");
                fprintf(stderr, "\t-a  add new bad sectors to the table\n");
                fprintf(stderr, "\t-f  reformat listed sectors as bad\n");
                fprintf(stderr, "\t-c  copy original sector to replacement\n");
                exit(1);
        }
-       dp = getdiskbyname(argv[0]);
-       if (dp == NULL) {
-               fprintf(stderr, "%s: unknown disk type\n", argv[0]);
+       if (argv[0][0] != '/')
+               (void)sprintf(name, "/dev/r%s%s", argv[0], RAWPART);
+       else
+               strcpy(name, argv[0]);
+       f = open(name, argc == 1? O_RDONLY : O_RDWR);
+       if (f < 0)
+               Perror(name);
+       if (read(f, label, sizeof(label)) < 0) 
+               Perror("read");
+       for (dp = (struct disklabel *)(label + LABELOFFSET);
+           dp < (struct disklabel *)
+               (label + sizeof(label) - sizeof(struct disklabel));
+           dp = (struct disklabel *)((char *)dp + 64))
+               if (dp->d_magic == DISKMAGIC && dp->d_magic2 == DISKMAGIC)
+                       break;
+       if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC) {
+               fprintf(stderr, "Bad pack magic number (pack is unlabeled)\n");
                exit(1);
        }
                exit(1);
        }
-       if (argv[1][0] != '/')
-               sprintf(name, "/dev/r%sc", argv[1]);
-       else
-               strcpy(name, argv[1]);
-       argc -= 2;
-       argv += 2;
+       if (dp->d_secsize > MAXSECSIZE || dp->d_secsize <= 0) {
+               fprintf(stderr, "Disk sector size too large/small (%d)\n",
+                       dp->d_secsize);
+               exit(7);
+       }
        size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; 
        size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; 
+       argc--;
+       argv++;
        if (argc == 0) {
        if (argc == 0) {
-               f = open(name, O_RDONLY);
-               if (f < 0)
-                       Perror(name);
-               sn = getold(f, &dkbad);
+               sn = getold(f, &oldbad);
                printf("bad block information at sector %d in %s:\n",
                    sn, name);
                printf("bad block information at sector %d in %s:\n",
                    sn, name);
-               printf("cartridge serial number: %d(10)\n", dkbad.bt_csn);
-               switch (dkbad.bt_flag) {
+               printf("cartridge serial number: %d(10)\n", oldbad.bt_csn);
+               switch (oldbad.bt_flag) {
 
 
-               case -1:
+               case (u_short)-1:
                        printf("alignment cartridge\n");
                        break;
 
                        printf("alignment cartridge\n");
                        break;
 
-               case 0:
+               case DKBAD_MAGIC:
                        break;
 
                default:
                        break;
 
                default:
-                       printf("bt_flag=%x(16)?\n", dkbad.bt_flag);
+                       printf("bt_flag=%x(16)?\n", oldbad.bt_flag);
                        break;
                }
                        break;
                }
-               bt = dkbad.bt_bad;
+               bt = oldbad.bt_bad;
                for (i = 0; i < 126; i++) {
                        bad = (bt->bt_cyl<<16) + bt->bt_trksec;
                        if (bad < 0)
                for (i = 0; i < 126; i++) {
                        bad = (bt->bt_cyl<<16) + bt->bt_trksec;
                        if (bad < 0)
@@ -129,11 +176,9 @@ main(argc, argv)
                            bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
                        bt++;
                }
                            bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
                        bt++;
                }
+               (void) checkold(&oldbad);
                exit(0);
        }
                exit(0);
        }
-       f = open(name, (fflag || add)? O_RDWR: O_WRONLY);
-       if (f < 0)
-               Perror(name);
        if (add) {
                /*
                 * Read in the old badsector table.
        if (add) {
                /*
                 * Read in the old badsector table.
@@ -141,20 +186,21 @@ main(argc, argv)
                 * are in order.  Copy the old table to the new one.
                 */
                (void) getold(f, &oldbad);
                 * are in order.  Copy the old table to the new one.
                 */
                (void) getold(f, &oldbad);
-               i = checkold();
+               i = checkold(&oldbad);
                if (verbose)
                if (verbose)
-                       printf("Had %d bad sectors\n", i);
+                       printf("Had %d bad sectors, adding %d\n", i, argc);
                if (i + argc > 126) {
                        printf("bad144: not enough room for %d more sectors\n",
                                argc);
                        printf("limited to 126 by information format\n");
                        exit(1);
                }
                if (i + argc > 126) {
                        printf("bad144: not enough room for %d more sectors\n",
                                argc);
                        printf("limited to 126 by information format\n");
                        exit(1);
                }
-               dkbad = oldbad;
+               curbad = oldbad;
        } else {
        } else {
-               dkbad.bt_csn = atoi(*argv++);
+               curbad.bt_csn = atoi(*argv++);
                argc--;
                argc--;
-               dkbad.bt_mbz = 0;
+               curbad.bt_mbz = 0;
+               curbad.bt_flag = DKBAD_MAGIC;
                if (argc > 126) {
                        printf("bad144: too many bad sectors specified\n");
                        printf("limited to 126 by information format\n");
                if (argc > 126) {
                        printf("bad144: too many bad sectors specified\n");
                        printf("limited to 126 by information format\n");
@@ -168,15 +214,15 @@ main(argc, argv)
                daddr_t sn = atoi(*argv++);
                argc--;
                if (sn < 0 || sn >= size) {
                daddr_t sn = atoi(*argv++);
                argc--;
                if (sn < 0 || sn >= size) {
-                       printf("%d: out of range [0,%d) for %s\n",
-                           sn, size, dp->d_name);
+                       printf("%d: out of range [0,%d) for disk %s\n",
+                           sn, size, dp->d_typename);
                        errs++;
                        continue;
                }
                bn[i] = sn;
                        errs++;
                        continue;
                }
                bn[i] = sn;
-               dkbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks);
+               curbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks);
                sn %= (dp->d_nsectors*dp->d_ntracks);
                sn %= (dp->d_nsectors*dp->d_ntracks);
-               dkbad.bt_bad[i].bt_trksec =
+               curbad.bt_bad[i].bt_trksec =
                    ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors);
                i++;
        }
                    ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors);
                i++;
        }
@@ -184,8 +230,8 @@ main(argc, argv)
                exit(1);
        nbad = i;
        while (i < 126) {
                exit(1);
        nbad = i;
        while (i < 126) {
-               dkbad.bt_bad[i].bt_trksec = -1;
-               dkbad.bt_bad[i].bt_cyl = -1;
+               curbad.bt_bad[i].bt_trksec = -1;
+               curbad.bt_bad[i].bt_cyl = -1;
                i++;
        }
        if (add) {
                i++;
        }
        if (add) {
@@ -194,25 +240,46 @@ main(argc, argv)
                 * Then shuffle the replacement sectors so that
                 * the previous bad sectors get the same replacement data.
                 */
                 * Then shuffle the replacement sectors so that
                 * the previous bad sectors get the same replacement data.
                 */
-               qsort(dkbad.bt_bad, nbad, sizeof (struct bt_bad), compare);
+               qsort((char *)curbad.bt_bad, nbad, sizeof (struct bt_bad),
+                   compare);
+               if (dups) {
+                       fprintf(stderr,
+"bad144: bad sectors have been duplicated; can't add existing sectors\n");
+                       exit(3);
+               }
                shift(f, nbad, nbad-new);
        }
                shift(f, nbad, nbad-new);
        }
-       for (i = 0; i < 10; i += 2) {
+       if (badfile == -1)
+               i = 0;
+       else
+               i = badfile * 2;
+       for (; i < 10 && i < dp->d_nsectors; i += 2) {
                if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i),
                    L_SET) < 0)
                        Perror("lseek");
                if (verbose)
                        printf("write badsect file at %d\n",
                                size - dp->d_nsectors + i);
                if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i),
                    L_SET) < 0)
                        Perror("lseek");
                if (verbose)
                        printf("write badsect file at %d\n",
                                size - dp->d_nsectors + i);
-               if (write(f, (caddr_t)&dkbad, sizeof dkbad) != sizeof dkbad) {
+               if (nflag == 0 && write(f, (caddr_t)&curbad, sizeof(curbad)) !=
+                   sizeof(curbad)) {
                        char msg[80];
                        char msg[80];
-                       sprintf(msg, "bad144: write bad sector file %d", i/2);
+                       (void)sprintf(msg, "bad144: write bad sector file %d",
+                           i/2);
                        perror(msg);
                }
                        perror(msg);
                }
+               if (badfile != -1)
+                       break;
        }
        }
-       if (fflag)
-               for (i = 0; i < new; i++)
+#ifdef vax
+       if (nflag == 0 && fflag)
+               for (i = nbad - new; i < nbad; i++)
                        format(f, bn[i]);
                        format(f, bn[i]);
+#endif
+#ifdef DIOCSBAD
+       if (nflag == 0 && ioctl(f, DIOCSBAD, (caddr_t)&curbad) < 0)
+               fprintf(stderr,
+       "Can't sync bad-sector file; reboot for changes to take effect\n");
+#endif
        exit(0);
 }
 
        exit(0);
 }
 
@@ -224,21 +291,27 @@ struct dkbad *bad;
        daddr_t sn;
        char msg[80];
 
        daddr_t sn;
        char msg[80];
 
-       for (i = 0; i < 10; i += 2) {
+       if (badfile == -1)
+               i = 0;
+       else
+               i = badfile * 2;
+       for (; i < 10 && i < dp->d_nsectors; i += 2) {
                sn = size - dp->d_nsectors + i;
                if (lseek(f, sn * dp->d_secsize, L_SET) < 0)
                        Perror("lseek");
                sn = size - dp->d_nsectors + i;
                if (lseek(f, sn * dp->d_secsize, L_SET) < 0)
                        Perror("lseek");
-               if (read(f, bad, sizeof (*bad)) == sizeof (*bad)) {
+               if (read(f, (char *) bad, dp->d_secsize) == dp->d_secsize) {
                        if (i > 0)
                                printf("Using bad-sector file %d\n", i/2);
                        return(sn);
                }
                        if (i > 0)
                                printf("Using bad-sector file %d\n", i/2);
                        return(sn);
                }
-               sprintf(msg, "bad144: read bad sector file at sn %d", sn);
+               (void)sprintf(msg, "bad144: read bad sector file at sn %d", sn);
                perror(msg);
                perror(msg);
+               if (badfile != -1)
+                       break;
        }
        }
-       fprintf(stderr,
-           "bad144: %s: can't read bad block info\n", name);
+       fprintf(stderr, "bad144: %s: can't read bad block info\n", name);
        exit(1);
        exit(1);
+       /*NOTREACHED*/
 }
 
 checkold()
 }
 
 checkold()
@@ -246,37 +319,51 @@ checkold()
        register int i;
        register struct bt_bad *bt;
        daddr_t sn, lsn;
        register int i;
        register struct bt_bad *bt;
        daddr_t sn, lsn;
+       int errors = 0, warned = 0;
 
 
-       if (oldbad.bt_flag != 0) {
+       if (oldbad.bt_flag != DKBAD_MAGIC) {
                fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n",
                        name);
                fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n",
                        name);
-               exit(1);
+               errors++;
        }
        if (oldbad.bt_mbz != 0) {
                fprintf(stderr, "bad144: %s: bad magic number\n", name);
        }
        if (oldbad.bt_mbz != 0) {
                fprintf(stderr, "bad144: %s: bad magic number\n", name);
-               exit(1);
+               errors++;
        }
        }
-       lsn = 0;
        bt = oldbad.bt_bad;
        for (i = 0; i < 126; i++, bt++) {
        bt = oldbad.bt_bad;
        for (i = 0; i < 126; i++, bt++) {
-               if (bt->bt_cyl == -1 && bt->bt_trksec == -1)
+               if (bt->bt_cyl == 0xffff && bt->bt_trksec == 0xffff)
                        break;
                if ((bt->bt_cyl >= dp->d_ncylinders) ||
                    ((bt->bt_trksec >> 8) >= dp->d_ntracks) ||
                    ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) {
                        break;
                if ((bt->bt_cyl >= dp->d_ncylinders) ||
                    ((bt->bt_trksec >> 8) >= dp->d_ntracks) ||
                    ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) {
-                       fprintf(stderr, "bad144: cyl/sect/trk out of range\n");
-                       exit(1);
+                       fprintf(stderr,
+                    "bad144: cyl/trk/sect out of range in existing entry: ");
+                       fprintf(stderr, "sn=%d, cn=%d, tn=%d, sn=%d\n",
+                               badsn(bt), bt->bt_cyl, bt->bt_trksec>>8,
+                               bt->bt_trksec & 0xff);
+                       errors++;
                }
                sn = (bt->bt_cyl * dp->d_ntracks +
                    (bt->bt_trksec >> 8)) *
                    dp->d_nsectors + (bt->bt_trksec & 0xff);
                }
                sn = (bt->bt_cyl * dp->d_ntracks +
                    (bt->bt_trksec >> 8)) *
                    dp->d_nsectors + (bt->bt_trksec & 0xff);
-               if (sn < lsn) {
-                   fprintf(stderr, "bad144: bad sector file out of order\n");
-                   exit(1);
+               if (i > 0 && sn < lsn && !warned) {
+                   fprintf(stderr,
+                       "bad144: bad sector file is out of order\n");
+                   errors++;
+                   warned++;
+               }
+               if (i > 0 && sn == lsn) {
+                   fprintf(stderr,
+                       "bad144: bad sector file contains duplicates (sn %d)\n",
+                       sn);
+                   errors++;
                }
                lsn = sn;
        }
                }
                lsn = sn;
        }
-       return i;
+       if (errors)
+               exit(1);
+       return (i);
 }
 
 /*
 }
 
 /*
@@ -295,14 +382,14 @@ shift(f, new, old)
        new--; old--;
        while (new >= 0 && new != old) {
                if (old < 0 ||
        new--; old--;
        while (new >= 0 && new != old) {
                if (old < 0 ||
-                   compare(&dkbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) {
+                   compare(&curbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) {
                        /*
                         * Insert new replacement here-- copy original
                         * sector if requested and possible,
                         * otherwise write a zero block.
                         */
                        if (!copy ||
                        /*
                         * Insert new replacement here-- copy original
                         * sector if requested and possible,
                         * otherwise write a zero block.
                         */
                        if (!copy ||
-                           !blkcopy(f, badsn(&dkbad.bt_bad[new]), repl - new))
+                           !blkcopy(f, badsn(&curbad.bt_bad[new]), repl - new))
                                blkzero(f, repl - new);
                } else {
                        if (blkcopy(f, repl - old, repl - new) == 0)
                                blkzero(f, repl - new);
                } else {
                        if (blkcopy(f, repl - old, repl - new) == 0)
@@ -315,47 +402,69 @@ shift(f, new, old)
        }
 }
 
        }
 }
 
+char *buf;
+
 /*
  *  Copy disk sector s1 to s2.
  */
 blkcopy(f, s1, s2)
 daddr_t s1, s2;
 {
 /*
  *  Copy disk sector s1 to s2.
  */
 blkcopy(f, s1, s2)
 daddr_t s1, s2;
 {
-       char buf[512];
+       register tries, n;
 
 
-       if (lseek(f, dp->d_secsize * s1, L_SET) < 0)
-               Perror("lseek");
-       if (read(f, buf, sizeof (buf)) != sizeof (buf)) {
-               if (verbose)
-                       fprintf(stderr, "bad144: can't read sector, %d\n", s1);
+       if (buf == (char *)NULL) {
+               buf = malloc((unsigned)dp->d_secsize);
+               if (buf == (char *)NULL) {
+                       fprintf(stderr, "Out of memory\n");
+                       exit(20);
+               }
+       }
+       for (tries = 0; tries < RETRIES; tries++) {
+               if (lseek(f, dp->d_secsize * s1, L_SET) < 0)
+                       Perror("lseek");
+               if ((n = read(f, buf, dp->d_secsize)) == dp->d_secsize)
+                       break;
+       }
+       if (n != dp->d_secsize) {
+               fprintf(stderr, "bad144: can't read sector, %d: ", s1);
+               if (n < 0)
+                       perror((char *)0);
                return(0);
        }
        if (lseek(f, dp->d_secsize * s2, L_SET) < 0)
                Perror("lseek");
        if (verbose)
                printf("copying %d to %d\n", s1, s2);
                return(0);
        }
        if (lseek(f, dp->d_secsize * s2, L_SET) < 0)
                Perror("lseek");
        if (verbose)
                printf("copying %d to %d\n", s1, s2);
-       if (write(f, buf, sizeof (buf)) != sizeof (buf)) {
+       if (nflag == 0 && write(f, buf, dp->d_secsize) != dp->d_secsize) {
                fprintf(stderr,
                fprintf(stderr,
-                   "bad144: can't write replacement sector, %d\n", s2);
+                   "bad144: can't write replacement sector, %d: ", s2);
+               perror((char *)0);
                return(0);
        }
        return(1);
 }
 
                return(0);
        }
        return(1);
 }
 
-char zbuf[512];
+char *zbuf;
 
 blkzero(f, sn)
 daddr_t sn;
 {
 
 
 blkzero(f, sn)
 daddr_t sn;
 {
 
+       if (zbuf == (char *)NULL) {
+               zbuf = malloc((unsigned)dp->d_secsize);
+               if (zbuf == (char *)NULL) {
+                       fprintf(stderr, "Out of memory\n");
+                       exit(20);
+               }
+       }
        if (lseek(f, dp->d_secsize * sn, L_SET) < 0)
                Perror("lseek");
        if (verbose)
                printf("zeroing %d\n", sn);
        if (lseek(f, dp->d_secsize * sn, L_SET) < 0)
                Perror("lseek");
        if (verbose)
                printf("zeroing %d\n", sn);
-       if (write(f, zbuf, sizeof (zbuf)) != sizeof (zbuf)) {
+       if (nflag == 0 && write(f, zbuf, dp->d_secsize) != dp->d_secsize) {
                fprintf(stderr,
                fprintf(stderr,
-                   "bad144: can't write replacement sector, %d\n", sn);
-               exit(1);
+                   "bad144: can't write replacement sector, %d", sn);
+               perror((char *)0);
        }
 }
 
        }
 }
 
@@ -366,7 +475,9 @@ register struct bt_bad *b1, *b2;
                return(1);
        if (b1->bt_cyl < b2->bt_cyl)
                return(-1);
                return(1);
        if (b1->bt_cyl < b2->bt_cyl)
                return(-1);
-       return (b2->bt_trksec - b1->bt_trksec);
+       if (b1->bt_trksec == b2->bt_trksec)
+               dups++;
+       return (b1->bt_trksec - b2->bt_trksec);
 }
 
 daddr_t
 }
 
 daddr_t
@@ -377,6 +488,9 @@ register struct bt_bad *bt;
                + (bt->bt_trksec&0xff));
 }
 
                + (bt->bt_trksec&0xff));
 }
 
+#ifdef vax
+#include <machine/dkio.h>
+
 struct rp06hdr {
        short   h_cyl;
        short   h_trksec;
 struct rp06hdr {
        short   h_cyl;
        short   h_trksec;
@@ -392,10 +506,13 @@ struct rp06hdr {
  */
 struct hpuphdr {
        u_short hpup_cyl;
  */
 struct hpuphdr {
        u_short hpup_cyl;
-       u_short hpup_trksec;
+       u_char  hpup_sect;
+       u_char  hpup_track;
        char    hpup_data[512];
 #define        HPUP_OKSECT     0xc000          /* this normally means sector is good */
        char    hpup_data[512];
 #define        HPUP_OKSECT     0xc000          /* this normally means sector is good */
+#define        HPUP_16BIT      0x1000          /* 1 == 16 bit format */
 };
 };
+int rp06format(), hpupformat();
 
 struct formats {
        char    *f_name;                /* disk name */
 
 struct formats {
        char    *f_name;                /* disk name */
@@ -403,36 +520,83 @@ struct    formats {
        int     f_bic;                  /* value to bic in hpup_cyl */
        int     (*f_routine)();         /* routine for special handling */
 } formats[] = {
        int     f_bic;                  /* value to bic in hpup_cyl */
        int     (*f_routine)();         /* routine for special handling */
 } formats[] = {
-       { "rp06",       sizeof (struct rp06hdr),        RP06_FMT,       0 },
-       { "eagle",      sizeof (struct hpuphdr),        HPUP_OKSECT,    0 },
-       { "capricorn",  sizeof (struct hpuphdr),        HPUP_OKSECT,    0 },
-       { "rm03",       sizeof (struct hpuphdr),        HPUP_OKSECT,    0 },
-       { "rm05",       sizeof (struct hpuphdr),        HPUP_OKSECT,    0 },
-       { "9300",       sizeof (struct hpuphdr),        HPUP_OKSECT,    0 },
-       { "9766",       sizeof (struct hpuphdr),        HPUP_OKSECT,    0 },
+       { "rp06",       sizeof (struct rp06hdr), RP06_FMT,      rp06format },
+       { "eagle",      sizeof (struct hpuphdr), HPUP_OKSECT,   hpupformat },
+       { "capricorn",  sizeof (struct hpuphdr), HPUP_OKSECT,   hpupformat },
+       { "rm03",       sizeof (struct hpuphdr), HPUP_OKSECT,   hpupformat },
+       { "rm05",       sizeof (struct hpuphdr), HPUP_OKSECT,   hpupformat },
+       { "9300",       sizeof (struct hpuphdr), HPUP_OKSECT,   hpupformat },
+       { "9766",       sizeof (struct hpuphdr), HPUP_OKSECT,   hpupformat },
        { 0, 0, 0, 0 }
 };
 
        { 0, 0, 0, 0 }
 };
 
+/*ARGSUSED*/
+hpupformat(fp, dp, blk, buf, count)
+       struct formats *fp;
+       struct disklabel *dp;
+       daddr_t blk;
+       char *buf;
+       int count;
+{
+       struct hpuphdr *hdr = (struct hpuphdr *)buf;
+       int sect;
+
+       if (count < sizeof(struct hpuphdr)) {
+               hdr->hpup_cyl = (HPUP_OKSECT | HPUP_16BIT) |
+                       (blk / (dp->d_nsectors * dp->d_ntracks));
+               sect = blk % (dp->d_nsectors * dp->d_ntracks);
+               hdr->hpup_track = (u_char)(sect / dp->d_nsectors);
+               hdr->hpup_sect = (u_char)(sect % dp->d_nsectors);
+       }
+       return (0);
+}
+
+/*ARGSUSED*/
+rp06format(fp, dp, blk, buf, count)
+       struct formats *fp;
+       struct disklabel *dp;
+       daddr_t blk;
+       char *buf;
+       int count;
+{
+
+       if (count < sizeof(struct rp06hdr)) {
+               fprintf(stderr, "Can't read header on blk %d, can't reformat\n",
+                       blk);
+               return (-1);
+       }
+       return (0);
+}
+
 format(fd, blk)
        int fd;
        daddr_t blk;
 {
        register struct formats *fp;
 format(fd, blk)
        int fd;
        daddr_t blk;
 {
        register struct formats *fp;
-       char *buf, *malloc();
+       static char *buf;
+       static char bufsize;
+       struct format_op fop;
+       int n;
 
        for (fp = formats; fp->f_name; fp++)
 
        for (fp = formats; fp->f_name; fp++)
-               if (strcmp(dp->d_name, fp->f_name) == 0)
+               if (strcmp(dp->d_typename, fp->f_name) == 0)
                        break;
        if (fp->f_name == 0) {
                fprintf(stderr, "bad144: don't know how to format %s disks\n",
                        break;
        if (fp->f_name == 0) {
                fprintf(stderr, "bad144: don't know how to format %s disks\n",
-                       dp->d_name);
+                       dp->d_typename);
                exit(2);
        }
                exit(2);
        }
-       buf = malloc(fp->f_bufsize);
+       if (buf && bufsize < fp->f_bufsize) {
+               free(buf);
+               buf = NULL;
+       }
+       if (buf == NULL)
+               buf = malloc((unsigned)fp->f_bufsize);
        if (buf == NULL) {
                fprintf(stderr, "bad144: can't allocate sector buffer\n");
                exit(3);
        }
        if (buf == NULL) {
                fprintf(stderr, "bad144: can't allocate sector buffer\n");
                exit(3);
        }
+       bufsize = fp->f_bufsize;
        /*
         * Here we do the actual formatting.  All we really
         * do is rewrite the sector header and flag the bad sector
        /*
         * Here we do the actual formatting.  All we really
         * do is rewrite the sector header and flag the bad sector
@@ -440,30 +604,38 @@ format(fd, blk)
         * purpose format routine is specified, we allow it to
         * process the sector as well.
         */
         * purpose format routine is specified, we allow it to
         * process the sector as well.
         */
-       if (lseek(fd, (long)blk * 512, L_SET) < 0)
-               Perror("lseek");
        if (verbose)
                printf("format blk %d\n", blk);
        if (verbose)
                printf("format blk %d\n", blk);
-       if (ioctl(fd, DKIOCHDR, 0) < 0)
-               Perror("ioctl");
-       read(fd, buf, fp->f_bufsize);
+       bzero((char *)&fop, sizeof(fop));
+       fop.df_buf = buf;
+       fop.df_count = fp->f_bufsize;
+       fop.df_startblk = blk;
+       bzero(buf, fp->f_bufsize);
+       if (ioctl(fd, DIOCRFORMAT, &fop) < 0)
+               perror("bad144: read format");
+       if (fp->f_routine &&
+           (*fp->f_routine)(fp, dp, blk, buf, fop.df_count) != 0)
+               return;
        if (fp->f_bic) {
                struct hpuphdr *xp = (struct hpuphdr *)buf;
 
                xp->hpup_cyl &= ~fp->f_bic;
        }
        if (fp->f_bic) {
                struct hpuphdr *xp = (struct hpuphdr *)buf;
 
                xp->hpup_cyl &= ~fp->f_bic;
        }
-       if (fp->f_routine)
-               (*fp->f_routine)(fp, dp, blk, buf);
-       if (lseek(fd, (long)blk * 512, L_SET) < 0)
-               Perror("lseek");
-       if (ioctl(fd, DKIOCHDR, 0) < 0)
-               Perror("ioctl");
-       if (write(fd, buf, fp->f_bufsize) != fp->f_bufsize) {
+       if (nflag)
+               return;
+       bzero((char *)&fop, sizeof(fop));
+       fop.df_buf = buf;
+       fop.df_count = fp->f_bufsize;
+       fop.df_startblk = blk;
+       if (ioctl(fd, DIOCWFORMAT, &fop) < 0)
+               Perror("write format");
+       if (fop.df_count != fp->f_bufsize) {
                char msg[80];
                char msg[80];
-               sprintf(msg, "bad144: write format %d", blk);
+               (void)sprintf(msg, "bad144: write format %d", blk);
                perror(msg);
        }
 }
                perror(msg);
        }
 }
+#endif
 
 Perror(op)
        char *op;
 
 Perror(op)
        char *op;