| /* | |
| * (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 <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "util_io.h" | |
| #ifdef _WIN32 | |
| # include <io.h> | |
| #else | |
| long filelength (int fno); | |
| # include <sys/types.h> | |
| # include <sys/stat.h> | |
| #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]; | |
| 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 | |