Page MenuHomeFreeBSD

D30812.id91331.diff
No OneTemporary

D30812.id91331.diff

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

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)

Event Timeline