Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 Jul 2021 15:47:26 GMT
From:      =?utf-8?Q?Stefan E=C3=9Fer?= <se@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: b7c17fd730ca - stable/12 - sbin/md5: add md5sum to synopsis in the man-page
Message-ID:  <202107061547.166FlQsD078703@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by se:

URL: https://cgit.FreeBSD.org/src/commit/?id=b7c17fd730ca4e8806a506b617ad32218aa0b826

commit b7c17fd730ca4e8806a506b617ad32218aa0b826
Author:     Stefan Eßer <se@FreeBSD.org>
AuthorDate: 2021-06-19 11:27:16 +0000
Commit:     Stefan Eßer <se@FreeBSD.org>
CommitDate: 2021-07-06 15:44:14 +0000

    sbin/md5: add md5sum to synopsis in the man-page
    
    When invoked with "sum" following the hash name, the -c option takes a
    file argument, not a string argument.
    
    (cherry picked from commit 84f35b6f86efd004a8f25ef6eecea0f5d02733c4)
    
    sbin/md5: improve compatibility with coreutils -c option
    
    The -c option expects a digest file in either BSD or coreutils format.
    
    The output for matched and mismatched files is identical to that
    of the coreutils version.
    
    The review of these changes included test cases that have already
    been committed for the functionality that existed before.
    Another test script is added to cover the coreutils compatible
    extension implemented by this patch.
    
    This commit contains a tests/Makefile that has been cleaned up
    compared to the review version, using an implicit rule to apply the
    TESTBASE path at build time (and the scripts have been renamed to
    have an extension of .SH instead of .sh to trigger this rule).
    
    Reviewed by:    imp
    Differential Revision:  https://reviews.freebsd.org/D30812
    
    (cherry picked from commit b33d1898c1b0e6d76b52eb48078260588802dc95)
    
    md5: Improve compatibility with coreutils and format fix
    
    The previous changes that added support for the coreutils -c option
    modified the output generated by passing -r to match that of the
    coreutils versions. The difference is that coreutils separates the
    hash from the file name by two blanks "  " (or a blank followed by
    an asterisk " *" with the -b option denoting).
    
    While most scripts or users will not notice the difference, it might
    be considered a violation of POLA and this commit reverts the change
    for the non-sum programs. These will print a single blank " " as the
    separator, as they die before the previous commit.
    
    In order to still generate output that is identical to that of the
    coreutils programs, this commit generates the "  " or " *" separator
    used by them for the -sum versions, depending on the presence of the
    -b option.
    
    (cherry picked from commit b33d1898c1b0e6d76b52eb48078260588802dc95)
    
    md5: Fix cross-build after c2870e576bd2
    
    On macOS and Linux the current set of headers do not end up pulling in
    sys/param.h, causing MAXPATHLEN to not be defined and the build to fail.
    
    (cherry picked from commit cab31e0e216c7defefd4aba14693ba2252ea7308)
---
 sbin/md5/md5.1                     | 114 ++++++++++++++++++++++---
 sbin/md5/md5.c                     | 171 ++++++++++++++++++++++++++++++++-----
 sbin/md5/tests/Makefile            |   1 +
 sbin/md5/tests/coreutils-c-test.SH |  21 +++++
 4 files changed, 274 insertions(+), 33 deletions(-)

diff --git a/sbin/md5/md5.1 b/sbin/md5/md5.1
index af4e606b62e7..f91e0b759dc7 100644
--- a/sbin/md5/md5.1
+++ b/sbin/md5/md5.1
@@ -15,6 +15,12 @@
 .Op Fl s Ar string
 .Op Ar
 .Pp
+.Nm md5sum
+.Op Fl pqrtx
+.Op Fl c Ar file
+.Op Fl s Ar string
+.Op Ar
+.Pp
 (All other hashes have the same options and usage.)
 .Sh DESCRIPTION
 The
@@ -85,17 +91,34 @@ The hexadecimal checksum of each file listed on the command line is printed
 after the options are processed.
 .Bl -tag -width indent
 .It Fl b
