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 >
C/C++ Source or Header  |  1991-09-08  |  11KB  |  404 lines

  1. #define VERSION       1.12
  2. #define LAST_CHANGED  901212
  3.  
  4. /*--------------------------------------*
  5.  | File: DT.c - Rev. 1.12 901212        |
  6.  +--------------------------------------+
  7.  | DT: disk test, a la Norton Utilities |
  8.  +--------------------------------------+---------------*
  9.  | Author: Maurizio Loreti, aka MLO or I3NOO.           |
  10.  | Address: University of Padova - Deparment of Physics |
  11.  |          Via F. Marzolo, 8 - 35131 PADOVA - Italy    |
  12.  | Phone: (39)(49) 844-313        FAX: (39)(49) 844-245 |
  13.  | E-Mail: LORETI at IPDINFN (BITNET) or VAXFPD::LORETI |
  14.  |         (DECnet). VAXFPD is node 38.257, i.e. 39169. |
  15.  | Home: Via G. Donizetti, 6 - 35010 CADONEGHE (Padova) |
  16.  *------------------------------------------------------*/
  17.  
  18. /**
  19.  | #include's
  20. **/
  21.  
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <stdarg.h>
  26. #include <dos.h>
  27. #include <exec/types.h>
  28. #include <exec/exec.h>
  29. #include <devices/trackdisk.h>
  30. #include "mlo.h"
  31.  
  32. /**
  33.  | #define's. The first two should be in TRACKDISK.H, the fourth in
  34.  | STDIO.H for ANSI compilers - but are not there in the Lattice
  35.  | Include files. TD_CYL is the number of bytes per cylinder.
  36. **/
  37.  
  38. #define NUMCYLS       80
  39. #define NUMHEADS      2
  40. #define TD_CYL        (TD_SECTOR * NUMSECS)
  41. #define FILENAME_MAX  108
  42. #define ON            1
  43. #define OFF           0
  44.  
  45. /**
  46.  | A structure definition for directory entries; for Lattice C, only one
  47.  | call to dfind/dnext can be active at a time: so, scanning directories,
  48.  | we check all files first and, only then, all subdirectories one by one.
  49. **/
  50.  
  51. typedef struct sdirEntry {
  52.   char *name;
  53.   struct sdirEntry *next;
  54. } dirEntry;
  55.  
  56. /**
  57.  | Global variables
  58. **/
  59.  
  60. struct MsgPort *diskPort = NULL;      /* Various Intuition pointers */
  61. struct IOExtTD *diskReq = NULL;       /*   for disk input */
  62. BYTE *diskBuffer = NULL;              /* Disk input buffer */
  63. ULONG diskChangeCount;                /* Disk change count */
  64. int nErFil = 0;                       /* Total number of errors */
  65. int nDirs = 0;                        /* Nr. of checked directories */
  66. int nFiles = 0;                       /* Nr. of checked files */
  67. Boolean fromWorkBench;                /* Scheduled from WB or CLI ? */
  68. Boolean abortDT = False;              /* True when CTRL-C hit */
  69.  
  70. /**
  71.  | The ANSI procedure prototypes
  72. **/
  73.  
  74. Boolean checkBreak(void);
  75. void checkDir(char *path, Boolean root);
  76. void checkFile(char *name);
  77. void cleanup(int code);
  78. void motor(int action);
  79. void pcl(int n, char *fmt, ...);
  80. void readCyl(int cyl, int hd);
  81. void seekFullRange(SHORT howmany);
  82. void syntax(void);
  83.  
  84. main(
  85.   int argc,
  86.   char **argv
  87. ){
  88.   int drive, cyl, head;
  89.   SHORT error;
  90.   char driveName[5];
  91.  
  92. /**
  93.  | To be called from CLI, with DT DFx[:] ; if called from the
  94.  | Workbench, a prompt for the floppy unit is sent to the console
  95.  | window (created from the Lattice initialisation routine).
  96.  |  Pass 1: a seek over full range;
  97.  |  Pass 2: read all cylinders;
  98.  |  Pass 3: read all files record by record.
  99.  | But first, check the input arguments and open Intuition.
  100. **/
  101.  
  102.   fprintf(stdout, "\n\t\"DT\" - v%.2f - MLO %d\n", VERSION, LAST_CHANGED);
  103.  
  104.   if (argc == 0) {
  105.     do {
  106.       fprintf(stdout, "\nDrive to test (DF0-DF4) ? ");
  107.       fgets(driveName, sizeof(driveName), stdin);
  108.     } while (strnicmp(driveName, "df", 2)   ||
  109.              (drive = atoi(driveName + 2)) < 0   ||   drive > 4);
  110.     fromWorkBench = True;
  111.   } else {
  112.     fromWorkBench = False;
  113.     if (argc != 2   ||   strnicmp(*++argv, "df", 2))    syntax();
  114.     if ((drive = atoi(*argv+2)) < 0   ||   drive > 4)   syntax();
  115.   }
  116.  
  117.   if ((diskBuffer = (BYTE *) AllocMem(TD_CYL, MEMF_CHIP)) == NULL) {
  118.     fprintf(stderr, "Can't allocate chip memory ...\n");
  119.     cleanup(SYS_ABORT_CODE);
  120.   }
  121.  
  122. /**
  123.  | Pass 1
  124. **/
  125.  
  126.   if (!(diskPort = (struct MsgPort *) CreatePort(0, 0))) {
  127.     fprintf(stderr, "Can't create I/O port ...\n");
  128.     cleanup(SYS_ABORT_CODE);
  129.   }
  130.  
  131.   if (!(diskReq = (struct IOExtTD *)
  132.       CreateExtIO(diskPort, sizeof(struct IOExtTD))) ) {
  133.     fprintf(stderr, "Can't obtain I/O request block ...\n");
  134.     cleanup(SYS_ABORT_CODE);
  135.   }
  136.  
  137.   sprintf(driveName, "DF%d:", drive);
  138.   if (error = OpenDevice(TD_NAME, drive, diskReq, 0)) {
  139.     fprintf(stderr,
  140.             "Error 0x%X returned by OpenDevice for drive %s ...\n",
  141.             error, driveName);
  142.     cleanup(SYS_ABORT_CODE);
  143.   }
  144.  
  145.   diskReq->iotd_Req.io_Command = TD_CHANGENUM;
  146.   DoIO(diskReq);
  147.   diskChangeCount = diskReq->iotd_Req.io_Actual;
  148.   fprintf(stdout, "\nChange number for drive %s is %d;\n",
  149.           driveName, diskChangeCount);
  150.   motor(ON);
  151.   seekFullRange(1);
  152.  
  153. /**
  154.  | Pass 2
  155. **/
  156.  
  157.   fprintf(stdout, "Checking all disk tracks:\n");
  158.   for (cyl=0; cyl<NUMCYLS; cyl++) {
  159.     for (head=0; head<NUMHEADS; head++) {
  160.       fprintf(stdout, "  reading cylinder %d, head %d ...\r", cyl, head);
  161.       readCyl(cyl, head);
  162.         if (error = diskReq->iotd_Req.io_Error) {
  163.         fprintf(stdout,
  164.                 "  Error 0x%X detected for cylinder %d, head %d\n",
  165.                 error, cyl, head);
  166.         nErFil++;
  167.       }
  168.     }
  169.  
  170. /**
  171.  | Test for CTRL-C
  172. **/
  173.  
  174.     if (checkBreak()) {
  175.       fprintf(stdout, "\n*** DT: BREAK ***\n");
  176.       motor(OFF);
  177.       cleanup(SYS_NORMAL_CODE);
  178.     }
  179.   }
  180.   motor(OFF);
  181.   if (nErFil) {
  182.     fprintf(stdout, "%d hard errors detected reading drive %s.\n",
  183.             nErFil, driveName);
  184.     cleanup(SYS_ABORT_CODE);
  185.   } else {
  186.     fprintf(stdout, "  no errors detected reading drive %s.\n", driveName);
  187.     nErFil = 0;
  188.   }
  189.  
  190. /**
  191.  | Pass 3
  192. **/
  193.  
  194.   fprintf(stdout, "Checking all files in drive %s\n", driveName);
  195.   checkDir(driveName, True);
  196.   pcl(2, "%d director%s and %d file%s checked: %d error%s detected.",
  197.       nDirs, (nDirs == 1 ? "y" : "ies"),
  198.       nFiles, (nFiles == 1 ? "" : "s"),
  199.       nErFil, (nErFil == 1 ? "" : "s"));
  200.   cleanup(SYS_NORMAL_CODE);
  201. }
  202.  
  203. Boolean checkBreak(void)
  204. {
  205.   long SetSignal();
  206.  
  207.   if (SetSignal(0L, 0x1000L)  &  0x1000L)   return True;
  208.     else                                    return False;
  209. }
  210.  
  211. void checkDir(
  212.   char *path,
  213.   Boolean root
  214. ){
  215.   struct FILEINFO info;
  216.   char fileName[FILENAME_MAX];
  217.   int error;
  218.   dirEntry *rdE = NULL;
  219.   dirEntry *pdE;
  220.  
  221. /**
  222.  | Check a directory; path contains the full directory name, and root is
  223.  | non zero for the root directory. We scan all directory files, checking
  224.  | 'true' files at first and all subdirectories at the end, one by one.
  225. **/
  226.  
  227.   nDirs++;
  228.   pcl(1, "  checking files in%s directory %s ...",
  229.       (root ? " root" : ""), path);
  230.   strcpy(fileName, path);
  231.   strcat(fileName, (root ? "#?" : "/#?"));
  232.  
  233.   error = dfind(&info, fileName, True);
  234.   while (!error   &&   !abortDT) {
  235.     strcpy(fileName, path);
  236.     if (!root) strcat(fileName, "/");
  237.     strcat(fileName, info.fib_FileName);
  238.     if (info.fib_DirEntryType < 0) {
  239.       checkFile(fileName);
  240.     } else {
  241.       if ((pdE = malloc(sizeof(dirEntry))) == NULL) {
  242.         fprintf(stderr, "Can't allocate heap memory ...\n");
  243.         cleanup(SYS_ABORT_CODE);
  244.       }
  245.       if ((pdE->name = malloc(strlen(fileName) + 1)) == NULL) {
  246.         fprintf(stderr, "Can't allocate heap memory ...\n");
  247.         cleanup(SYS_ABORT_CODE);
  248.       }
  249.       strcpy(pdE->name, fileName);
  250.       pdE->next = rdE;
  251.       rdE = pdE;
  252.     }
  253.     error = dnext(&info);
  254.     if (abortDT = checkBreak()) {
  255.       pcl(1, "*** DT: BREAK ***");
  256.     }
  257.   }
  258.  
  259.   while (rdE != NULL) {
  260.     if (!abortDT) checkDir(rdE->name, False);
  261.     free(rdE->name);
  262.     pdE = rdE->next;
  263.     free(rdE);
  264.     rdE = pdE;
  265.   }
  266. }
  267.  
  268. void checkFile(
  269.   char *name
  270. ){
  271.   struct FileHandle *pFH;
  272.   long ier;
  273.  
  274. /**
  275.  | Check a file, opening and reading record by record; this procedure
  276.  | is performed using the standard AmigaDOS disk file interface.
  277. **/
  278.  
  279.   nFiles++;
  280.   pcl(0, "    file %s ...", name);
  281.   if ((pFH = (struct FileHandle *) Open(name, MODE_OLDFILE)) == NULL) {
  282.     pcl(1, "* Error opening file \"%s\": file not found.", name);
  283.     nErFil++;
  284.   } else {
  285.     while ((ier = Read(pFH, diskBuffer, TD_CYL)) > 0) { }
  286.     if (ier < 0) {
  287.       pcl(1, "* AmigaDOS error %d reading file \"%s\".", IoErr(), name);
  288.       nErFil++;
  289.     }
  290.   }
  291.   Close(pFH);
  292. }
  293.  
  294. void cleanup(
  295.   int code
  296. ){
  297.   if (diskBuffer != NULL) {
  298.     FreeMem(diskBuffer, TD_CYL);
  299.   }
  300.   if (diskReq != NULL) {
  301.     CloseDevice(diskReq);
  302.     DeleteExtIO(diskReq, sizeof(struct IOExtTD));
  303.   }
  304.   if (diskPort != NULL)   DeletePort(diskPort);
  305.  
  306.   if (fromWorkBench) {
  307.     int i;
  308.     fprintf(stdout, "Strike <CR> to continue ...");
  309.     while ( (i = getchar()) != '\n'   &&   i != EOF)  { }
  310.   }
  311.   exit(code);
  312. }
  313.  
  314. void motor(
  315.   int action
  316. ){
  317.   diskReq->iotd_Req.io_Length = action;
  318.   diskReq->iotd_Req.io_Command = TD_MOTOR;
  319.   DoIO(diskReq);
  320. }
  321.  
  322. void pcl(
  323.   int n,
  324.   char *fmt,
  325.   ...
  326. ){
  327.   va_list vl;
  328.   static length = 0;
  329.   int nc;
  330.  
  331. /**
  332.  | What the hell is the delete-to-end-of-line sequence on the Amiga?
  333.  | The AmigaDOS manual refers to the ANSI sequence <ESC>[1K - that do
  334.  | not work in my NewCon windows; so I wrote this simple interface. When
  335.  | overprinting, we check if the length of the new line is greater than
  336.  | the old one - if not, we output some blanks. "n" is the number of
  337.  | newlines at the end, or zero for no newline but carriage return.
  338. **/
  339.  
  340.   va_start(vl, fmt);
  341.   nc = vfprintf(stdout, fmt, vl);
  342.   va_end(vl);
  343.   length -= nc;
  344.   if (length > 0) fprintf(stdout, "%*s", length, " ");
  345.   if (n) {
  346.     while (n--) fprintf(stdout, "\n");
  347.     length = 0;
  348.   } else {
  349.     fprintf(stdout, "\r");
  350.     length = nc;
  351.   }
  352. }
  353.  
  354. void readCyl(
  355.   int cyl,
  356.   int hd
  357. ){
  358.   LONG offset;
  359.  
  360.   diskReq->iotd_Req.io_Length = TD_CYL;
  361.   diskReq->iotd_Req.io_Data = (APTR) diskBuffer;
  362.   diskReq->iotd_Req.io_Command = ETD_READ;
  363.   diskReq->iotd_Count = diskChangeCount;
  364.   offset = TD_SECTOR * (NUMSECS * (hd + NUMHEADS * cyl));
  365.   diskReq->iotd_Req.io_Offset = offset;
  366.   DoIO(diskReq);
  367. }
  368.  
  369. void seekFullRange(
  370.   SHORT howmany
  371. ){
  372.   int i;
  373.   SHORT error;
  374.  
  375.   for (i=1; i<=howmany; i++) {
  376.     diskReq->iotd_Req.io_Offset =
  377.           ((NUMCYLS - 1) * NUMSECS * NUMHEADS - 1) * TD_SECTOR;
  378.     diskReq->iotd_Req.io_Command = TD_SEEK;
  379.     DoIO(diskReq);
  380.     if (error = diskReq -> iotd_Req.io_Error) {
  381.       fprintf(stdout, "\nSeek cycle %d, error 0x%X ...\n", i, error);
  382.       cleanup(SYS_ABORT_CODE);
  383.     }
  384.  
  385.     diskReq->iotd_Req.io_Offset = 0;
  386.     diskReq->iotd_Req.io_Command = TD_SEEK;
  387.     DoIO(diskReq);
  388.     if (error = diskReq->iotd_Req.io_Error) {
  389.       fprintf(stdout, "\nSeek cycle %d, error 0x%X ...\n", i, error);
  390.       cleanup(SYS_ABORT_CODE);
  391.     }
  392.   }
  393.   fprintf(stdout, "no errors detected seeking over full disk range.\n");
  394. }
  395.  
  396. void syntax(void)
  397. {
  398.   fprintf(stdout,
  399.         "\n\tUsage:\t\tDT DFn, where 'n' (0-4) is the drive number.\n");
  400.   fprintf(stdout,
  401.         "\tPurpose:\tDisk test.\n\n");
  402.   cleanup(SYS_NORMAL_CODE);
  403. }
  404.