Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144379499
D30812.id91331.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D30812.id91331.diff
View Options
diff --git a/sbin/md5/md5.1 b/sbin/md5/md5.1
--- a/sbin/md5/md5.1
+++ b/sbin/md5/md5.1
@@ -1,5 +1,5 @@
.\" $FreeBSD$
-.Dd June 19, 2021
+.Dd June 24, 2021
.Dt MD5 1
.Os
.Sh NAME
@@ -14,6 +14,7 @@
.Op Fl c Ar string
.Op Fl s Ar string
.Op Ar
+.Pp
.Nm md5sum
.Op Fl pqrtx
.Op Fl c Ar file
@@ -80,13 +81,28 @@
.Nm -sum
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 file name followed by
+.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 .
@@ -141,8 +157,8 @@
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
+ada5f60f23af88ff95b8091d6d67bef6 /boot/loader.conf
+d80bf36c332dc0fdc479366ec3fa44cd /etc/rc.conf
.Ed
.Pp
Write the digest for
@@ -165,6 +181,27 @@
$ 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.
.Sh SEE ALSO
.Xr cksum 1 ,
.Xr md5 3 ,
@@ -203,9 +240,7 @@
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
--- a/sbin/md5/md5.c
+++ b/sbin/md5/md5.c
@@ -53,6 +53,7 @@
#define TEST_BLOCK_COUNT 100000
#define MDTESTCOUNT 8
+static int cflag;
static int pflag;
static int qflag;
static int rflag;
@@ -152,12 +153,93 @@
(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 +259,9 @@
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 +281,13 @@
*/
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))
@@ -220,9 +302,11 @@
case 'b':
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 +342,20 @@
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 +377,15 @@
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 +397,12 @@
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 +417,8 @@
static void
MDOutput(const Algorithm_t *alg, char *p, char *argv[])
{
+ bool checkfailed = false;
+
if (p == NULL) {
warn("%s", *argv);
failed++;
@@ -318,21 +427,27 @@
* 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)
+ 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 +674,9 @@
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
--- a/sbin/md5/tests/Makefile
+++ b/sbin/md5/tests/Makefile
@@ -32,6 +32,7 @@
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
--- /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
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 9, 3:38 AM (17 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28532659
Default Alt Text
D30812.id91331.diff (10 KB)
Attached To
Mode
D30812: Add support for -c option to sha256sum et.al.
Attached
Detach File
Event Timeline
Log In to Comment