bin/170278: [request] Add --check option to md5(1)
Alexander Pyhalov
apyhalov at gmail.com
Sat Sep 1 13:37:58 UTC 2012
Hello.
I''ve modified patch for md5.c, so now md5/sha256/etc handles input files
containing checksums in two formats:
ALGORITHM(path_to_file) = checksum
and
checksum path_to_file.
It seems, this patch (which at least applies to md5.c in 8.3) needs testing.
--
Best regards,
Alexander Pyhalov
-------------- next part --------------
--- /usr/src/sbin/md5/md5.c 2012-06-06 21:42:10.901208101 +0400
+++ md5.c 2012-09-01 17:27:49.957655225 +0400
@@ -20,10 +20,13 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
+#include <ctype.h>
#include <err.h>
+#include <getopt.h>
#include <md5.h>
#include <ripemd.h>
#include <sha.h>
@@ -41,6 +44,7 @@
#define TEST_BLOCK_COUNT 100000
#define MDTESTCOUNT 8
+int fflag;
int qflag;
int rflag;
int sflag;
@@ -73,6 +77,8 @@
static void MDTestSuite(Algorithm_t *);
static void MDFilter(Algorithm_t *, int);
static void usage(Algorithm_t *);
+static void ProcessCheckAgainstFile(char *filename, int *failed, int digest);
+static void strtoupper(char *s);
typedef union {
MD5_CTX md5;
@@ -85,6 +91,13 @@
SHA256_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */
#define HEX_DIGEST_LENGTH 65
+/* maximum length of string in controlsum file - digest plus file path
+ plus some dilimiters */
+#define MAX_STRING_LENGTH (HEX_DIGEST_LENGTH+MAXPATHLEN+64)
+
+/* maximum length of algorithm name */
+#define MAX_ALG_LENGTH 10
+
/* algorithm function table */
struct Algorithm_t Algorithm[] = {
@@ -126,6 +139,9 @@
int failed;
unsigned digest;
const char* progname;
+ struct option longopts[] = {
+ { "check",no_argument,NULL,'f'}
+ };
if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
@@ -142,11 +158,14 @@
failed = 0;
checkAgainst = NULL;
checksFailed = 0;
- while ((ch = getopt(argc, argv, "c:pqrs:tx")) != -1)
+ while ((ch = getopt_long(argc, argv, "c:pfqrs:tx",longopts,NULL)) != -1)
switch (ch) {
case 'c':
checkAgainst = optarg;
break;
+ case 'f':
+ fflag = 1;
+ break;
case 'p':
MDFilter(&Algorithm[digest], 1);
break;
@@ -174,29 +193,35 @@
if (*argv) {
do {
- p = Algorithm[digest].File(*argv, buf);
- if (!p) {
- warn("%s", *argv);
- failed++;
+ if (fflag){
+ ProcessCheckAgainstFile(*argv,&failed,digest);
} else {
- if (qflag)
- printf("%s", p);
- else if (rflag)
- printf("%s %s", p, *argv);
- else
- printf("%s (%s) = %s",
- Algorithm[digest].name, *argv, p);
- if (checkAgainst && strcmp(checkAgainst,p))
- {
- checksFailed++;
- if (!qflag)
- printf(" [ Failed ]");
+ p = Algorithm[digest].File(*argv, buf);
+ if (!p) {
+ warn("%s", *argv);
+ failed++;
+ } else {
+ if (qflag)
+ printf("%s", p);
+ else if (rflag)
+ printf("%s %s", p, *argv);
+ else
+ printf("%s (%s) = %s",
+ Algorithm[digest].name, *argv, p);
+ if (checkAgainst && strcmp(checkAgainst,p))
+ {
+ checksFailed++;
+ if (!qflag)
+ printf(" [ Failed ]");
+ }
+ printf("\n");
}
- printf("\n");
}
} while (*++argv);
- } else if (!sflag && (optind == 1 || qflag || rflag))
+ } else if (!fflag && !sflag && (optind == 1 || qflag || rflag))
MDFilter(&Algorithm[digest], 0);
+ else if (fflag)
+ ProcessCheckAgainstFile(NULL,&failed,digest);
if (failed != 0)
return (1);
@@ -205,6 +230,135 @@
return (0);
}
+
+/*
+ * Reads a file with control sums and filenames and checks them
+ */
+static void
+ProcessCheckAgainstFile(char *filename, int *failed, int digest){
+ char buf[HEX_DIGEST_LENGTH];
+ char checkAgainstCur[HEX_DIGEST_LENGTH];
+ char strar[MAX_STRING_LENGTH+1];
+ char *cur;
+ char *str;
+ char curfname[MAXPATHLEN+1];
+ char alg[MAX_ALG_LENGTH+1];
+ char *p;
+ FILE *fl;
+ int first,next,eq,len,parsed;
+
+ if(filename)
+ fl=fopen(filename,"r");
+ else {
+ fl=stdin;
+ }
+ if(fl){
+ str=&strar[0];
+ bzero(str,MAX_STRING_LENGTH);
+ while(fgets(str,MAX_STRING_LENGTH,fl)){
+ parsed=0;
+ bzero(checkAgainstCur,HEX_DIGEST_LENGTH);
+ bzero(curfname,MAXPATHLEN);
+ bzero(alg,MAX_ALG_LENGTH);
+
+ while(isspace(*str)&& *str!='\0')
+ str++;
+ first=strcspn(str,"(");
+ if(first) {
+ cur=&str[first];
+
+ next=strlen(str);
+ while(next>first && str[next]!=')')
+ next--;
+
+ if(first&&next && next>first && next-first<=MAXPATHLEN){
+ strncpy(curfname,&str[first+1],next-first);
+ curfname[next-first-1]='\0';
+ while(first>0 && isspace(str[first-1]))
+ first--;
+ if(first<=MAX_ALG_LENGTH){
+ strncpy(alg,str,first);
+ strtoupper(alg);
+ eq=strcspn(&str[next],"=");
+ eq++;
+ while(isspace(str[eq+next]) && str[eq+next]!='\0')
+ eq++;
+ len=strlen(str);
+ while(isspace(str[len])&& len>next)
+ len--;
+ if(len-next-eq<=HEX_DIGEST_LENGTH){
+ strncpy(checkAgainstCur,&str[eq+next],len-eq-next);
+ checkAgainstCur[len-eq-next-1]='\0';
+ parsed=1;
+ }
+
+
+ }
+
+ }
+
+ }
+ if(!parsed) {
+ first=strcspn(str,"\t ");
+ if(first && first<=HEX_DIGEST_LENGTH){
+ strncpy(checkAgainstCur,str,first);
+ checkAgainstCur[first]='\0';
+
+ str=&(str[first]);
+ while(isspace(*str)&&*str!='\0')
+ str++;
+ len=strlen(str);
+ if(len>MAXPATHLEN)
+ len=MAXPATHLEN;
+ strncpy(curfname,str,len);
+ curfname[len-1]='\0';
+ strncpy(alg,Algorithm[digest].name,MAX_ALG_LENGTH);
+ parsed=1;
+ }
+ }
+ if(parsed && !strncmp(alg,Algorithm[digest].name,MAX_ALG_LENGTH)) {
+ p = Algorithm[digest].File(curfname, buf);
+ if (!p) {
+ warn("%s", curfname);
+ failed++;
+ } else {
+ if (qflag)
+ printf("%s", p);
+ else if (rflag)
+ printf("%s %s", p, curfname);
+ else
+ printf("%s (%s) = %s",
+ Algorithm[digest].name, curfname, p);
+ if (strcmp(checkAgainstCur,p)) {
+ checksFailed++;
+ if (!qflag)
+ printf(" [ Failed ]");
+ }
+ putchar('\n');
+ }
+ } else {
+ (*failed)++;
+ }
+ bzero(str,MAX_STRING_LENGTH);
+ }
+ fclose(fl);
+ } else {
+ (*failed)++;
+ }
+}
+
+/*
+ * Convert strings to upper case
+ */
+static void
+strtoupper(char *s){
+ int i;
+
+ if(s){
+ for(i=0;s[i]!='\0';i++)
+ s[i]=toupper(s[i]);
+ }
+}
/*
* Digests a string and prints the result.
*/
More information about the freebsd-bugs
mailing list