stdio and tty's require clearerr to insure EOF is reset
[unix-history] / usr / src / usr.sbin / bad144 / bad144.c
CommitLineData
6cb1d6d5
SL
1#ifndef lint
2static char *sccsid = "@(#)bad144.c 4.5 (Berkeley) 83/06/12";
3#endif
52ff80b5
BJ
4
5/*
6 * bad144
7 *
8 * This program prints and/or initializes a bad block record for a pack,
9 * in the format used by the DEC standard 144.
10 *
11 * BUGS:
12 * Only reads/writes the first of the bad block record (sector 0
13 * of the last track of the disk); in fact, there are copies
14 * of the information in the first 5 even numbered sectors of this
15 * track, but UNIX uses only the first, and we don't bother with the
16 * others.
17 *
18 * It is preferable to write the bad information with a standard formatter,
19 * but this program will do in a pinch, e.g. if the bad information is
20 * accidentally wiped out this is a much faster way of restoring it than
ace59b28
SL
21 * reformatting.
22 *
6cb1d6d5
SL
23 * RP06 sectors are marked as bad by inverting the format bit in the
24 * header; on other drives the BSE bit is set.
52ff80b5
BJ
25 */
26#include <sys/types.h>
27#include <sys/dkbad.h>
ace59b28 28#include <sys/ioctl.h>
6cb1d6d5 29#include <sys/file.h>
ace59b28 30#include <machine/dkio.h>
347d81fa 31
52ff80b5 32#include <stdio.h>
347d81fa 33#include <disktab.h>
52ff80b5 34
ace59b28 35int fflag;
52ff80b5
BJ
36struct dkbad dkbad;
37
38main(argc, argv)
39 int argc;
6cb1d6d5 40 char *argv[];
52ff80b5 41{
52ff80b5 42 register struct bt_bad *bt;
347d81fa 43 register struct disktab *dp;
52ff80b5 44 char name[BUFSIZ];
347d81fa 45 int size, i, f, bad, oldbad, errs;
52ff80b5
BJ
46
47 argc--, argv++;
ace59b28
SL
48 if (argc > 0 && strcmp(*argv, "-f") == 0) {
49 argc--, argv++;
50 fflag++;
51 }
52ff80b5 52 if (argc < 2) {
ace59b28
SL
53 fprintf(stderr,
54 "usage: bad144 [ -f ] type disk [ snum [ bn ... ] ]\n");
347d81fa
SL
55 fprintf(stderr, "e.g.: bad144 rk07 hk0\n");
56 exit(1);
57 }
58 dp = getdiskbyname(argv[0]);
59 if (dp == NULL) {
60 fprintf(stderr, "%s: unknown disk type\n", argv[0]);
52ff80b5
BJ
61 exit(1);
62 }
52ff80b5
BJ
63 sprintf(name, "/dev/r%sc", argv[1]);
64 argc -= 2;
65 argv += 2;
347d81fa 66 size = dp->d_nsectors * dp->d_ntracks * dp->d_ncylinders;
52ff80b5 67 if (argc == 0) {
6cb1d6d5
SL
68 f = open(name, O_RDONLY);
69 if (f < 0)
70 Perror(name);
71 if (lseek(f, dp->d_secsize*(size-dp->d_nsectors), L_SET) < 0)
72 Perror("lseek");
52ff80b5
BJ
73 printf("bad block information at 0x%x in %s:\n",
74 tell(f), name);
75 if (read(f, &dkbad, sizeof (struct dkbad)) !=
76 sizeof (struct dkbad)) {
6cb1d6d5 77 fprintf("bad144: %s: can't read bad block info\n");
52ff80b5
BJ
78 exit(1);
79 }
80 printf("cartidge serial number: %d(10)\n", dkbad.bt_csn);
81 switch (dkbad.bt_flag) {
347d81fa 82
52ff80b5
BJ
83 case -1:
84 printf("alignment cartridge\n");
85 break;
347d81fa 86
52ff80b5
BJ
87 case 0:
88 break;
347d81fa 89
52ff80b5
BJ
90 default:
91 printf("bt_flag=%x(16)?\n", dkbad.bt_flag);
92 break;
93 }
94 oldbad = 0;
95 bt = dkbad.bt_bad;
96 for (i = 0; i < 128; i++) {
97 bad = (bt->bt_cyl<<16) + bt->bt_trksec;
98 if (bad < 0)
99 break;
100 printf("sn=%d, cn=%d, tn=%d, sn=%d\n",
347d81fa
SL
101 (bt->bt_cyl*dp->d_ntracks + (bt->bt_trksec>>8)) *
102 dp->d_nsectors + (bt->bt_trksec&0xff),
52ff80b5
BJ
103 bt->bt_cyl, bt->bt_trksec>>8, bt->bt_trksec&0xff);
104 bt++;
105 }
6cb1d6d5 106 exit(0);
52ff80b5 107 }
ace59b28 108 f = open(name, 1 + fflag);
6cb1d6d5
SL
109 if (f < 0)
110 Perror(name);
52ff80b5
BJ
111 dkbad.bt_csn = atoi(*argv++);
112 argc--;
67f2497d 113 dkbad.bt_mbz = 0;
347d81fa
SL
114 if (argc > 2 * dp->d_nsectors || argc > 126) {
115 printf("bad144: too many bad sectors specified\n");
116 if (2 * dp->d_nsectors > 126)
52ff80b5
BJ
117 printf("limited to 126 by information format\n");
118 else
119 printf("limited to %d (only 2 tracks of sectors)\n",
347d81fa 120 2 * dp->d_nsectors);
52ff80b5
BJ
121 exit(1);
122 }
123 errs = 0;
124 i = 0;
125 while (argc > 0) {
126 int sn = atoi(*argv++);
347d81fa 127
52ff80b5 128 argc--;
347d81fa 129 if (sn < 0 || sn >= size) {
52ff80b5 130 printf("%d: out of range [0,%d) for %s\n",
347d81fa 131 sn, size, dp->d_name);
52ff80b5
BJ
132 errs++;
133 }
347d81fa
SL
134 dkbad.bt_bad[i].bt_cyl = sn / (dp->d_nsectors*dp->d_ntracks);
135 sn %= (dp->d_nsectors*dp->d_ntracks);
52ff80b5 136 dkbad.bt_bad[i].bt_trksec =
347d81fa 137 ((sn/dp->d_nsectors) << 8) + (sn%dp->d_nsectors);
52ff80b5
BJ
138 i++;
139 }
140 while (i < 126) {
141 dkbad.bt_bad[i].bt_trksec = -1;
142 dkbad.bt_bad[i].bt_cyl = -1;
143 i++;
144 }
145 if (errs)
146 exit(1);
6cb1d6d5
SL
147 if (lseek(f, dp->d_secsize * (size - dp->d_nsectors), L_SET) < 0)
148 Perror("lseek");
149 if (write(f, (caddr_t)&dkbad, sizeof (dkbad)) != sizeof (dkbad))
150 Perror(name);
ace59b28
SL
151 if (fflag)
152 for (i = 0, bt = dkbad.bt_bad; i < 128; i++, bt++) {
153 daddr_t bn;
154
155 bad = (bt->bt_cyl<<16) + bt->bt_trksec;
156 if (bad < 0)
157 break;
158 bn = (bt->bt_cyl * dp->d_ntracks +
159 (bt->bt_trksec >> 8)) *
160 dp->d_nsectors + (bt->bt_trksec & 0xff);
161 format(f, dp, bn);
162 }
52ff80b5
BJ
163 exit(0);
164}
ace59b28
SL
165
166struct rp06hdr {
167 short h_cyl;
168 short h_trksec;
169 short h_key1;
170 short h_key2;
171 char h_data[512];
172#define RP06_FMT 010000 /* 1 == 16 bit, 0 == 18 bit */
173};
6cb1d6d5
SL
174
175/*
176 * Most massbus and unibus drives
177 * have headers of this form
178 */
179struct hpuphdr {
180 u_short hpup_cyl;
181 u_short hpup_trksec;
182 char hpup_data[512];
183#define HPUP_OKSECT 0xc000 /* this normally means sector is good */
184};
ace59b28
SL
185
186struct formats {
187 char *f_name; /* disk name */
188 int f_bufsize; /* size of sector + header */
6cb1d6d5 189 int f_bic; /* value to bic in hpup_cyl */
ace59b28
SL
190 int (*f_routine)(); /* routine for special handling */
191} formats[] = {
6cb1d6d5
SL
192 { "rp06", sizeof (struct rp06hdr), RP06_FMT, 0 },
193 { "eagle", sizeof (struct hpuphdr), HPUP_OKSECT, 0 },
194 { "capricorn", sizeof (struct hpuphdr), HPUP_OKSECT, 0 },
195 { 0, 0, 0, 0 }
ace59b28
SL
196};
197
198format(fd, dp, blk)
199 int fd;
200 struct disktab *dp;
201 daddr_t blk;
202{
203 register struct formats *fp;
204 char *buf, *malloc();
205
206 for (fp = formats; fp->f_name; fp++)
207 if (strcmp(dp->d_name, fp->f_name) == 0)
208 break;
209 if (fp->f_name == 0) {
210 fprintf(stderr, "bad144: don't know how to format %s disks\n",
211 dp->d_name);
212 exit(2);
213 }
214 buf = malloc(fp->f_bufsize);
215 if (buf == NULL) {
216 fprintf(stderr, "bad144: can't allocate sector buffer\n");
217 exit(3);
218 }
219 /*
220 * Here we do the actual formatting. All we really
221 * do is rewrite the sector header and flag the bad sector
222 * according to the format table description. If a special
223 * purpose format routine is specified, we allow it to
224 * process the sector as well.
225 */
6cb1d6d5
SL
226 if (lseek(fd, (long)blk * 512, L_SET) < 0)
227 Perror("lseek");
228 if (ioctl(fd, DKIOCHDR, 0) < 0)
229 Perror("ioctl");
230 if (read(fd, buf, fp->f_bufsize) != fp->f_bufsize)
231 Perror("read");
232 if (fp->f_bic) {
233 struct hpuphdr *xp = (struct hpuphdr *)buf;
234
235 xp->hpup_cyl &= ~fp->f_bic;
236 }
ace59b28
SL
237 if (fp->f_routine)
238 (*fp->f_routine)(fp, dp, blk, buf);
6cb1d6d5
SL
239 if (lseek(fd, (long)blk * 512, L_SET) < 0)
240 Perror("lseek");
241 if (ioctl(fd, DKIOCHDR, 0) < 0)
242 Perror("ioctl");
243 if (write(fd, buf, fp->f_bufsize) != fp->f_bufsize)
244 Perror("write");
ace59b28
SL
245}
246
6cb1d6d5
SL
247Perror(op)
248 char *op;
ace59b28
SL
249{
250
6cb1d6d5
SL
251 fprintf(stderr, "bad144: "); perror(op);
252 exit(4);
ace59b28 253}