-Ignored for compatibility with the coreutils
+Make the
 .Nm -sum
-programs.
+programs separate hash and digest with a blank followed by an asterisk instead
+of by 2 blank characters for full compatibility with the output generated by the
+coreutils versions of these programs.
 .It Fl c Ar string
-Compare the digest of the file against this string.
+If the program was called with a name that does not end in
+.Nm sum ,
+compare the digest of the file against this string.
 .Pq Note that this option is not yet useful if multiple files are specified.
-This option causes an error in for the
-.Nm -sum
-programs because it check the checksums listed in a file for the coreutils
-.Nm -sum
-programs that is not yet implemented.
+.It Fl c Ar file
+If the program was called with a name that does end in
+.Nm sum ,
+the file passed as argument must contain digest lines generated by the same
+digest algorithm with or without the
+.Fl r
+option
+.Pq i.e. in either classical BSD format or in GNU coreutils format .
+A line with the file name followed by a colon
+.Dq ":"
+and either OK or FAILED is written for each well-formed line in the digest file.
+If applicable, the number of failed comparisons and the number of lines that were
+skipped since they were not well-formed are printed at the end.
+The
+.Fl q
+option can be used to quiesce the output unless there are mismatched entries in
+the digest.
+.Pp
 .It Fl s Ar string
 Print a checksum of the given
 .Ar string .
@@ -132,6 +155,77 @@ utilities exit 0 on success,
 and 2 if at least one file does not have the same hash as the
 .Fl c
 option.
+<<<<<<< HEAD
+=======
+.Sh EXAMPLES
+Calculate the MD5 checksum of the string
+.Dq Hello .
+.Bd -literal -offset indent
+$ md5 -s Hello
+MD5 ("Hello") = 8b1a9953c4611296a827abf8c47804d7
+.Ed
+.Pp
+Same as above, but note the absence of the newline character in the input
+string:
+.Bd -literal -offset indent
+$ echo -n Hello | md5
+8b1a9953c4611296a827abf8c47804d7
+.Ed
+.Pp
+Calculate the checksum of multiple files reversing the output:
+.Bd -literal -offset indent
+$ md5 -r /boot/loader.conf /etc/rc.conf
+ada5f60f23af88ff95b8091d6d67bef6 /boot/loader.conf
+d80bf36c332dc0fdc479366ec3fa44cd /etc/rc.conf
+.Pd
+The
+.Nm -sum
+variants put 2 blank characters between hash and file name for full compatibilty
+with the coreutils versions of these commands.
+.Ed
+.Pp
+Write the digest for
+.Pa /boot/loader.conf
+in a file named
+.Pa digest .
+Then calculate the checksum again and validate it against the checksum string
+extracted from the
+.Pa digest
+file:
+.Bd -literal -offset indent
+$ md5 /boot/loader.conf > digest && md5 -c $(cut -f2 -d= digest) /boot/loader.conf
+MD5 (/boot/loader.conf) = ada5f60f23af88ff95b8091d6d67bef6
+.Ed
+.Pp
+Same as above but comparing the digest against an invalid string
+.Pq Dq randomstring ,
+which results in a failure.
+.Bd -literal -offset indent
+$ md5 -c randomstring /boot/loader.conf
+MD5 (/boot/loader.conf) = ada5f60f23af88ff95b8091d6d67bef6 [ Failed ]
+.Ed
+.Pp
+If invoked with a name ending in
+.Nm -sum
+the
+.Fl c
+option does not compare against a hash string passed as parameter.
+Instead, it expects a digest file, as created under the name
+.Pa digest
+for
+.Pa /boot/loader.conf
+in the example above.
+.Bd -literal -offset indent
+$ md5 -c digest /boot/loader.conf
+/boot/loader.conf: OK
+.Ed
+.Pp
+The digest file may contain any number of lines in the format generated with or without the
+.Fl r
+option
+.Pq i.e. in either classical BSD format or in GNU coreutils format .
+If a hash value does not match the file, FAILED is printed instead of OK.
+>>>>>>> c2870e576bd2 (sbin/md5: improve compatibility with coreutils -c option)
 .Sh SEE ALSO
 .Xr cksum 1 ,
 .Xr md5 3 ,
