git: 1288891878d9 - stable/14 - md5: Accept "-" as alias for stdin.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Sat, 24 Feb 2024 12:15:01 UTC
The branch stable/14 has been updated by des:

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

commit 1288891878d9a194af8c170bb6a33c06e306e0e0
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2024-02-16 12:36:58 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2024-02-24 12:12:49 +0000

    md5: Accept "-" as alias for stdin.
    
    (based on a patch by jhb)
    
    MFC after:      1 week
    PR:             276915
    Reported by:    Hannes Hauswedell <h2+fbsdports@fsfe.org>
    Reviewed by:    allanjude, markj, jhb, emaste
    Differential Revision:  https://reviews.freebsd.org/D43870
    
    (cherry picked from commit 72ee91fed4cfdcfbfb767cc166370b40e50d446a)
    
    md5: Ignore files in string and passthrough mode.
    
    MFC after:      1 week
    Reviewed by:    allanjude, markj
    Differential Revision:  https://reviews.freebsd.org/D43871
    
    (cherry picked from commit 5b44edb4058365ba8e4ccfdb5176c1cddd4394fe)
    
    md5: Clean up input stream rights.
    
    Keep it simple, caph_limit_stdio() and fileargs_fopen() already take
    care of everything for us.
    
    MFC after:      1 week
    Reviewed by:    markj, jhb, emaste
    Differential Revision:  https://reviews.freebsd.org/D43897
    
    (cherry picked from commit 17d5b027c1921d0c6ba2de7993dd808dbf4df078)
    
    md5: Add test case for GNU input modes.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    allanjude, markj
    Differential Revision:  https://reviews.freebsd.org/D43988
    
    (cherry picked from commit e7308a60a5b77a1e4aff6e27eddef40fedabb98c)
    
    md5: Fix Perl mode long options.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    imp, allanjude, markj
    Differential Revision:  https://reviews.freebsd.org/D43989
    
    (cherry picked from commit 4db7ca24470576948e33f48033cfa5be2749950e)
    
    md5: Fix GNU check mode.
    
    Fixes:          9b20849bc5f1b500f2de7aeca77f0e6556069bbb
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    imp, allanjude, markj
    Differential Revision:  https://reviews.freebsd.org/D43990
    
    (cherry picked from commit c05533d97ac178f8e811407860d47d3c0ae61eed)
    
    md5: Untabify declarations.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    imp, allanjude, markj
    Differential Revision:  https://reviews.freebsd.org/D43991
    
    (cherry picked from commit 702f133fa18185a7e10e66316e8f158be935b696)
---
 sbin/md5/md5.1             |   9 +++-
 sbin/md5/md5.c             | 101 +++++++++++++++++++++++----------------------
 sbin/md5/tests/md5_test.sh |  35 ++++++++++++++++
 3 files changed, 95 insertions(+), 50 deletions(-)

diff --git a/sbin/md5/md5.1 b/sbin/md5/md5.1
index 0cdfff928211..0a8dc46f3b1f 100644
--- a/sbin/md5/md5.1
+++ b/sbin/md5/md5.1
@@ -1,4 +1,4 @@
-.Dd May 10, 2023
+.Dd February 13, 2024
 .Dt MD5 1
 .Os
 .Sh NAME
@@ -79,6 +79,11 @@ utility does the same, but with command-line options and an output
 format that match those of the similarly named utility that ships with
 Perl.
 .Pp
+In all cases, each file listed on the command line is processed separately.
+If no files are listed on the command line, or a file name is given as
+.Pa - ,
+input is taken from stdin instead.
+.Pp
 It is conjectured that it is computationally infeasible to
 produce two messages having the same message digest, or to produce any
 message having a given prespecified target message digest.
@@ -124,6 +129,7 @@ option, the calculated digest is printed in addition to the exit status being se
 .Pq Note that this option is not yet useful if multiple files are specified.
 .It Fl p , -passthrough
 Echo stdin to stdout and append the checksum to stdout.
