| 1 | /* |
| 2 | * Copyright (c) 1993, 198019861988 |
| 3 | * The Regents of the University of California. All rights reserved. |
| 4 | * |
| 5 | * %sccs.include.redist.c% |
| 6 | */ |
| 7 | |
| 8 | #ifndef lint |
| 9 | static char copyright[] = |
| 10 | "@(#) Copyright (c) 1993, 198019861988\n\ |
| 11 | The Regents of the University of California. All rights reserved.\n"; |
| 12 | #endif not lint |
| 13 | |
| 14 | #ifndef lint |
| 15 | static char sccsid[] = "@(#)bad144.c 8.1 (Berkeley) %G%"; |
| 16 | #endif not lint |
| 17 | |
| 18 | /* |
| 19 | * bad144 |
| 20 | * |
| 21 | * This program prints and/or initializes a bad block record for a pack, |
| 22 | * in the format used by the DEC standard 144. |
| 23 | * It can also add bad sector(s) to the record, moving the sector |
| 24 | * replacements as necessary. |
| 25 | * |
| 26 | * It is preferable to write the bad information with a standard formatter, |
| 27 | * but this program will do. |
| 28 | * |
| 29 | * RP06 sectors are marked as bad by inverting the format bit in the |
| 30 | * header; on other drives the valid-sector bit is cleared. |
| 31 | */ |
| 32 | #include <sys/param.h> |
| 33 | #include <sys/dkbad.h> |
| 34 | #include <sys/ioctl.h> |
| 35 | #include <sys/file.h> |
| 36 | #include <sys/disklabel.h> |
| 37 | #include <ufs/ffs/fs.h> |
| 38 | |
| 39 | #include <stdio.h> |
| 40 | #include <paths.h> |
| 41 | |
| 42 | #define RETRIES 10 /* number of retries on reading old sectors */ |
| 43 | #define RAWPART "c" /* disk partition containing badsector tables */ |
| 44 | |
| 45 | int fflag, add, copy, verbose, nflag; |
| 46 | int compare(); |
| 47 | int dups; |
| 48 | int badfile = -1; /* copy of badsector table to use, -1 if any */ |
| 49 | #define MAXSECSIZE 1024 |
| 50 | struct dkbad curbad, oldbad; |
| 51 | #define DKBAD_MAGIC 0 |
| 52 | |
| 53 | char label[BBSIZE]; |
| 54 | daddr_t size, getold(), badsn(); |
| 55 | struct disklabel *dp; |
| 56 | char name[BUFSIZ]; |
| 57 | char *malloc(); |
| 58 | off_t lseek(); |
| 59 | |
| 60 | main(argc, argv) |
| 61 | int argc; |
| 62 | char *argv[]; |
| 63 | { |
| 64 | register struct bt_bad *bt; |
| 65 | daddr_t sn, bn[126]; |
| 66 | int i, f, nbad, new, bad, errs; |
| 67 | |
| 68 | argc--, argv++; |
| 69 | while (argc > 0 && **argv == '-') { |
| 70 | (*argv)++; |
| 71 | while (**argv) { |
| 72 | switch (**argv) { |
| 73 | #if vax |
| 74 | case 'f': |
| 75 | fflag++; |
| 76 | break; |
| 77 | #endif |
| 78 | case 'a': |
| 79 | add++; |
| 80 | break; |
| 81 | case 'c': |
| 82 | copy++; |
| 83 | break; |
| 84 | case 'v': |
| 85 | verbose++; |
| 86 | break; |
| 87 | case 'n': |
| 88 | nflag++; |
| 89 | verbose++; |
| 90 | break; |
| 91 | default: |
| 92 | if (**argv >= '0' && **argv <= '4') { |
| 93 | badfile = **argv - '0'; |
| 94 | break; |
| 95 | } |
| 96 | goto usage; |
| 97 | } |
| 98 | (*argv)++; |
| 99 | } |
| 100 | argc--, argv++; |
| 101 | } |
| 102 | if (argc < 1) { |
| 103 | usage: |
| 104 | fprintf(stderr, |
| 105 | "usage: bad144 [ -f ] disk [ snum [ bn ... ] ]\n"); |
| 106 | fprintf(stderr, |
| 107 | "to read or overwrite bad-sector table, e.g.: bad144 hp0\n"); |
| 108 | fprintf(stderr, |
| 109 | "or bad144 -a [ -f ] [ -c ] disk bn ...\n"); |
| 110 | fprintf(stderr, "where options are:\n"); |
| 111 | fprintf(stderr, "\t-a add new bad sectors to the table\n"); |
| 112 | fprintf(stderr, "\t-f reformat listed sectors as bad\n"); |
| 113 | fprintf(stderr, "\t-c copy original sector to replacement\n"); |
| 114 | exit(1); |
| 115 | } |
| 116 | if (argv[0][0] != '/') |
| 117 | (void)sprintf(name, "%s/r%s%s", _PATH_DEV, argv[0], RAWPART); |
| 118 | else |
| 119 | strcpy(name, argv[0]); |
| 120 | f = open(name, argc == 1? O_RDONLY : O_RDWR); |
| 121 | if (f < 0) |
| 122 | Perror(name); |
| 123 | if (read(f, label, sizeof(label)) < 0) |
| 124 | Perror("read"); |
| 125 | for (dp = (struct disklabel *)(label + LABELOFFSET); |
| 126 | dp < (struct disklabel *) |
| 127 | (label + sizeof(label) - sizeof(struct disklabel)); |
| 128 | dp = (struct disklabel *)((char *)dp + 64)) |
| 129 | if (dp->d_magic == DISKMAGIC && dp->d_magic2 == DISKMAGIC) |
| 130 | break; |
| 131 | if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC) { |
| 132 | fprintf(stderr, "Bad pack magic number (pack is unlabeled)\n"); |
| 133 | exit(1); |
| 134 | } |
| 135 | if (dp->d_secsize > MAXSECSIZE || dp->d_secsize <= 0) { |
| 136 | fprintf(stderr, "Disk sector size too large/small (%d)\n", |
| 137 | dp->d_secsize); |
| 138 | exit(7); |
| 139 | } |
| 140 | size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders; |
| 141 | argc--; |
| 142 | argv++; |
| 143 | if (argc == 0) { |
| 144 | sn = getold(f, &oldbad); |
| 145 | printf("bad block information at sector %d in %s:\n", |
| 146 | sn, name); |
| 147 | printf("cartridge serial number: %d(10)\n", oldbad.bt_csn); |
| 148 | switch (oldbad.bt_flag) { |
| 149 | |
| 150 | case (u_short)-1: |
| 151 | printf("alignment cartridge\n"); |
| 152 | break; |
| 153 | |
| 154 | case DKBAD_MAGIC: |
| 155 | break; |
| 156 | |
| 157 | default: |
| 158 | printf("bt_flag=%x(16)?\n", oldbad.bt_flag); |
| 159 | break; |
| 160 | } |
| 161 | bt = oldbad.bt_bad; |
| 162 | for (i = 0; i < 126; i++) { |
| 163 | bad = (bt->bt_cyl<<16) + bt->bt_trksec; |
| 164 | if (bad < 0) |
| 165 | break; |
| 166 | printf("sn=%d, cn=%d, tn=%d, sn=%d\n", badsn(bt), |
| 167 | bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff); |
| 168 | bt++; |
| 169 | } |
| 170 | (void) checkold(&oldbad); |
| 171 | exit(0); |
| 172 | } |
| 173 | if (add) { |
| 174 | /* |
| 175 | * Read in the old badsector table. |
| 176 | * Verify that it makes sense, and the bad sectors |
| 177 | * are in order. Copy the old table to the new one. |
| 178 | */ |
| 179 | (void) getold(f, &oldbad); |
| 180 | i = checkold(&oldbad); |
| 181 | if (verbose) |
| 182 | printf("Had %d bad sectors, adding %d\n", i, argc); |
| 183 | if (i + argc > 126) { |
| 184 | printf("bad144: not enough room for %d more sectors\n", |
| 185 | argc); |
| 186 | printf("limited to 126 by information format\n"); |
| 187 | exit(1); |
| 188 | } |
| 189 | curbad = oldbad; |
| 190 | } else { |
| 191 | curbad.bt_csn = atoi(*argv++); |
| 192 | argc--; |
| 193 | curbad.bt_mbz = 0; |
| 194 | curbad.bt_flag = DKBAD_MAGIC; |
| 195 | if (argc > 126) { |
| 196 | printf("bad144: too many bad sectors specified\n"); |
| 197 | printf("limited to 126 by information format\n"); |
| 198 | exit(1); |
| 199 | } |
| 200 | i = 0; |
| 201 | } |
| 202 | errs = 0; |
| 203 | new = argc; |
| 204 | while (argc > 0) { |
| 205 | daddr_t sn = atoi(*argv++); |
| 206 | argc--; |
| 207 | if (sn < 0 || sn >= size) { |
| 208 | printf("%d: out of range [0,%d) for disk %s\n", |
| 209 | sn, size, dp->d_typename); |
| 210 | errs++; |
| 211 | continue; |
| 212 | } |
| 213 | bn[i] = sn; |
| 214 | curbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks); |
| 215 | sn %= (dp->d_nsectors*dp->d_ntracks); |
| 216 | curbad.bt_bad[i].bt_trksec = |
| 217 | ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors); |
| 218 | i++; |
| 219 | } |
| 220 | if (errs) |
| 221 | exit(1); |
| 222 | nbad = i; |
| 223 | while (i < 126) { |
| 224 | curbad.bt_bad[i].bt_trksec = -1; |
| 225 | curbad.bt_bad[i].bt_cyl = -1; |
| 226 | i++; |
| 227 | } |
| 228 | if (add) { |
| 229 | /* |
| 230 | * Sort the new bad sectors into the list. |
| 231 | * Then shuffle the replacement sectors so that |
| 232 | * the previous bad sectors get the same replacement data. |
| 233 | */ |
| 234 | qsort((char *)curbad.bt_bad, nbad, sizeof (struct bt_bad), |
| 235 | compare); |
| 236 | if (dups) { |
| 237 | fprintf(stderr, |
| 238 | "bad144: bad sectors have been duplicated; can't add existing sectors\n"); |
| 239 | exit(3); |
| 240 | } |
| 241 | shift(f, nbad, nbad-new); |
| 242 | } |
| 243 | if (badfile == -1) |
| 244 | i = 0; |
| 245 | else |
| 246 | i = badfile * 2; |
| 247 | for (; i < 10 && i < dp->d_nsectors; i += 2) { |
| 248 | if (lseek(f, dp->d_secsize * (size - dp->d_nsectors + i), |
| 249 | L_SET) < 0) |
| 250 | Perror("lseek"); |
| 251 | if (verbose) |
| 252 | printf("write badsect file at %d\n", |
| 253 | size - dp->d_nsectors + i); |
| 254 | if (nflag == 0 && write(f, (caddr_t)&curbad, sizeof(curbad)) != |
| 255 | sizeof(curbad)) { |
| 256 | char msg[80]; |
| 257 | (void)sprintf(msg, "bad144: write bad sector file %d", |
| 258 | i/2); |
| 259 | perror(msg); |
| 260 | } |
| 261 | if (badfile != -1) |
| 262 | break; |
| 263 | } |
| 264 | #ifdef vax |
| 265 | if (nflag == 0 && fflag) |
| 266 | for (i = nbad - new; i < nbad; i++) |
| 267 | format(f, bn[i]); |
| 268 | #endif |
| 269 | #ifdef DIOCSBAD |
| 270 | if (nflag == 0 && ioctl(f, DIOCSBAD, (caddr_t)&curbad) < 0) |
| 271 | fprintf(stderr, |
| 272 | "Can't sync bad-sector file; reboot for changes to take effect\n"); |
| 273 | #endif |
| 274 | exit(0); |
| 275 | } |
| 276 | |
| 277 | daddr_t |
| 278 | getold(f, bad) |
| 279 | struct dkbad *bad; |
| 280 | { |
| 281 | register int i; |
| 282 | daddr_t sn; |
| 283 | char msg[80]; |
| 284 | |
| 285 | if (badfile == -1) |
| 286 | i = 0; |
| 287 | else |
| 288 | i = badfile * 2; |
| 289 | for (; i < 10 && i < dp->d_nsectors; i += 2) { |
| 290 | sn = size - dp->d_nsectors + i; |
| 291 | if (lseek(f, sn * dp->d_secsize, L_SET) < 0) |
| 292 | Perror("lseek"); |
| 293 | if (read(f, (char *) bad, dp->d_secsize) == dp->d_secsize) { |
| 294 | if (i > 0) |
| 295 | printf("Using bad-sector file %d\n", i/2); |
| 296 | return(sn); |
| 297 | } |
| 298 | (void)sprintf(msg, "bad144: read bad sector file at sn %d", sn); |
| 299 | perror(msg); |
| 300 | if (badfile != -1) |
| 301 | break; |
| 302 | } |
| 303 | fprintf(stderr, "bad144: %s: can't read bad block info\n", name); |
| 304 | exit(1); |
| 305 | /*NOTREACHED*/ |
| 306 | } |
| 307 | |
| 308 | checkold() |
| 309 | { |
| 310 | register int i; |
| 311 | register struct bt_bad *bt; |
| 312 | daddr_t sn, lsn; |
| 313 | int errors = 0, warned = 0; |
| 314 | |
| 315 | if (oldbad.bt_flag != DKBAD_MAGIC) { |
| 316 | fprintf(stderr, "bad144: %s: bad flag in bad-sector table\n", |
| 317 | name); |
| 318 | errors++; |
| 319 | } |
| 320 | if (oldbad.bt_mbz != 0) { |
| 321 | fprintf(stderr, "bad144: %s: bad magic number\n", name); |
| 322 | errors++; |
| 323 | } |
| 324 | bt = oldbad.bt_bad; |
| 325 | for (i = 0; i < 126; i++, bt++) { |
| 326 | if (bt->bt_cyl == 0xffff && bt->bt_trksec == 0xffff) |
| 327 | break; |
| 328 | if ((bt->bt_cyl >= dp->d_ncylinders) || |
| 329 | ((bt->bt_trksec >> 8) >= dp->d_ntracks) || |
| 330 | ((bt->bt_trksec & 0xff) >= dp->d_nsectors)) { |
| 331 | fprintf(stderr, |
| 332 | "bad144: cyl/trk/sect out of range in existing entry: "); |
| 333 | fprintf(stderr, "sn=%d, cn=%d, tn=%d, sn=%d\n", |
| 334 | badsn(bt), bt->bt_cyl, bt->bt_trksec>>8, |
| 335 | bt->bt_trksec & 0xff); |
| 336 | errors++; |
| 337 | } |
| 338 | sn = (bt->bt_cyl * dp->d_ntracks + |
| 339 | (bt->bt_trksec >> 8)) * |
| 340 | dp->d_nsectors + (bt->bt_trksec & 0xff); |
| 341 | if (i > 0 && sn < lsn && !warned) { |
| 342 | fprintf(stderr, |
| 343 | "bad144: bad sector file is out of order\n"); |
| 344 | errors++; |
| 345 | warned++; |
| 346 | } |
| 347 | if (i > 0 && sn == lsn) { |
| 348 | fprintf(stderr, |
| 349 | "bad144: bad sector file contains duplicates (sn %d)\n", |
| 350 | sn); |
| 351 | errors++; |
| 352 | } |
| 353 | lsn = sn; |
| 354 | } |
| 355 | if (errors) |
| 356 | exit(1); |
| 357 | return (i); |
| 358 | } |
| 359 | |
| 360 | /* |
| 361 | * Move the bad sector replacements |
| 362 | * to make room for the new bad sectors. |
| 363 | * new is the new number of bad sectors, old is the previous count. |
| 364 | */ |
| 365 | shift(f, new, old) |
| 366 | { |
| 367 | daddr_t repl; |
| 368 | |
| 369 | /* |
| 370 | * First replacement is last sector of second-to-last track. |
| 371 | */ |
| 372 | repl = size - dp->d_nsectors - 1; |
| 373 | new--; old--; |
| 374 | while (new >= 0 && new != old) { |
| 375 | if (old < 0 || |
| 376 | compare(&curbad.bt_bad[new], &oldbad.bt_bad[old]) > 0) { |
| 377 | /* |
| 378 | * Insert new replacement here-- copy original |
| 379 | * sector if requested and possible, |
| 380 | * otherwise write a zero block. |
| 381 | */ |
| 382 | if (!copy || |
| 383 | !blkcopy(f, badsn(&curbad.bt_bad[new]), repl - new)) |
| 384 | blkzero(f, repl - new); |
| 385 | } else { |
| 386 | if (blkcopy(f, repl - old, repl - new) == 0) |
| 387 | fprintf(stderr, |
| 388 | "Can't copy replacement sector %d to %d\n", |
| 389 | repl-old, repl-new); |
| 390 | old--; |
| 391 | } |
| 392 | new--; |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | char *buf; |
| 397 | |
| 398 | /* |
| 399 | * Copy disk sector s1 to s2. |
| 400 | */ |
| 401 | blkcopy(f, s1, s2) |
| 402 | daddr_t s1, s2; |
| 403 | { |
| 404 | register tries, n; |
| 405 | |
| 406 | if (buf == (char *)NULL) { |
| 407 | buf = malloc((unsigned)dp->d_secsize); |
| 408 | if (buf == (char *)NULL) { |
| 409 | fprintf(stderr, "Out of memory\n"); |
| 410 | exit(20); |
| 411 | } |
| 412 | } |
| 413 | for (tries = 0; tries < RETRIES; tries++) { |
| 414 | if (lseek(f, dp->d_secsize * s1, L_SET) < 0) |
| 415 | Perror("lseek"); |
| 416 | if ((n = read(f, buf, dp->d_secsize)) == dp->d_secsize) |
| 417 | break; |
| 418 | } |
| 419 | if (n != dp->d_secsize) { |
| 420 | fprintf(stderr, "bad144: can't read sector, %d: ", s1); |
| 421 | if (n < 0) |
| 422 | perror((char *)0); |
| 423 | return(0); |
| 424 | } |
| 425 | if (lseek(f, dp->d_secsize * s2, L_SET) < 0) |
| 426 | Perror("lseek"); |
| 427 | if (verbose) |
| 428 | printf("copying %d to %d\n", s1, s2); |
| 429 | if (nflag == 0 && write(f, buf, dp->d_secsize) != dp->d_secsize) { |
| 430 | fprintf(stderr, |
| 431 | "bad144: can't write replacement sector, %d: ", s2); |
| 432 | perror((char *)0); |
| 433 | return(0); |
| 434 | } |
| 435 | return(1); |
| 436 | } |
| 437 | |
| 438 | char *zbuf; |
| 439 | |
| 440 | blkzero(f, sn) |
| 441 | daddr_t sn; |
| 442 | { |
| 443 | |
| 444 | if (zbuf == (char *)NULL) { |
| 445 | zbuf = malloc((unsigned)dp->d_secsize); |
| 446 | if (zbuf == (char *)NULL) { |
| 447 | fprintf(stderr, "Out of memory\n"); |
| 448 | exit(20); |
| 449 | } |
| 450 | } |
| 451 | if (lseek(f, dp->d_secsize * sn, L_SET) < 0) |
| 452 | Perror("lseek"); |
| 453 | if (verbose) |
| 454 | printf("zeroing %d\n", sn); |
| 455 | if (nflag == 0 && write(f, zbuf, dp->d_secsize) != dp->d_secsize) { |
| 456 | fprintf(stderr, |
| 457 | "bad144: can't write replacement sector, %d: ", sn); |
| 458 | perror((char *)0); |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | compare(b1, b2) |
| 463 | register struct bt_bad *b1, *b2; |
| 464 | { |
| 465 | if (b1->bt_cyl > b2->bt_cyl) |
| 466 | return(1); |
| 467 | if (b1->bt_cyl < b2->bt_cyl) |
| 468 | return(-1); |
| 469 | if (b1->bt_trksec == b2->bt_trksec) |
| 470 | dups++; |
| 471 | return (b1->bt_trksec - b2->bt_trksec); |
| 472 | } |
| 473 | |
| 474 | daddr_t |
| 475 | badsn(bt) |
| 476 | register struct bt_bad *bt; |
| 477 | { |
| 478 | return ((bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) * dp->d_nsectors |
| 479 | + (bt->bt_trksec&0xff)); |
| 480 | } |
| 481 | |
| 482 | #ifdef vax |
| 483 | |
| 484 | struct rp06hdr { |
| 485 | short h_cyl; |
| 486 | short h_trksec; |
| 487 | short h_key1; |
| 488 | short h_key2; |
| 489 | char h_data[512]; |
| 490 | #define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */ |
| 491 | }; |
| 492 | |
| 493 | /* |
| 494 | * Most massbus and unibus drives |
| 495 | * have headers of this form |
| 496 | */ |
| 497 | struct hpuphdr { |
| 498 | u_short hpup_cyl; |
| 499 | u_char hpup_sect; |
| 500 | u_char hpup_track; |
| 501 | char hpup_data[512]; |
| 502 | #define HPUP_OKSECT 0xc000 /* this normally means sector is good */ |
| 503 | #define HPUP_16BIT 0x1000 /* 1 == 16 bit format */ |
| 504 | }; |
| 505 | int rp06format(), hpupformat(); |
| 506 | |
| 507 | struct formats { |
| 508 | char *f_name; /* disk name */ |
| 509 | int f_bufsize; /* size of sector + header */ |
| 510 | int f_bic; /* value to bic in hpup_cyl */ |
| 511 | int (*f_routine)(); /* routine for special handling */ |
| 512 | } formats[] = { |
| 513 | { "rp06", sizeof (struct rp06hdr), RP06_FMT, rp06format }, |
| 514 | { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, |
| 515 | { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, |
| 516 | { "rm03", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, |
| 517 | { "rm05", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, |
| 518 | { "9300", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, |
| 519 | { "9766", sizeof (struct hpuphdr), HPUP_OKSECT, hpupformat }, |
| 520 | { 0, 0, 0, 0 } |
| 521 | }; |
| 522 | |
| 523 | /*ARGSUSED*/ |
| 524 | hpupformat(fp, dp, blk, buf, count) |
| 525 | struct formats *fp; |
| 526 | struct disklabel *dp; |
| 527 | daddr_t blk; |
| 528 | char *buf; |
| 529 | int count; |
| 530 | { |
| 531 | struct hpuphdr *hdr = (struct hpuphdr *)buf; |
| 532 | int sect; |
| 533 | |
| 534 | if (count < sizeof(struct hpuphdr)) { |
| 535 | hdr->hpup_cyl = (HPUP_OKSECT | HPUP_16BIT) | |
| 536 | (blk / (dp->d_nsectors * dp->d_ntracks)); |
| 537 | sect = blk % (dp->d_nsectors * dp->d_ntracks); |
| 538 | hdr->hpup_track = (u_char)(sect / dp->d_nsectors); |
| 539 | hdr->hpup_sect = (u_char)(sect % dp->d_nsectors); |
| 540 | } |
| 541 | return (0); |
| 542 | } |
| 543 | |
| 544 | /*ARGSUSED*/ |
| 545 | rp06format(fp, dp, blk, buf, count) |
| 546 | struct formats *fp; |
| 547 | struct disklabel *dp; |
| 548 | daddr_t blk; |
| 549 | char *buf; |
| 550 | int count; |
| 551 | { |
| 552 | |
| 553 | if (count < sizeof(struct rp06hdr)) { |
| 554 | fprintf(stderr, "Can't read header on blk %d, can't reformat\n", |
| 555 | blk); |
| 556 | return (-1); |
| 557 | } |
| 558 | return (0); |
| 559 | } |
| 560 | |
| 561 | format(fd, blk) |
| 562 | int fd; |
| 563 | daddr_t blk; |
| 564 | { |
| 565 | register struct formats *fp; |
| 566 | static char *buf; |
| 567 | static char bufsize; |
| 568 | struct format_op fop; |
| 569 | int n; |
| 570 | |
| 571 | for (fp = formats; fp->f_name; fp++) |
| 572 | if (strcmp(dp->d_typename, fp->f_name) == 0) |
| 573 | break; |
| 574 | if (fp->f_name == 0) { |
| 575 | fprintf(stderr, "bad144: don't know how to format %s disks\n", |
| 576 | dp->d_typename); |
| 577 | exit(2); |
| 578 | } |
| 579 | if (buf && bufsize < fp->f_bufsize) { |
| 580 | free(buf); |
| 581 | buf = NULL; |
| 582 | } |
| 583 | if (buf == NULL) |
| 584 | buf = malloc((unsigned)fp->f_bufsize); |
| 585 | if (buf == NULL) { |
| 586 | fprintf(stderr, "bad144: can't allocate sector buffer\n"); |
| 587 | exit(3); |
| 588 | } |
| 589 | bufsize = fp->f_bufsize; |
| 590 | /* |
| 591 | * Here we do the actual formatting. All we really |
| 592 | * do is rewrite the sector header and flag the bad sector |
| 593 | * according to the format table description. If a special |
| 594 | * purpose format routine is specified, we allow it to |
| 595 | * process the sector as well. |
| 596 | */ |
| 597 | if (verbose) |
| 598 | printf("format blk %d\n", blk); |
| 599 | bzero((char *)&fop, sizeof(fop)); |
| 600 | fop.df_buf = buf; |
| 601 | fop.df_count = fp->f_bufsize; |
| 602 | fop.df_startblk = blk; |
| 603 | bzero(buf, fp->f_bufsize); |
| 604 | if (ioctl(fd, DIOCRFORMAT, &fop) < 0) |
| 605 | perror("bad144: read format"); |
| 606 | if (fp->f_routine && |
| 607 | (*fp->f_routine)(fp, dp, blk, buf, fop.df_count) != 0) |
| 608 | return; |
| 609 | if (fp->f_bic) { |
| 610 | struct hpuphdr *xp = (struct hpuphdr *)buf; |
| 611 | |
| 612 | xp->hpup_cyl &= ~fp->f_bic; |
| 613 | } |
| 614 | if (nflag) |
| 615 | return; |
| 616 | bzero((char *)&fop, sizeof(fop)); |
| 617 | fop.df_buf = buf; |
| 618 | fop.df_count = fp->f_bufsize; |
| 619 | fop.df_startblk = blk; |
| 620 | if (ioctl(fd, DIOCWFORMAT, &fop) < 0) |
| 621 | Perror("write format"); |
| 622 | if (fop.df_count != fp->f_bufsize) { |
| 623 | char msg[80]; |
| 624 | (void)sprintf(msg, "bad144: write format %d", blk); |
| 625 | perror(msg); |
| 626 | } |
| 627 | } |
| 628 | #endif |
| 629 | |
| 630 | Perror(op) |
| 631 | char *op; |
| 632 | { |
| 633 | |
| 634 | fprintf(stderr, "bad144: "); perror(op); |
| 635 | exit(4); |
| 636 | } |