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