home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
552.lha
/
DT_v1.12
/
Source
/
dt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-08
|
11KB
|
404 lines
#define VERSION 1.12
#define LAST_CHANGED 901212
/*--------------------------------------*
| File: DT.c - Rev. 1.12 901212 |
+--------------------------------------+
| DT: disk test, a la Norton Utilities |
+--------------------------------------+---------------*
| Author: Maurizio Loreti, aka MLO or I3NOO. |
| Address: University of Padova - Deparment of Physics |
| Via F. Marzolo, 8 - 35131 PADOVA - Italy |
| Phone: (39)(49) 844-313 FAX: (39)(49) 844-245 |
| E-Mail: LORETI at IPDINFN (BITNET) or VAXFPD::LORETI |
| (DECnet). VAXFPD is node 38.257, i.e. 39169. |
| Home: Via G. Donizetti, 6 - 35010 CADONEGHE (Padova) |
*------------------------------------------------------*/
/**
| #include's
**/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dos.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <devices/trackdisk.h>
#include "mlo.h"
/**
| #define's. The first two should be in TRACKDISK.H, the fourth in
| STDIO.H for ANSI compilers - but are not there in the Lattice
| Include files. TD_CYL is the number of bytes per cylinder.
**/
#define NUMCYLS 80
#define NUMHEADS 2
#define TD_CYL (TD_SECTOR * NUMSECS)
#define FILENAME_MAX 108
#define ON 1
#define OFF 0
/**
| A structure definition for directory entries; for Lattice C, only one
| call to dfind/dnext can be active at a time: so, scanning directories,
| we check all files first and, only then, all subdirectories one by one.
**/
typedef struct sdirEntry {
char *name;
struct sdirEntry *next;
} dirEntry;
/**
| Global variables
**/
struct MsgPort *diskPort = NULL; /* Various Intuition pointers */
struct IOExtTD *diskReq = NULL; /* for disk input */
BYTE *diskBuffer = NULL; /* Disk input buffer */
ULONG diskChangeCount; /* Disk change count */
int nErFil = 0; /* Total number of errors */
int nDirs = 0; /* Nr. of checked directories */
int nFiles = 0; /* Nr. of checked files */
Boolean fromWorkBench; /* Scheduled from WB or CLI ? */
Boolean abortDT = False; /* True when CTRL-C hit */
/**
| The ANSI procedure prototypes
**/
Boolean checkBreak(void);
void checkDir(char *path, Boolean root);
void checkFile(char *name);
void cleanup(int code);
void motor(int action);
void pcl(int n, char *fmt, ...);
void readCyl(int cyl, int hd);
void seekFullRange(SHORT howmany);
void syntax(void);
main(
int argc,
char **argv
){
int drive, cyl, head;
SHORT error;
char driveName[5];
/**
| To be called from CLI, with DT DFx[:] ; if called from the
| Workbench, a prompt for the floppy unit is sent to the console
| window (created from the Lattice initialisation routine).
| Pass 1: a seek over full range;
| Pass 2: read all cylinders;
| Pass 3: read all files record by record.
| But first, check the input arguments and open Intuition.
**/
fprintf(stdout, "\n\t\"DT\" - v%.2f - MLO %d\n", VERSION, LAST_CHANGED);
if (argc == 0) {
do {
fprintf(stdout, "\nDrive to test (DF0-DF4) ? ");
fgets(driveName, sizeof(driveName), stdin);
} while (strnicmp(driveName, "df", 2) ||
(drive = atoi(driveName + 2)) < 0 || drive > 4);
fromWorkBench = True;
} else {
fromWorkBench = False;
if (argc != 2 || strnicmp(*++argv, "df", 2)) syntax();
if ((drive = atoi(*argv+2)) < 0 || drive > 4) syntax();
}
if ((diskBuffer = (BYTE *) AllocMem(TD_CYL, MEMF_CHIP)) == NULL) {
fprintf(stderr, "Can't allocate chip memory ...\n");
cleanup(SYS_ABORT_CODE);
}
/**
| Pass 1
**/
if (!(diskPort = (struct MsgPort *) CreatePort(0, 0))) {
fprintf(stderr, "Can't create I/O port ...\n");
cleanup(SYS_ABORT_CODE);
}
if (!(diskReq = (struct IOExtTD *)
CreateExtIO(diskPort, sizeof(struct IOExtTD))) ) {
fprintf(stderr, "Can't obtain I/O request block ...\n");
cleanup(SYS_ABORT_CODE);
}
sprintf(driveName, "DF%d:", drive);
if (error = OpenDevice(TD_NAME, drive, diskReq, 0)) {
fprintf(stderr,
"Error 0x%X returned by OpenDevice for drive %s ...\n",
error, driveName);
cleanup(SYS_ABORT_CODE);
}
diskReq->iotd_Req.io_Command = TD_CHANGENUM;
DoIO(diskReq);
diskChangeCount = diskReq->iotd_Req.io_Actual;
fprintf(stdout, "\nChange number for drive %s is %d;\n",
driveName, diskChangeCount);
motor(ON);
seekFullRange(1);
/**
| Pass 2
**/
fprintf(stdout, "Checking all disk tracks:\n");
for (cyl=0; cyl<NUMCYLS; cyl++) {
for (head=0; head<NUMHEADS; head++) {
fprintf(stdout, " reading cylinder %d, head %d ...\r", cyl, head);
readCyl(cyl, head);
if (error = diskReq->iotd_Req.io_Error) {
fprintf(stdout,
" Error 0x%X detected for cylinder %d, head %d\n",
error, cyl, head);
nErFil++;
}
}
/**
| Test for CTRL-C
**/
if (checkBreak()) {
fprintf(stdout, "\n*** DT: BREAK ***\n");
motor(OFF);
cleanup(SYS_NORMAL_CODE);
}
}
motor(OFF);
if (nErFil) {
fprintf(stdout, "%d hard errors detected reading drive %s.\n",
nErFil, driveName);
cleanup(SYS_ABORT_CODE);
} else {
fprintf(stdout, " no errors detected reading drive %s.\n", driveName);
nErFil = 0;
}
/**
| Pass 3
**/
fprintf(stdout, "Checking all files in drive %s\n", driveName);
checkDir(driveName, True);
pcl(2, "%d director%s and %d file%s checked: %d error%s detected.",
nDirs, (nDirs == 1 ? "y" : "ies"),
nFiles, (nFiles == 1 ? "" : "s"),
nErFil, (nErFil == 1 ? "" : "s"));
cleanup(SYS_NORMAL_CODE);
}
Boolean checkBreak(void)
{
long SetSignal();
if (SetSignal(0L, 0x1000L) & 0x1000L) return True;
else return False;
}
void checkDir(
char *path,
Boolean root
){
struct FILEINFO info;
char fileName[FILENAME_MAX];
int error;
dirEntry *rdE = NULL;
dirEntry *pdE;
/**
| Check a directory; path contains the full directory name, and root is
| non zero for the root directory. We scan all directory files, checking
| 'true' files at first and all subdirectories at the end, one by one.
**/
nDirs++;
pcl(1, " checking files in%s directory %s ...",
(root ? " root" : ""), path);
strcpy(fileName, path);
strcat(fileName, (root ? "#?" : "/#?"));
error = dfind(&info, fileName, True);
while (!error && !abortDT) {
strcpy(fileName, path);
if (!root) strcat(fileName, "/");
strcat(fileName, info.fib_FileName);
if (info.fib_DirEntryType < 0) {
checkFile(fileName);
} else {
if ((pdE = malloc(sizeof(dirEntry))) == NULL) {
fprintf(stderr, "Can't allocate heap memory ...\n");
cleanup(SYS_ABORT_CODE);
}
if ((pdE->name = malloc(strlen(fileName) + 1)) == NULL) {
fprintf(stderr, "Can't allocate heap memory ...\n");
cleanup(SYS_ABORT_CODE);
}
strcpy(pdE->name, fileName);
pdE->next = rdE;
rdE = pdE;
}
error = dnext(&info);
if (abortDT = checkBreak()) {
pcl(1, "*** DT: BREAK ***");
}
}
while (rdE != NULL) {
if (!abortDT) checkDir(rdE->name, False);
free(rdE->name);
pdE = rdE->next;
free(rdE);
rdE = pdE;
}
}
void checkFile(
char *name
){
struct FileHandle *pFH;
long ier;
/**
| Check a file, opening and reading record by record; this procedure
| is performed using the standard AmigaDOS disk file interface.
**/
nFiles++;
pcl(0, " file %s ...", name);
if ((pFH = (struct FileHandle *) Open(name, MODE_OLDFILE)) == NULL) {
pcl(1, "* Error opening file \"%s\": file not found.", name);
nErFil++;
} else {
while ((ier = Read(pFH, diskBuffer, TD_CYL)) > 0) { }
if (ier < 0) {
pcl(1, "* AmigaDOS error %d reading file \"%s\".", IoErr(), name);
nErFil++;
}
}
Close(pFH);
}
void cleanup(
int code
){
if (diskBuffer != NULL) {
FreeMem(diskBuffer, TD_CYL);
}
if (diskReq != NULL) {
CloseDevice(diskReq);
DeleteExtIO(diskReq, sizeof(struct IOExtTD));
}
if (diskPort != NULL) DeletePort(diskPort);
if (fromWorkBench) {
int i;
fprintf(stdout, "Strike <CR> to continue ...");
while ( (i = getchar()) != '\n' && i != EOF) { }
}
exit(code);
}
void motor(
int action
){
diskReq->iotd_Req.io_Length = action;
diskReq->iotd_Req.io_Command = TD_MOTOR;
DoIO(diskReq);
}
void pcl(
int n,
char *fmt,
...
){
va_list vl;
static length = 0;
int nc;
/**
| What the hell is the delete-to-end-of-line sequence on the Amiga?
| The AmigaDOS manual refers to the ANSI sequence <ESC>[1K - that do
| not work in my NewCon windows; so I wrote this simple interface. When
| overprinting, we check if the length of the new line is greater than
| the old one - if not, we output some blanks. "n" is the number of
| newlines at the end, or zero for no newline but carriage return.
**/
va_start(vl, fmt);
nc = vfprintf(stdout, fmt, vl);
va_end(vl);
length -= nc;
if (length > 0) fprintf(stdout, "%*s", length, " ");
if (n) {
while (n--) fprintf(stdout, "\n");
length = 0;
} else {
fprintf(stdout, "\r");
length = nc;
}
}
void readCyl(
int cyl,
int hd
){
LONG offset;
diskReq->iotd_Req.io_Length = TD_CYL;
diskReq->iotd_Req.io_Data = (APTR) diskBuffer;
diskReq->iotd_Req.io_Command = ETD_READ;
diskReq->iotd_Count = diskChangeCount;
offset = TD_SECTOR * (NUMSECS * (hd + NUMHEADS * cyl));
diskReq->iotd_Req.io_Offset = offset;
DoIO(diskReq);
}
void seekFullRange(
SHORT howmany
){
int i;
SHORT error;
for (i=1; i<=howmany; i++) {
diskReq->iotd_Req.io_Offset =
((NUMCYLS - 1) * NUMSECS * NUMHEADS - 1) * TD_SECTOR;
diskReq->iotd_Req.io_Command = TD_SEEK;
DoIO(diskReq);
if (error = diskReq -> iotd_Req.io_Error) {
fprintf(stdout, "\nSeek cycle %d, error 0x%X ...\n", i, error);
cleanup(SYS_ABORT_CODE);
}
diskReq->iotd_Req.io_Offset = 0;
diskReq->iotd_Req.io_Command = TD_SEEK;
DoIO(diskReq);
if (error = diskReq->iotd_Req.io_Error) {
fprintf(stdout, "\nSeek cycle %d, error 0x%X ...\n", i, error);
cleanup(SYS_ABORT_CODE);
}
}
fprintf(stdout, "no errors detected seeking over full disk range.\n");
}
void syntax(void)
{
fprintf(stdout,
"\n\tUsage:\t\tDT DFn, where 'n' (0-4) is the drive number.\n");
fprintf(stdout,
"\tPurpose:\tDisk test.\n\n");
cleanup(SYS_NORMAL_CODE);
}