+In this mode, any files specified on the command line are silently ignored.
 .It Fl q , -quiet
 Quiet mode \(em only the checksum is printed out.
 Overrides the
@@ -141,6 +147,7 @@ options.
 .It Fl s Ar string , Fl -string= Ns Ar string
 Print a checksum of the given
 .Ar string .
+In this mode, any files specified on the command line are silently ignored.
 .It Fl t , Fl -time-trial
 Run a built-in time trial.
 For the
diff --git a/sbin/md5/md5.c b/sbin/md5/md5.c
index eb9a2ffae1cc..1bf897d119c0 100644
--- a/sbin/md5/md5.c
+++ b/sbin/md5/md5.c
@@ -264,7 +264,8 @@ static const char *gnu_shortopts = "bctwz";
 
 static const struct option perl_longopts[] = {
 	{ "algorithm",		required_argument,	0, opt_algorithm },
-	{ "check",		required_argument,	0, opt_check },
+	{ "binary",		no_argument,		0, opt_binary },
+	{ "check",		no_argument,		0, opt_check },
 	{ "help",		no_argument,		0, opt_help },
 	{ "ignore-missing",	no_argument,		0, opt_ignore_missing },
 	{ "quiet",		no_argument,		0, opt_quiet },
@@ -287,9 +288,10 @@ MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
 }
 
 struct chksumrec {
-	char	*filename;
-	char	*chksum;
-	struct	chksumrec	*next;
+	char *filename;
+	enum input_mode input_mode;
+	char *chksum;
+	struct chksumrec *next;
 };
 
 static struct chksumrec *head = NULL;
@@ -302,17 +304,17 @@ static unsigned int numrecs;
 static void
 gnu_check(const char *checksumsfile)
 {
-	FILE	*inp;
-	char	*linebuf = NULL;
-	size_t	linecap;
-	ssize_t	linelen;
-	int	lineno;
-	char	*filename;
-	char	*hashstr;
-	struct chksumrec	*rec;
-	const char	*digestname;
-	size_t	digestnamelen;
-	size_t	hashstrlen;
+	FILE *inp;
+	char *linebuf = NULL;
+	size_t linecap;
+	ssize_t linelen;
+	int lineno;
+	char *filename;
+	char *hashstr;
+	struct chksumrec *rec;
+	const char *digestname;
+	size_t digestnamelen;
+	size_t hashstrlen;
 	struct stat st;
 
 	if (strcmp(checksumsfile, "-") == 0)
@@ -362,16 +364,18 @@ gnu_check(const char *checksumsfile)
 		if (rec == NULL)
 			errx(1, "malloc failed");
 
-		if (*filename == '*' ||
-		    *filename == ' ' ||
-		    *filename == 'U' ||
-		    *filename == '^') {
-			if (lstat(filename, &st) != 0)
-				filename++;
+		if ((*filename == '*' || *filename == ' ' ||
+		    *filename == 'U' || *filename == '^') &&
+		    lstat(filename, &st) != 0 &&
+		    lstat(filename + 1, &st) == 0) {
+			rec->filename = strdup(filename + 1);
+			rec->input_mode = (enum input_mode)*filename;
+		} else {
+			rec->filename = strdup(filename);
+			rec->input_mode = input_mode;
 		}
 
 		rec->chksum = strdup(hashstr);
-		rec->filename = strdup(filename);
 		if (rec->chksum == NULL || rec->filename == NULL)
 			errx(1, "malloc failed");
 		rec->next = NULL;
@@ -396,17 +400,17 @@ int
 main(int argc, char *argv[])
 {
 #ifdef HAVE_CAPSICUM
-	cap_rights_t	rights;
-	fileargs_t	*fa = NULL;
+	cap_rights_t rights;
+	fileargs_t *fa = NULL;
 #endif
 	const struct option *longopts;
 	const char *shortopts;
-	FILE   *f;
-	int	i, opt;
-	char   *p, *string = NULL;
-	char	buf[HEX_DIGEST_LENGTH];
-	size_t	len;
-	struct chksumrec	*rec;
+	FILE *f;
+	int i, opt;
+	char *p, *string = NULL;
+	char buf[HEX_DIGEST_LENGTH];
+	size_t len;
+	struct chksumrec *rec;
 
 	if ((progname = strrchr(argv[0], '/')) == NULL)
 		progname = argv[0];
@@ -575,7 +579,7 @@ main(int argc, char *argv[])
 	argv += optind;
 
 #ifdef HAVE_CAPSICUM
-	if (caph_limit_stdout() < 0 || caph_limit_stderr() < 0)
+	if (caph_limit_stdio() < 0)
 		err(1, "unable to limit rights for stdio");
 #endif
 
@@ -607,41 +611,40 @@ main(int argc, char *argv[])
 		err(1, "Unable to enter capability mode");
 #endif
 
-	if (*argv) {
+	if (*argv && !pflag && string == NULL) {
 		do {
 			const char *filename = *argv;
 			const char *filemode = "rb";
 
+			if (cflag && mode != mode_bsd) {
+				input_mode = rec->input_mode;
+				checkAgainst = rec->chksum;
+				rec = rec->next;
+			}
+			if (input_mode == input_text)
+				filemode = "r";
+			if (strcmp(filename, "-") == 0) {
+				f = stdin;
+			} else {
 #ifdef HAVE_CAPSICUM
-			if ((f = fileargs_fopen(fa, filename, filemode)) == NULL) {
+				f = fileargs_fopen(fa, filename, filemode);
 #else
-			if ((f = fopen(filename, filemode)) == NULL) {
+				f = fopen(filename, filemode);
 #endif
+			}
+			if (f == NULL) {
 				if (errno != ENOENT || !(cflag && ignoreMissing)) {
 					warn("%s", filename);
 					failed = true;
 				}
-				if (cflag && mode != mode_bsd)
-					rec = rec->next;
 				continue;
 			}
-#ifdef HAVE_CAPSICUM
-			if (caph_rights_limit(fileno(f), &rights) < 0)
-				err(1, "capsicum");
-#endif
-			if (cflag && mode != mode_bsd) {
-				checkAgainst = rec->chksum;
-				rec = rec->next;
-			}
 			p = MDInput(&Algorithm[digest], f, buf, false);
-			(void)fclose(f);
+			if (f != stdin)
+				(void)fclose(f);
 			MDOutput(&Algorithm[digest], p, filename);
 		} while (*++argv);
 	} else if (!cflag && string == NULL && !skip) {
-#ifdef HAVE_CAPSICUM
-		if (caph_limit_stdin() < 0)
-			err(1, "capsicum");
-#endif
 		if (mode == mode_bsd)
 			output_mode = output_bare;
 		p = MDInput(&Algorithm[digest], stdin, buf, pflag);
diff --git a/sbin/md5/tests/md5_test.sh b/sbin/md5/tests/md5_test.sh
index c6bc1dfd7be0..34bdf43f13ea 100644
--- a/sbin/md5/tests/md5_test.sh
+++ b/sbin/md5/tests/md5_test.sh
@@ -197,11 +197,15 @@ bsd_${alg}_vec${i}_body() {
 	printf '%s' \"\$inp_${i}\" >in
 	atf_check -o inline:\"\$out_${i}_${alg}\n\" ${alg} <in
 	atf_check -o inline:\"\$name_bsd_${alg} (in) = \$out_${i}_${alg}\n\" ${alg} in
+	atf_check -o inline:\"\$name_bsd_${alg} (-) = \$out_${i}_${alg}\n\" ${alg} - <in
 	atf_check -o inline:\"\$out_${i}_${alg} in\n\" ${alg} -r in
+	atf_check -o inline:\"\$out_${i}_${alg} -\n\" ${alg} -r - <in
 	# -q overrides -r regardless of order
 	for opt in -q -qr -rq ; do
 		atf_check -o inline:\"\$out_${i}_${alg}\n\" ${alg} \${opt} in
 	done
+	atf_check -o inline:\"\$inp_${i}\$out_${i}_${alg}\n\" ${alg} -p <in
+	atf_check -o inline:\"\$out_${i}_${alg}\n\" ${alg} -s \"\$inp_${i}\"
 }
 "
 		eval "
@@ -215,9 +219,13 @@ gnu_${alg}_vec${i}_body() {
 	atf_check -o inline:\"\$out_${i}_${alg}  -\n\" ${alg}sum <in
 	atf_check -o inline:\"\$out_${i}_${alg} *-\n\" ${alg}sum -b <in
 	atf_check -o inline:\"\$out_${i}_${alg}  in\n\" ${alg}sum in
+	atf_check -o inline:\"\$out_${i}_${alg}  -\n\" ${alg}sum - <in
 	atf_check -o inline:\"\$out_${i}_${alg} *in\n\" ${alg}sum -b in
+	atf_check -o inline:\"\$out_${i}_${alg} *-\n\" ${alg}sum -b - <in
 	atf_check -o inline:\"\$name_bsd_${alg} (in) = \$out_${i}_${alg}\n\" ${alg}sum --tag in
+	atf_check -o inline:\"\$name_bsd_${alg} (-) = \$out_${i}_${alg}\n\" ${alg}sum --tag - <in
 	atf_check -o inline:\"\$out_${i}_${alg}  in\0\" ${alg}sum -z in
+	atf_check -o inline:\"\$out_${i}_${alg}  -\0\" ${alg}sum -z - <in
 }
 "
 		eval "
@@ -233,9 +241,13 @@ perl_${alg}_vec${i}_body() {
 	atf_check -o inline:\"\$out_${i}_${alg} *-\n\" shasum \$alg_perl_${alg} -b <in
 	atf_check -o inline:\"\$out_${i}_${alg} U-\n\" shasum \$alg_perl_${alg} -U <in
 	atf_check -o inline:\"\$out_${i}_${alg}  in\n\" shasum \$alg_perl_${alg} in
+	atf_check -o inline:\"\$out_${i}_${alg}  -\n\" shasum \$alg_perl_${alg} - <in
 	atf_check -o inline:\"\$out_${i}_${alg} *in\n\" shasum \$alg_perl_${alg} -b in
+	atf_check -o inline:\"\$out_${i}_${alg} *-\n\" shasum \$alg_perl_${alg} -b - <in
 	atf_check -o inline:\"\$out_${i}_${alg} Uin\n\" shasum \$alg_perl_${alg} -U in
+	atf_check -o inline:\"\$out_${i}_${alg} U-\n\" shasum \$alg_perl_${alg} -U - <in
 	atf_check -o inline:\"\$name_perl_${alg} (in) = \$out_${i}_${alg}\n\" shasum \$alg_perl_${alg} --tag in
+	atf_check -o inline:\"\$name_perl_${alg} (-) = \$out_${i}_${alg}\n\" shasum \$alg_perl_${alg} --tag - <in
 }
 "
 	done
@@ -357,6 +369,28 @@ gnu_cflag_body()
 
 }
 
+atf_test_case gnu_cflag_mode
+gnu_cflag_mode_head()
+{
+	atf_set descr "Verify handling of input modes in GNU check mode"
+	atf_set require.progs "sha1sum"
+}
+gnu_cflag_mode_body()
+{
+	printf "The Magic Words are 01010011 01001111\r\n" >input
+	# The first line is malformed per GNU coreutils but matches
+	# what we produce when mode == mode_bsd && output_mode ==
+	# output_reverse (i.e. `sha1 -r`) so we want to support it.
+	cat >digests <<EOF
+53d88300dfb2be42f0ef25e3d9de798e31bb7e69 input
+53d88300dfb2be42f0ef25e3d9de798e31bb7e69 *input
+53d88300dfb2be42f0ef25e3d9de798e31bb7e69  input
+2290cf6ba4ac5387e520088de760b71a523871b0 ^input
+c1065e0d2bbc1c67dcecee0187d61316fb9c5582 Uinput
+EOF
+	atf_check sha1sum --quiet --check digests
+}
+
 atf_init_test_cases()
 {
 	for alg in $algorithms ; do
@@ -371,4 +405,5 @@ atf_init_test_cases()
 	done
 	atf_add_test_case gnu_bflag
 	atf_add_test_case gnu_cflag
+	atf_add_test_case gnu_cflag_mode
 }