@@ -171,9 +265,7 @@ The RIPEMD-160 page:
 All of the utilities that end in
 .Sq sum
 are intended to be compatible with the GNU coreutils programs.
-However, the long arguments and the
-.Fl -check
-functionality are not provided.
+However, the long option functionality is not provided.
 .Sh ACKNOWLEDGMENTS
 This program is placed in the public domain for free general use by
 RSA Data Security.
diff --git a/sbin/md5/md5.c b/sbin/md5/md5.c
index e553d4c56e85..7235e6e0a39f 100644
--- a/sbin/md5/md5.c
+++ b/sbin/md5/md5.c
@@ -21,6 +21,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <err.h>
@@ -53,6 +54,8 @@ __FBSDID("$FreeBSD$");
 #define TEST_BLOCK_COUNT 100000
 #define MDTESTCOUNT 8
 
+static int bflag;
+static int cflag;
 static int pflag;
 static int qflag;
 static int rflag;
@@ -152,12 +155,93 @@ static const struct Algorithm_t Algorithm[] = {
 		(DIGEST_End*)&SKEIN1024_End, &SKEIN1024_Data, &SKEIN1024_Fd }
 };
 
+static unsigned	digest;
+static unsigned	malformed;
+static bool	gnu_emu = false;
+
 static void
 MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
 {
 	MD5Update(c, data, len);
 }
 
+struct chksumrec {
+	char	*filename;
+	char	*chksum;
+	struct	chksumrec	*next;
+};
+
+static struct chksumrec *head = NULL;
+static struct chksumrec **next = &head;
+
+#define PADDING	7	/* extra padding for "SHA512t256 (...) = ...\n" style */
+#define CHKFILELINELEN	(HEX_DIGEST_LENGTH + MAXPATHLEN + PADDING)
+
+static int gnu_check(const char *checksumsfile)
+{
+	FILE	*inp;
+	char	linebuf[CHKFILELINELEN];
+	int	linelen;
+	int	lineno;
+	char	*filename;
+	char	*hashstr;
+	struct chksumrec	*rec;
+	const char	*digestname;
+	int	digestnamelen;
+	int	hashstrlen;
+
+	if ((inp = fopen(checksumsfile, "r")) == NULL)
+		err(1, "%s", checksumsfile);
+	digestname = Algorithm[digest].name;
+	digestnamelen = strlen(digestname);
+	hashstrlen = strlen(*(Algorithm[digest].TestOutput[0]));
+	lineno = 1;
+	while (fgets(linebuf, sizeof(linebuf), inp) != NULL) {
+		linelen = strlen(linebuf) - 1;
+		if (linelen <= 0)
+			break;
+		if (linebuf[linelen] != '\n')
+			errx(1, "malformed input line %d (len=%d)", lineno, linelen);
+		linebuf[linelen] = '\0';
+		filename = linebuf + digestnamelen + 2;
+		hashstr = linebuf + linelen - hashstrlen;
+		/*
+		 * supported formats:
+		 * BSD: <DigestName> (<Filename>): <Digest>
+		 * GNU: <Digest> [ *]<Filename>
+		 */
+		if (linelen >= digestnamelen + hashstrlen + 6 &&
+		    strncmp(linebuf, digestname, digestnamelen) == 0 &&
+		    strncmp(filename - 2, " (", 2) == 0 &&
+		    strncmp(hashstr - 4, ") = ", 4) == 0) {
+			*(hashstr - 4) = '\0';
+		} else if (linelen >= hashstrlen + 3 &&
+		    linebuf[hashstrlen] == ' ') {
+			linebuf[hashstrlen] = '\0';
+			hashstr = linebuf;
+			filename = linebuf + hashstrlen + 1;
+			if (*filename == ' ' || *filename == '*')
+				filename++;
+		} else {
+			malformed++;
+			continue;
+		}
+		rec = malloc(sizeof (*rec));
+		if (rec == NULL)
+			errx(1, "malloc failed");
+		rec->chksum = strdup(hashstr);
+		rec->filename = strdup(filename);
+		if (rec->chksum == NULL || rec->filename == NULL)
+			errx(1, "malloc failed");
+		rec->next = NULL;
+		*next = rec;
+		next = &rec->next;
+		lineno++;
+	}
+	fclose(inp);
+	return (lineno - 1);
+}
+
 /* Main driver.
 
 Arguments (may be any combination):
@@ -177,9 +261,9 @@ main(int argc, char *argv[])
 	char   *p, *string;
 	char	buf[HEX_DIGEST_LENGTH];
 	size_t	len;
- 	unsigned	digest;
 	char	*progname;
-	bool	gnu_emu = false;
+	struct chksumrec	*rec;
+	int	numrecs;
 
  	if ((progname = strrchr(argv[0], '/')) == NULL)
  		progname = argv[0];
@@ -199,13 +283,13 @@ main(int argc, char *argv[])
 	 */
 	len = strlen(progname);
 	if (len > 3 && strcmp(progname + len - 3, "sum") == 0) {
-		progname[len - 3] = '\0';
+		len -= 3;
 		rflag = 1;
 		gnu_emu = true;
 	}
 
  	for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++)
