/* * (C) Copyright 2002, Brian Knittel. * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN * RISK basis, there is no warranty of fitness for any purpose, and the rest of the * usual yada-yada. Please keep this notice and the copyright in any distributions * or modifications. * * This is not a supported product, but I welcome bug reports and fixes. * Mail to sim@ibm1130.org */ // checkdisk - validates and optionally dumps an IBM1130 DMS2 disk image file // // Usage: // checkdisk [-f] [-d cyl.sec|abssec] [-n count] filename // // Examples: // checkdisk file.dsk // report any misnumbered sectors in file.dsk // // checkdisk -f file.dsk // report and fix any misnumbered sectors // // checkdisk -d 198.0 file.dsk // dump cylinder 198 sector 0 // // checkdisk -d 0 file.dsk // dump absolute sector 0 // // checkdisk -d 198.0 -n 4 file.dsk // dump 4 sectors starting at m.n // ----------------------------------------------------------------------------------------- #include #include #include #include "util_io.h" #ifdef WIN32 # include #else long filelength (int fno); # include # include #endif #ifndef TRUE # define BOOL int # define TRUE 1 # define FALSE 0 #endif #define DSK_NUMWD 321 /* words/sector */ #define DSK_NUMSC 4 /* sectors/surface */ #define DSK_NUMSF 2 /* surfaces/cylinder */ #define DSK_NUMCY 203 /* cylinders/drive */ #define DSK_NUMDR 5 /* drives/controller */ #define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */ char *usestr = "Usage: checkdisk [-f] [-d cyl.sec|abssec] [-n count] diskfile"; char *baddisk = "Cannot fix this"; void bail (char *msg); char *lowcase (char *str); int main (int argc, char **argv) { FILE *fp; char *fname = NULL, *arg, *argval; int i, j, cyl, sec, pos, asec, retry, nbad = 0, nfixed = 0, nline; BOOL fixit = FALSE, dump = FALSE; int dsec, nsec = 1; unsigned short wd, buf[DSK_NUMWD]; util_io_init(); for (i = 1; i < argc;) { arg = argv[i++]; if (*arg == '-') { arg++; lowcase(arg); while (*arg) { switch (*arg++) { case 'f': fixit = TRUE; break; case 'd': dump = TRUE; if (i >= argc) bail(usestr); argval = argv[i++]; if (strchr(argval, '.') != NULL) { if (sscanf(argval, "%d.%d", &cyl, &sec) != 2) bail(usestr); dsec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec; } else if (sscanf(argval, "%d", &dsec) != 1) bail(usestr); if (dsec < 0 || dsec >= (DSK_NUMCY*DSK_NUMSF*DSK_NUMSC)) bail("No such sector"); break; case 'n': if (i >= argc) bail(usestr); argval = argv[i++]; if (sscanf(argval, "%d", &nsec) != 1) bail(usestr); if (nsec <= 0) bail(usestr); break; default: bail(usestr); } } } else if (fname == NULL) fname = arg; else bail(usestr); } if (fname == NULL) bail(usestr); if ((fp = fopen(fname, "rb+")) == NULL) { perror(fname); return 1; } if (filelength(fileno(fp)) != 2*DSK_SIZE) { fprintf(stderr, "File is wrong length, expected %d\n", DSK_SIZE); bail(baddisk); } for (cyl = 0; cyl < DSK_NUMCY; cyl++) { for (sec = 0; sec < (DSK_NUMSF*DSK_NUMSC); sec++) { retry = 1; again: asec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec; pos = asec*2*DSK_NUMWD; if (fseek(fp, pos, SEEK_SET) != 0) { fprintf(stderr, "Error seeking to pos %x\n", pos); bail(baddisk); } if (fxread(&wd, sizeof(wd), 1, fp) != 1) { fprintf(stderr, "Error reading word at abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos); bail(baddisk); } if (wd != asec) { fprintf(stderr, "Bad sector #%x at abs sec %x, cyl %x, sec %x at offset %x\n", wd, asec, cyl, sec, pos); nbad++; if (fixit) { if (fseek(fp, pos, SEEK_SET) != 0) { fprintf(stderr, "Error seeking to pos %x\n", pos); bail(baddisk); } if (fxwrite(&asec, sizeof(wd), 1, fp) != 1) { fprintf(stderr, "Error writing sector # to abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos); bail(baddisk); } if (retry) { retry = 0; nfixed++; goto again; } fprintf(stderr, "Failed after retry\n"); bail(baddisk); } } } } if (nbad) printf("%d bad sector mark%s %s\n", nbad, (nbad == 1) ? "" : "s", fixit ? "fixed" : "found"); else if (! dump) printf("All sector marks OK\n"); if (! dump) return 0; pos = dsec*2*DSK_NUMWD; if (fseek(fp, pos, SEEK_SET) != 0) { fprintf(stderr, "Error seeking to pos %x\n", pos); bail(baddisk); } for (i = 0; i < nsec; i++) { cyl = dsec / (DSK_NUMSF*DSK_NUMSC); sec = dsec - cyl*(DSK_NUMSF*DSK_NUMSC); if (fxread(&buf, sizeof(buf[0]), DSK_NUMWD, fp) != DSK_NUMWD) { fprintf(stderr, "Error reading abs sec %x, cyl %x, sec %x at offset %x\n", dsec, cyl, sec, pos); bail(baddisk); } printf("\nSector %d.%d - %d - /%04x label %04x\n", cyl, sec, dsec, dsec, buf[0]); for (nline = 0, j = 1; j < DSK_NUMWD; j++) { printf("%04x", buf[j]); if (++nline == 16) { putchar('\n'); nline = 0; } else putchar(' '); } dsec++; } return 0; } void bail (char *msg) { fprintf(stderr, "%s\n", msg); exit(1); } /* ------------------------------------------------------------------------ * lowcase - force a string to lower case (ASCII) * ------------------------------------------------------------------------ */ char *lowcase (char *str) { char *s; for (s = str; *s; s++) { if (*s >= 'A' && *s <= 'Z') *s += 32; } return str; } #ifndef WIN32 long filelength (int fno) { struct stat sb; if (fstat(fno, &sb) != 0) return 0; return (long) sb.st_size; } #endif