First Commit of my working state
[simh.git] / Ibm1130 / utils / checkdisk.c
1 /*
2 * (C) Copyright 2002, Brian Knittel.
3 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
4 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the
5 * usual yada-yada. Please keep this notice and the copyright in any distributions
6 * or modifications.
7 *
8 * This is not a supported product, but I welcome bug reports and fixes.
9 * Mail to sim@ibm1130.org
10 */
11
12 // checkdisk - validates and optionally dumps an IBM1130 DMS2 disk image file
13 //
14 // Usage:
15 // checkdisk [-f] [-d cyl.sec|abssec] [-n count] filename
16 //
17 // Examples:
18 // checkdisk file.dsk
19 // report any misnumbered sectors in file.dsk
20 //
21 // checkdisk -f file.dsk
22 // report and fix any misnumbered sectors
23 //
24 // checkdisk -d 198.0 file.dsk
25 // dump cylinder 198 sector 0
26 //
27 // checkdisk -d 0 file.dsk
28 // dump absolute sector 0
29 //
30 // checkdisk -d 198.0 -n 4 file.dsk
31 // dump 4 sectors starting at m.n
32 // -----------------------------------------------------------------------------------------
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include "util_io.h"
37
38 #ifdef _WIN32
39 # include <io.h>
40 #else
41 long filelength (int fno);
42 # include <sys/types.h>
43 # include <sys/stat.h>
44 #endif
45
46 #ifndef TRUE
47 # define BOOL int
48 # define TRUE 1
49 # define FALSE 0
50 #endif
51
52 #define DSK_NUMWD 321 /* words/sector */
53 #define DSK_NUMSC 4 /* sectors/surface */
54 #define DSK_NUMSF 2 /* surfaces/cylinder */
55 #define DSK_NUMCY 203 /* cylinders/drive */
56 #define DSK_NUMDR 5 /* drives/controller */
57 #define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */
58
59 char *usestr = "Usage: checkdisk [-f] [-d cyl.sec|abssec] [-n count] diskfile";
60 char *baddisk = "Cannot fix this";
61
62 void bail (char *msg);
63 char *lowcase (char *str);
64
65 int main (int argc, char **argv)
66 {
67 FILE *fp;
68 char *fname = NULL, *arg, *argval;
69 int i, j, cyl, sec, pos, asec, retry, nbad = 0, nfixed = 0, nline;
70 BOOL fixit = FALSE, dump = FALSE;
71 int dsec, nsec = 1;
72 unsigned short wd, buf[DSK_NUMWD];
73
74 for (i = 1; i < argc;) {
75 arg = argv[i++];
76 if (*arg == '-') {
77 arg++;
78 lowcase(arg);
79 while (*arg) {
80 switch (*arg++) {
81 case 'f':
82 fixit = TRUE;
83 break;
84
85 case 'd':
86 dump = TRUE;
87
88 if (i >= argc)
89 bail(usestr);
90
91 argval = argv[i++];
92 if (strchr(argval, '.') != NULL) {
93 if (sscanf(argval, "%d.%d", &cyl, &sec) != 2)
94 bail(usestr);
95
96 dsec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec;
97 }
98 else if (sscanf(argval, "%d", &dsec) != 1)
99 bail(usestr);
100
101 if (dsec < 0 || dsec >= (DSK_NUMCY*DSK_NUMSF*DSK_NUMSC))
102 bail("No such sector");
103
104 break;
105
106 case 'n':
107 if (i >= argc)
108 bail(usestr);
109
110 argval = argv[i++];
111 if (sscanf(argval, "%d", &nsec) != 1)
112 bail(usestr);
113
114 if (nsec <= 0)
115 bail(usestr);
116
117 break;
118
119 default:
120 bail(usestr);
121 }
122 }
123 }
124 else if (fname == NULL)
125 fname = arg;
126 else
127 bail(usestr);
128 }
129
130 if (fname == NULL)
131 bail(usestr);
132
133 if ((fp = fopen(fname, "rb+")) == NULL) {
134 perror(fname);
135 return 1;
136 }
137
138 if (filelength(fileno(fp)) != 2*DSK_SIZE) {
139 fprintf(stderr, "File is wrong length, expected %d\n", DSK_SIZE);
140 bail(baddisk);
141 }
142
143 for (cyl = 0; cyl < DSK_NUMCY; cyl++) {
144 for (sec = 0; sec < (DSK_NUMSF*DSK_NUMSC); sec++) {
145 retry = 1;
146 again:
147 asec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec;
148 pos = asec*2*DSK_NUMWD;
149
150 if (fseek(fp, pos, SEEK_SET) != 0) {
151 fprintf(stderr, "Error seeking to pos %x\n", pos);
152 bail(baddisk);
153 }
154
155 if (fxread(&wd, sizeof(wd), 1, fp) != 1) {
156 fprintf(stderr, "Error reading word at abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos);
157 bail(baddisk);
158 }
159
160 if (wd != asec) {
161 fprintf(stderr, "Bad sector #%x at abs sec %x, cyl %x, sec %x at offset %x\n", wd, asec, cyl, sec, pos);
162 nbad++;
163
164 if (fixit) {
165 if (fseek(fp, pos, SEEK_SET) != 0) {
166 fprintf(stderr, "Error seeking to pos %x\n", pos);
167 bail(baddisk);
168 }
169
170 if (fxwrite(&asec, sizeof(wd), 1, fp) != 1) {
171 fprintf(stderr, "Error writing sector # to abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos);
172 bail(baddisk);
173 }
174
175 if (retry) {
176 retry = 0;
177 nfixed++;
178 goto again;
179 }
180
181 fprintf(stderr, "Failed after retry\n");
182 bail(baddisk);
183 }
184 }
185 }
186 }
187
188 if (nbad)
189 printf("%d bad sector mark%s %s\n", nbad, (nbad == 1) ? "" : "s", fixit ? "fixed" : "found");
190 else if (! dump)
191 printf("All sector marks OK\n");
192
193 if (! dump)
194 return 0;
195
196 pos = dsec*2*DSK_NUMWD;
197 if (fseek(fp, pos, SEEK_SET) != 0) {
198 fprintf(stderr, "Error seeking to pos %x\n", pos);
199 bail(baddisk);
200 }
201
202 for (i = 0; i < nsec; i++) {
203 cyl = dsec / (DSK_NUMSF*DSK_NUMSC);
204 sec = dsec - cyl*(DSK_NUMSF*DSK_NUMSC);
205
206 if (fxread(&buf, sizeof(buf[0]), DSK_NUMWD, fp) != DSK_NUMWD) {
207 fprintf(stderr, "Error reading abs sec %x, cyl %x, sec %x at offset %x\n", dsec, cyl, sec, pos);
208 bail(baddisk);
209 }
210
211 printf("\nSector %d.%d - %d - /%04x label %04x\n", cyl, sec, dsec, dsec, buf[0]);
212 for (nline = 0, j = 1; j < DSK_NUMWD; j++) {
213 printf("%04x", buf[j]);
214 if (++nline == 16) {
215 putchar('\n');
216 nline = 0;
217 }
218 else
219 putchar(' ');
220 }
221
222 dsec++;
223 }
224
225 return 0;
226 }
227
228 void bail (char *msg)
229 {
230 fprintf(stderr, "%s\n", msg);
231 exit(1);
232 }
233
234 /* ------------------------------------------------------------------------
235 * lowcase - force a string to lower case (ASCII)
236 * ------------------------------------------------------------------------ */
237
238 char *lowcase (char *str)
239 {
240 char *s;
241
242 for (s = str; *s; s++) {
243 if (*s >= 'A' && *s <= 'Z')
244 *s += 32;
245 }
246
247 return str;
248 }
249
250 #ifndef _WIN32
251
252 long filelength (int fno)
253 {
254 struct stat sb;
255
256 if (fstat(fno, &sb) != 0)
257 return 0;
258
259 return (long) sb.st_size;
260 }
261 #endif
262