blob: bf775d00984399b2131bac1ae7d3c38cf68d6e31 [file] [log] [blame] [raw]
/*
* (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