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