- 		if (strcasecmp(Algorithm[digest].progname, progname) == 0)
+ 		if (strncasecmp(Algorithm[digest].progname, progname, len) == 0)
  			break;
 
  	if (digest == sizeof(Algorithm)/sizeof(*Algorithm))
@@ -218,11 +302,14 @@ main(int argc, char *argv[])
 	while ((ch = getopt(argc, argv, "bc:pqrs:tx")) != -1)
 		switch (ch) {
 		case 'b':
+			bflag = 1;
 			break;
 		case 'c':
+			cflag = 1;
 			if (gnu_emu)
-				errx(1, "-c check option not supported");
-			checkAgainst = optarg;
+				numrecs = gnu_check(optarg);
+			else
+				checkAgainst = optarg;
 			break;
 		case 'p':
 			pflag = 1;
@@ -258,6 +345,20 @@ main(int argc, char *argv[])
 		err(1, "unable to limit rights for stdio");
 #endif
 
+	if (cflag && gnu_emu) {
+		/*
+		 * Replace argv by an array of filenames from the digest file
+		 */
+		argc = 0;
+		argv = (char**)calloc(sizeof(char *), numrecs + 1);
+		for (rec = head; rec != NULL; rec = rec->next) {
+			argv[argc] = rec->filename;
+			argc++;
+		}
+		argv[argc] = NULL;
+		rec = head;
+	}
+
 	if (*argv) {
 		do {
 			if ((fd = open(*argv, O_RDONLY)) < 0) {
@@ -279,11 +380,15 @@ main(int argc, char *argv[])
 					err(1, "capsicum");
 #endif
 			}
+			if (cflag && gnu_emu) {
+				checkAgainst = rec->chksum;
+				rec = rec->next;
+			}
 			p = Algorithm[digest].Fd(fd, buf);
 			(void)close(fd);
 			MDOutput(&Algorithm[digest], p, argv);
 		} while (*++argv);
-	} else if (!sflag && !skip) {
+	} else if (!cflag && !sflag && !skip) {
 #ifdef HAVE_CAPSICUM
 		if (caph_limit_stdin() < 0 || caph_enter() < 0)
 			err(1, "capsicum");
@@ -295,7 +400,12 @@ main(int argc, char *argv[])
 		p = Algorithm[digest].Data(string, len, buf);
 		MDOutput(&Algorithm[digest], p, &string);
 	}
-
+	if (gnu_emu) {
+		if (malformed > 0)
+			warnx("WARNING: %d lines are improperly formatted", malformed);
+		if (checksFailed > 0)
+			warnx("WARNING: %d computed checksums did NOT match", checksFailed);
+	}
 	if (failed != 0)
 		return (1);
 	if (checksFailed != 0)
@@ -310,6 +420,8 @@ main(int argc, char *argv[])
 static void
 MDOutput(const Algorithm_t *alg, char *p, char *argv[])
 {
+	bool checkfailed = false;
+
 	if (p == NULL) {
 		warn("%s", *argv);
 		failed++;
@@ -318,21 +430,33 @@ MDOutput(const Algorithm_t *alg, char *p, char *argv[])
 		 * If argv is NULL we are reading from stdin, where the output
 		 * format has always been just the hash.
 		 */
-		if (qflag || argv == NULL)
-			printf("%s", p);
-		else if (rflag)
-			printf("%s %s", p, *argv);
-		else
-			printf("%s (%s) = %s",
-			    alg->name, *argv, p);
-		if (checkAgainst && strcasecmp(checkAgainst, p) != 0)
-		{
-			checksFailed++;
-			if (!qflag)
-				printf(" [ Failed ]");
+		if (cflag && gnu_emu) {
+			checkfailed = strcasecmp(checkAgainst, p) != 0;
+			if (!qflag || checkfailed)
+				printf("%s: %s\n", *argv, checkfailed ? "FAILED" : "OK");
+		} else if (qflag || argv == NULL) {
+			printf("%s\n", p);
+		} else {
+			if (rflag)
+				if (gnu_emu)
+					if (bflag)
+						printf("%s *%s", p, *argv);
+					else
+						printf("%s  %s", p, *argv);
+				else
+					printf("%s %s", p, *argv);
+			else
+				printf("%s (%s) = %s", alg->name, *argv, p);
+			if (checkAgainst) {
+				checkfailed = strcasecmp(checkAgainst, p) != 0;
+				if (!qflag && checkfailed)
+					printf(" [ Failed ]");
+			}
+			printf("\n");
 		}
-		printf("\n");
 	}
+	if (checkfailed)
+		checksFailed++;
 }
 
 /*
@@ -559,6 +683,9 @@ static void
 usage(const Algorithm_t *alg)
 {
 
-	fprintf(stderr, "usage: %s [-pqrtx] [-c string] [-s string] [files ...]\n", alg->progname);
+	if (gnu_emu)
+		fprintf(stderr, "usage: %ssum [-pqrtx] [-c file] [-s string] [files ...]\n", alg->progname);
+	else
+		fprintf(stderr, "usage: %s [-pqrtx] [-c string] [-s string] [files ...]\n", alg->progname);
 	exit(1);
 }
diff --git a/sbin/md5/tests/Makefile b/sbin/md5/tests/Makefile
index b37332aa9894..93f3913c687d 100644
--- a/sbin/md5/tests/Makefile
+++ b/sbin/md5/tests/Makefile
@@ -32,6 +32,7 @@ PLAIN_TESTS_SH+=	self-test
 PLAIN_TESTS_SH+=	bsd-c-test
 PLAIN_TESTS_SH+=	bsd-p-test
 PLAIN_TESTS_SH+=	bsd-s-test
+PLAIN_TESTS_SH+=	coreutils-c-test
 
 .SUFFIXES:		.SH
 
diff --git a/sbin/md5/tests/coreutils-c-test.SH b/sbin/md5/tests/coreutils-c-test.SH
new file mode 100644
index 000000000000..5996e533c627
--- /dev/null
+++ b/sbin/md5/tests/coreutils-c-test.SH
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+/bin/cp %%TESTSBASE%%/sbin/md5/*.inp . || exit 127
+
+exitcode=0
+
+testloop () {
+	opt=$1
+
+	while read algorithm; do
+		${algorithm}sum -c %%TESTSBASE%%/sbin/md5/${algorithm}.digest || exitcode=1
+		${algorithm}sum -c %%TESTSBASE%%/sbin/md5/${algorithm}sum.digest || exitcode=1
+	done < %%TESTSBASE%%/sbin/md5/algorithms.txt
+}
+
+testloop ""
+testloop -q
+testloop -r
+testloop -qr
+
+exit $exitcode



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107061547.166FlQsD078703>