home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / source / util2src / crcchk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-24  |  16.9 KB  |  447 lines

  1. /*============================================================================*
  2.  * main() module: crcchk.c - CRC check utility.
  3.  *
  4.  * (C)Copyright IBM Corporation, 1989, 1990, 1991, 1992.     Brian E. Yoder
  5.  *
  6.  * This program reads a list of files, calculates the length and CRC value of
  7.  * each file, and optionally writes the results (length, CRC, name) to an
  8.  * output file.
  9.  *
  10.  * If a filename listed by the input file also contains a length and CRC value,
  11.  * this program compares the file's actual length and CRC to these values.
  12.  * Discrepancies are logged to stderr.
  13.  *
  14.  * Typically, this program is run at least twice: once to generate a list of
  15.  * lengths and CRC values for a group of files, and once to check to see
  16.  * if any of the listed files have changed.
  17.  *
  18.  * For example, assume 'listfile' is formatted as follows:
  19.  *
  20.  *        # List of files for crcchk program
  21.  *        \u\brian\bin\ccmt.exe
  22.  *        \u\brian\bin\ls.exe
  23.  *        \u\brian\bin\chmod.exe
  24.  *        \u\brian\bin\cdir.exe
  25.  *        \u\brian\bin\ccmt.exe
  26.  *
  27.  * Running the command "crcchk listfile crcfile" might produce the following
  28.  * output file named 'crcfile':
  29.  *
  30.  *        23864  0x48EA  \u\brian\bin\ccmt.exe
  31.  *         1819  0xC4AF  \u\brian\bin\ls.exe
  32.  *         2117  0xF631  \u\brian\bin\chmod.exe
  33.  *        20931  0xE8E3  \u\brian\bin\cdir.exe
  34.  *        23009  0xE69A  \u\brian\bin\ccmt.exe
  35.  *
  36.  * Running the command "crcchk crcfile" would then list, on stderr, all files
  37.  * listed in 'crcfile' that did not have the same length or CRC value as
  38.  * specified in 'crcfile'.  This would indicate which, if any, of the listed
  39.  * files had been changed.
  40.  *
  41.  * Additionally, if any errors occur (can't open input file, can't create
  42.  * output file, bad syntax or missing files specified inside the input file),
  43.  * this program returns a nonzero exit code.
  44.  *
  45.  * See the syntax() subroutine in this module for more information about the
  46.  * use of this program.  See the crcfile.c module for more information about
  47.  * CRCs.
  48.  *
  49.  * 11/01/90 - Created.
  50.  * 11/02/90 - Initial version.
  51.  * 02/25/91 - Fixed spelling error in syntax().
  52.  * 05/02/91 - Ported from PS/2 AIX to DOS.
  53.  * 05/08/91 - If we fail a file's length/CRC check, we still must write an
  54.  *            entry for that file.
  55.  * 06/07/92 - Added ability to process long (32-bit) CRC values.  In the list
  56.  *            file, 0xnnnn or shorter is assumed to be a 16-bit CRC, while
  57.  *            0xnnnnn or longer is assumed to be a 32-bit (long) CRC.
  58.  * 06/16/92 - Added -l flag to calculate long (32-bit) CRC values in the case
  59.  *            where an output file is specified but the input file lists no
  60.  *            CRC for a given file.
  61.  * 07/24/92 - Changed lval from long to ulong.
  62.  *============================================================================*/
  63.  
  64. static char copr[] = "(c)Copyright IBM Corporation, 1992.  All rights reserved.";
  65.  
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <memory.h>
  69. #include <sys/types.h>
  70.  
  71. #include "util.h"
  72.  
  73. /*============================================================================*
  74.  * Define internal functions to allow forward access
  75.  *============================================================================*/
  76.  
  77. static void syntax();
  78. int hex2ulong(char *, ulong *);
  79. int dec2ulong(char *, ulong *);
  80.  
  81. /*============================================================================*
  82.  * Main Program Entry Point
  83.  *============================================================================*/
  84.  
  85. main(argc, argv)
  86.  
  87. int argc;           /* arg count */
  88. char *argv[];       /* arg pointers */
  89.  
  90. {
  91.   int     rc;       /* Return code storage */
  92.   char   *flagstr;  /* Pointer to string of flags */
  93.   ulong   lval;     /* long value */
  94.   int     numargs;  /* No. of arguments processed (not including -flags) */
  95.   char    cf;       /* Current flag character (if any) */
  96.  
  97.   int     errcnt;   /* Number of errors detected */
  98.   int     f_long;   /* Force long (32-bit) CRCs (see 06/16/92 update note)? */
  99.  
  100.   char   *infname;  /* Pointers to names of input and output files */
  101.   char   *outfname;
  102.   FILE   *outfile;  /* Output file (optional) */
  103.  
  104.   int      tokc;    /* Number of tokens found in a line */
  105.   char   **tokv;    /* Pointer to array of token pointers */
  106.  
  107.   char   *alen;     /* Pointer to ASCII decimal length */
  108.   char   *acrc;     /* Pointer to ASCII hex CRC value */
  109.   char   *filename; /* Name of a file that is listed in the input file */
  110.  
  111.   ulong   listlen;  /* Converted length and CRC from the list file */
  112.   ulong   listcrc;
  113.  
  114.   ushort  crc;      /* Actual CRC and length values */
  115.   ulong   crc32;
  116.   ulong   len;
  117.  
  118.   int     find32;   /* TRUE == Find 32-bit CRC.  FALSE == Find 16-bit CRC */
  119.   ulong   filecrc;  /* For comparison purposes */
  120.  
  121.   numargs = 0;      /* Initialize number of arguments processed = none */
  122.  
  123.   infname = NULL;   /* Set name and file pointers to NULL */
  124.   outfname = NULL;
  125.   outfile = NULL;
  126.  
  127.   f_long = FALSE;   /* Default to generating 16-bit CRCs when none specified */
  128.  
  129. /*----------------------------------------------------------------------------*
  130.  * Check number of command line arguments:
  131.  *----------------------------------------------------------------------------*/
  132.  
  133.   argc--;                           /* Ignore 1st argument (program name) */
  134.   argv++;
  135.  
  136.   if (argc <= 0) syntax();          /* If no arguments: Display syntax */
  137.  
  138.  /*---------------------------------------------------------------------------*
  139.   * Process flags, if any
  140.   *---------------------------------------------------------------------------*/
  141.  
  142.   flagstr = *argv;                  /* Point 'flagstr' to argument */
  143.   if (*flagstr == '-')              /* If it begins with '-': It's a list of flags */
  144.   {
  145.      flagstr++;                          /* Point past the dash */
  146.  
  147.      while (*flagstr != '\0')            /* For each character in flag string: */
  148.      {
  149.         switch (*flagstr)
  150.         {
  151.            case 'l':
  152.            case 'L':
  153.               f_long = TRUE;
  154.               break;
  155.  
  156.            default:
  157.               fprintf(stderr, "Invalid flag '%c'.  For help, enter command with no arguments.\n",
  158.                  *flagstr);
  159.               exit(2);
  160.               break;
  161.         }
  162.         flagstr++;                            /* Check next character */
  163.      }
  164.  
  165.      argc--;                             /* Done with flags: Discard them */
  166.      argv++;
  167.   }
  168.  
  169.   if ((argc <= 0) || (argc > 2))    /* Verify number of arguments */
  170.      syntax();
  171.  
  172. /*----------------------------------------------------------------------------*
  173.  * Open the input text file as a customization file:
  174.  *----------------------------------------------------------------------------*/
  175.  
  176.   infname = argv[0];                /* Store pointer to file name */
  177.   rc = cfopen(infname);             /* Open the input file */
  178.   if (rc != 0)
  179.   {
  180.      fprintf(stderr, "crcchk: Cannot open file: %s\n",
  181.         infname);
  182.      return(1);
  183.   }
  184.  
  185. /*----------------------------------------------------------------------------*
  186.  * Create the output file if one is specified:
  187.  *----------------------------------------------------------------------------*/
  188.  
  189.   if (argc >= 2)
  190.   {
  191.      outfname = argv[1];
  192.      outfile = fopen(outfname, "w");
  193.      if (outfile == NULL)
  194.      {
  195.         fprintf(stderr, "crcchk: Cannot create file: %s\n",
  196.            outfname);
  197.         return(1);
  198.      }
  199.   }
  200.  
  201. /*----------------------------------------------------------------------------*
  202.  * Process each file listed in the input file:
  203.  *----------------------------------------------------------------------------*/
  204.  
  205.   errcnt = 0;                       /* No errors at start of loop! */
  206.   for (;;)                          /* For each entry in the file: */
  207.   {
  208.     /*------------------------------------------------------------------------*
  209.      * Read the (next) line from the input text file and break it up into
  210.      * tokens (ASCII strings).
  211.      *------------------------------------------------------------------------*/
  212.  
  213.      tokc = cfread(&tokv);               /* Read the entry */
  214.  
  215.      if (tokc == 0)                      /* If no tokens: */
  216.         break;                           /*    We're done: break out of loop */
  217.  
  218.      if ((tokc != 3) &&                  /* Check number of tokens: */
  219.          (tokc != 1))
  220.      {
  221.         fprintf(stderr, "crcchk: Wrong number of tokens: %s, line %lu\n",
  222.            infname, cfline());
  223.         errcnt++;
  224.         continue;
  225.      }
  226.  
  227.     /*------------------------------------------------------------------------*
  228.      * Store pointers to ASCII tokens from the input text file.
  229.      *------------------------------------------------------------------------*/
  230.  
  231.      if (tokc == 3)                      /* If 3 tokens: */
  232.      {
  233.          alen = tokv[0];                      /* Format is: 'length crc name' */
  234.          acrc = tokv[1];
  235.          filename = tokv[2];
  236.  
  237.          if (strlen(acrc) <= 6)               /* If "0x" and 4 or less digits: */
  238.             find32 = FALSE;                        /* It's a 16-bit CRC, not 32-bit */
  239.          else
  240.             find32 = TRUE;                         /* It's a 32-bit CRC */
  241.      }
  242.      else                                /* Else: There's one token: */
  243.      {
  244.          alen = "-";                          /* Format is: 'name' */
  245.          acrc = "-";
  246.          filename = tokv[0];
  247.      }
  248.  
  249.     /*------------------------------------------------------------------------*
  250.      * In case the file has no CRC associated with it, tell crcchk which
  251.      * type of CRC to generate: 16-bit, if f_long is TRUE; 32-bit, otherwise.
  252.      *------------------------------------------------------------------------*/
  253.  
  254.      if (strcmp(acrc, "-") == 0)         /* A CRC of "-" means there isn't one */
  255.         find32 = f_long;                 /* listed for this file */
  256.  
  257.     /*------------------------------------------------------------------------*
  258.      * Get the file's actual length and CRC values:
  259.      *------------------------------------------------------------------------*/
  260.  
  261.      if (find32)                         /* Find file's actual CRC and length */
  262.         rc = crcfile32(filename, &crc32, &len);
  263.      else
  264.         rc = crcfile(filename, &crc, &len);
  265.  
  266.      if (rc != 0)                        /* If error: */
  267.      {
  268.         fprintf(stderr, "crcchk: Cannot access file '%s'.\n", filename);
  269.         errcnt++;
  270.         continue;
  271.      }
  272.  
  273.     /*------------------------------------------------------------------------*
  274.      * Write information to output file if one is present
  275.      *------------------------------------------------------------------------*/
  276.  
  277.      if (outfile != NULL)                /* Write the information to output file */
  278.      {
  279.         if (find32)
  280.            fprintf(outfile, "%12lu  0x%08lX  %s\n", len, crc32, filename);
  281.         else
  282.            fprintf(outfile, "%12lu  0x%04X  %s\n",  len, crc, filename);
  283.      }
  284.  
  285.     /*------------------------------------------------------------------------*
  286.      * If valid length and/or CRC values are present, check them.  If they
  287.      * are not present (indicated by being a dash "-"), then ignore them.
  288.      *------------------------------------------------------------------------*/
  289.  
  290.      if (strcmp("-", alen) != 0)         /* Check length, if not "-": */
  291.      {
  292.         rc = dec2ulong(alen, &listlen);       /* Convert it */
  293.         if (rc != 0)
  294.         {
  295.            fprintf(stderr, "crcchk: Invalid length: '%s'  (in %s, line %lu)\n",
  296.               alen, infname, cfline());
  297.            errcnt++;
  298.            continue;
  299.         }
  300.  
  301.         if (listlen != len)                   /* Check the value */
  302.         {
  303.            fprintf(stderr, "crcchk: length mismatch for file: %s\n",
  304.               filename);
  305.            errcnt++;
  306.            continue;
  307.         }
  308.      }
  309.  
  310.      if (strcmp("-", acrc) != 0)         /* Check CRC, if not "-": */
  311.      {
  312.         rc = hex2ulong(acrc, &lval);          /* Convert it */
  313.         if (rc != 0)
  314.         {
  315.            fprintf(stderr, "crcchk: Invalid CRC: '%s'  (in %s, line %lu)\n",
  316.               acrc, infname, cfline());
  317.            errcnt++;
  318.            continue;
  319.         }
  320.  
  321.         listcrc = lval;                       /* Store listed value */
  322.         if (find32)                           /* If processing 32-bit CRC: */
  323.            filecrc = crc32;                        /* Store actual 32-bit CRC */
  324.         else                                  /* Else: */
  325.            filecrc = crc;                          /* Store actual 16-bit CRC */
  326.  
  327.  
  328.       //printf("(temp) listcrc = 0x%08lx , filecrc = 0x%08lx , find32 = %d  %s\n",
  329.       //        listcrc, filecrc, find32, filename);
  330.  
  331.         if (listcrc != filecrc)               /* Check listed vrs. actual values: */
  332.         {
  333.            fprintf(stderr, "crcchk: CRC mismatch for file: %s\n",
  334.               filename);
  335.            errcnt++;
  336.            continue;
  337.         }
  338.      }
  339.  
  340.     /*------------------------------------------------------------------------*
  341.      * End of for loop: Process next line of input text file
  342.      *------------------------------------------------------------------------*/
  343.  
  344.   } /* end of for (;;) loop */
  345.  
  346.   if (errcnt != 0)                  /* See if any errors occurred.  If so, */
  347.      return(1);                     /* Return with non-zero exit code */
  348.  
  349.   return(0);                        /* Done with main(): Return */
  350.  
  351. } /* end of main() */
  352.  
  353. /*============================================================================*
  354.  * syntax() - Display command syntax and exit to operating system!
  355.  *============================================================================*/
  356. static void syntax()
  357. {
  358.   fprintf(stderr, "Usage: crcchk [-l] infile [outfile]\n");
  359.   fprintf(stderr, "\n");
  360.   fprintf(stderr, "This program reads the input text file (infile) and optionally\n");
  361.   fprintf(stderr, "writes an output text file (outfile).\n");
  362.   fprintf(stderr, "\n");
  363.   fprintf(stderr, "Format of the input text file:  Non-blank, non-comment lines must\n");
  364.   fprintf(stderr, "must be formatted as follows.  If the length and CRC values are\n");
  365.   fprintf(stderr, "present, they are compared against the actual values for the file:\n");
  366.   fprintf(stderr, "\n");
  367.   fprintf(stderr, "       [length  CRC]  filename\n");
  368.   fprintf(stderr, "\n");
  369.   fprintf(stderr, "If an output file is specified:  For each filename in the input file,\n");
  370.   fprintf(stderr, "a line is written to the output file as follows:\n");
  371.   fprintf(stderr, "\n");
  372.   fprintf(stderr, "       length  CRC  filename\n");
  373.   fprintf(stderr, "\n");
  374.   fprintf(stderr, "If no CRC is present, then the -l flag tells crcchk to generate a\n");
  375.   fprintf(stderr, "32-bit (long) CRC for the file.  The default in this case is to\n");
  376.   fprintf(stderr, "generate a 16-bit CRC for the file.\n");
  377.   exit(1);
  378. }
  379.  
  380. /*============================================================================*
  381.  * hex2ulong() - Converts a hex string to a long integer.
  382.  *
  383.  * Purpose:
  384.  *   Converts the string of hexadecimal digits pointed to by 'str' to
  385.  *   an unsigned long integer.  The result is stored at &result.
  386.  *
  387.  * Returns:
  388.  *   0, if no errors.  Otherwise, an error occurred.
  389.  *============================================================================*/
  390. int hex2ulong(str, result)
  391.  
  392. char  *str;                  /* Pointer to string to be converted */
  393. ulong *result;               /* Pointer to where to store result */
  394.  
  395. {
  396.   int   base;                /* Base to use during conversion */
  397.   char *ptr;                 /* Pointer to character that terminated conversion */
  398.  
  399.   base = 16;                 /* Set base for conversion */
  400.  
  401.   /* Convert input string using input base */
  402.  
  403.   *result = strtoul(str, &ptr, base);
  404.  
  405.   /* Check conversion to ensure it was successful: 'ptr' should point to
  406.    * the end of the string */
  407.  
  408.   if (*ptr != '\0')
  409.      return(1);
  410.  
  411.   return(0);
  412. }
  413.  
  414. /*============================================================================*
  415.  * dec2ulong() - Converts a decimal string to a long integer.
  416.  *
  417.  * Purpose:
  418.  *   Converts the string of decimal digits pointed to by 'str' to
  419.  *   an unsigned long integer.  The result is stored at &result.
  420.  *
  421.  * Returns:
  422.  *   0, if no errors.  Otherwise, an error occurred.
  423.  *============================================================================*/
  424. int dec2ulong(str, result)
  425.  
  426. char  *str;                  /* Pointer to string to be converted */
  427. ulong *result;               /* Pointer to where to store result */
  428.  
  429. {
  430.   int   base;                /* Base to use during conversion */
  431.   char *ptr;                 /* Pointer to character that terminated conversion */
  432.  
  433.   base = 10;                 /* Set base for conversion */
  434.  
  435.   /* Convert input string using input base */
  436.  
  437.   *result = strtoul(str, &ptr, base);
  438.  
  439.   /* Check conversion to ensure it was successful: 'ptr' should point to
  440.    * the end of the string */
  441.  
  442.   if (*ptr != '\0')
  443.      return(1);
  444.  
  445.   return(0);
  446. }
  447.