| 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 |
| 59 | char *usestr = "Usage: checkdisk [-f] [-d cyl.sec|abssec] [-n count] diskfile";\r |
| 60 | char *baddisk = "Cannot fix this";\r |
| 61 | \r |
| 62 | void bail (char *msg);\r |
| 63 | char *lowcase (char *str);\r |
| 64 | \r |
| 65 | int 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 |
| 146 | again:\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 |
| 228 | void 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 |
| 238 | char *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 |
| 252 | long 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 |