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