On 01/11/15 16:51, Pádraig Brady wrote:
> On 10/12/10 00:38, Pádraig Brady wrote:
>> On 09/12/10 03:14, Luther wrote:
>>> Normally, when I use md5sum, it's when I download a file and an MD5SUMS
>>> file that comes with it. This MD5SUMS file usually lists many files
>>> including the one I downloaded. When I run 'md5sum -c MD5SUMS', I get
>>> many error messages about files that I don't have. Obviously, I don't
>>> care about the files I didn't download, and the error messages make it
>>> difficult to see the output relating to the file that I do care about.
>>>
>>> I suggest a new option, -i/--ignore-missing, which ignores any filenames
>>> that do not exist on the filesystem.
>>>
>>> In my patch, the option simply suppresses both relevant error messages.
>>> Another approach might be to have digest_check check to see if the file
>>> exists. If it doesn't, don't call digest_file or print the 'FAILED'
>>> message.
>>>
>>> Sorry if my patch is a little messy, being in 3 parts. I'm not used to
>>> using git.
>>>
>>> HTH, and let me know what you think...
>>> Luther
>>
>> Thanks for the patch,
>> and sorry for the mailing list delay
>> (I'm not sure what moderation is done on these lists)
>>
>> So you would like to filter out the warnings.
>> Well they go to stderr, so you could just:
>>
>>   md5sum -c file.sum 2>/dev/null
>>
>> If you wanted to filter further to just FAILED you could:
>>
>>   md5sum -c file.sum 2>/dev/null | grep FAILED$
>>
>> It has the disadvantage of being longer to type
>> but the advantage of using existing tools and
>> options to do the filtering.  So at first glance
>> this option doesn't seem needed.
> 
> There was another request for this at
> https://bugzilla.redhat.com/1276664
> 
> Thinking further, one reason we might consider this is because
> currently open() and read() errors are not distinguished.
> You would want to treat a read() error like a checksum error,
> and not like an open()==ENOENT. Also other errors from open()
> should not be treated like ENOENT.
> 
> Another reason is because grep -E '(OK|FAILED)$' is locale dependent,
> so one would need LC_ALL=C md5sum ... | grep ...
> 
> Given the above and how common this use case is,
> I'd now be 60:40 for adding Luther's patch.

Updated patch attached.

cheers,
Pádraig.
From f664e7e87b979503f263334caa02cc0525b77c43 Mon Sep 17 00:00:00 2001
From: Luther Thompson <[email protected]>
Date: Sun, 22 Nov 2015 21:47:59 +0000
Subject: [PATCH] md5sum, sha*sum: add --ignore-missing for checking a subset
 of files

* doc/coreutils.texi (md5sum invocation): Document the new option.
* src/md5sum.c (digest_file): Return an empty digest to indicate
a missing file.
(digest_check): don't fail or output status given an empty checksum.
(usage): Document the new option.
(main): Process and validate the new option.
* tests/misc/md5sum.pl: Add new test cases.
* NEWS: Mention the new feature.
---
 NEWS                 |  4 ++++
 doc/coreutils.texi   |  8 ++++++++
 src/md5sum.c         | 39 +++++++++++++++++++++++++++++++++------
 tests/misc/md5sum.pl | 23 +++++++++++++++++++++++
 4 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index fc5e927..9f6bff2 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,10 @@ GNU coreutils NEWS                                    -*- 
outline -*-
 
 ** New features
 
+  md5sum now supports the --ignore-missing option to allow
+  verifying a subset of files given a larger list of checksums.
+  This also affects sha1sum, sha224sum, sha256sum, sha384sum and sha512sum.
+
   printf now supports the '%q' format to print arguments in a form that
   is reusable by most shells, with non-printable characters escaped
   with the POSIX proposed $'...' syntax.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 0e28f49..7918aec 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -3830,6 +3830,14 @@ an MD5 checksum inconsistent with the associated file, 
or if no valid
 line is found, @command{md5sum} exits with nonzero status.  Otherwise,
 it exits successfully.
 
+@item --ignore-missing
+@opindex --ignore-missing
+@cindex verifying MD5 checksums
+This option is useful only when verifying checksums.
+When verifying checksums, don't fail or report any status
+for missing files.  This is useful when verifying a subset
+of downloaded files given a larger list of checksums.
+
 @item --quiet
 @opindex --quiet
 @cindex verifying MD5 checksums
diff --git a/src/md5sum.c b/src/md5sum.c
index 5d4b958..8990f1a 100644
--- a/src/md5sum.c
+++ b/src/md5sum.c
@@ -119,6 +119,9 @@ static bool status_only = false;
    improperly formatted checksum line.  */
 static bool warn = false;
 
+/* With --check, ignore missing files.  */
+static bool ignore_missing = false;
+
 /* With --check, suppress the "OK" printed for each verified file.  */
 static bool quiet = false;
 
@@ -133,7 +136,8 @@ static int bsd_reversed = -1;
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
 {
-  STATUS_OPTION = CHAR_MAX + 1,
+  IGNORE_MISSING_OPTION = CHAR_MAX + 1,
+  STATUS_OPTION,
   QUIET_OPTION,
   STRICT_OPTION,
   TAG_OPTION
@@ -143,6 +147,7 @@ static struct option const long_options[] =
 {
   { "binary", no_argument, NULL, 'b' },
   { "check", no_argument, NULL, 'c' },
+  { "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION},
   { "quiet", no_argument, NULL, QUIET_OPTION },
   { "status", no_argument, NULL, STATUS_OPTION },
   { "text", no_argument, NULL, 't' },
@@ -197,7 +202,8 @@ Print or check %s (%d-bit) checksums.\n\
 "), stdout);
       fputs (_("\
 \n\
-The following four options are useful only when verifying checksums:\n\
+The following five options are useful only when verifying checksums:\n\
+      --ignore-missing  don't fail or report status for missing files\n\
       --quiet          don't print OK for each successfully verified file\n\
       --status         don't output anything, status code shows success\n\
       --strict         exit non-zero for improperly formatted checksum lines\n\
@@ -482,6 +488,11 @@ digest_file (const char *filename, int *binary, unsigned 
char *bin_result)
       fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r"));
       if (fp == NULL)
         {
+          if (ignore_missing && errno == ENOENT)
+            {
+              *bin_result = '\0';
+              return true;
+            }
           error (0, errno, "%s", quotef (filename));
           return false;
         }
@@ -597,6 +608,7 @@ digest_check (const char *checkfile_name)
 
           ++n_properly_formatted_lines;
 
+          *bin_buffer = '\1'; /* flag set to 0 for ignored missing files.  */
           ok = digest_file (filename, &binary, bin_buffer);
 
           if (!ok)
@@ -613,10 +625,14 @@ digest_check (const char *checkfile_name)
           else
             {
               size_t digest_bin_bytes = digest_hex_bytes / 2;
-              size_t cnt;
+              size_t cnt = 0;
+
+              if (ignore_missing && ! *bin_buffer)
+                cnt = digest_bin_bytes;
+
               /* Compare generated binary number with text representation
                  in check file.  Ignore case of hex digits.  */
-              for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
+              for (;cnt < digest_bin_bytes; ++cnt)
                 {
                   if (tolower (hex_digest[2 * cnt])
                       != bin2hex[bin_buffer[cnt] >> 4]
@@ -629,7 +645,7 @@ digest_check (const char *checkfile_name)
 
               if (!status_only)
                 {
-                  if (cnt != digest_bin_bytes || ! quiet)
+                  if (cnt != digest_bin_bytes || (! quiet && *bin_buffer))
                     {
                       if (needs_escape)
                         putchar ('\\');
@@ -638,7 +654,7 @@ digest_check (const char *checkfile_name)
 
                   if (cnt != digest_bin_bytes)
                     printf (": %s\n", _("FAILED"));
-                  else if (!quiet)
+                  else if (!quiet && *bin_buffer)
                     printf (": %s\n", _("OK"));
                 }
             }
@@ -749,6 +765,9 @@ main (int argc, char **argv)
         warn = true;
         quiet = false;
         break;
+      case IGNORE_MISSING_OPTION:
+        ignore_missing = true;
+        break;
       case QUIET_OPTION:
         status_only = false;
         warn = false;
@@ -795,6 +814,14 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
+  if (ignore_missing && !do_check)
+    {
+      error (0, 0,
+             _("the --ignore-missing option is meaningful only when "
+               "verifying checksums"));
+      usage (EXIT_FAILURE);
+    }
+
   if (status_only && !do_check)
     {
       error (0, 0,
diff --git a/tests/misc/md5sum.pl b/tests/misc/md5sum.pl
index ad1896d..22a941f 100755
--- a/tests/misc/md5sum.pl
+++ b/tests/misc/md5sum.pl
@@ -25,6 +25,8 @@ my $prog = 'md5sum';
 
 my $degenerate = "d41d8cd98f00b204e9800998ecf8427e";
 
+my $try_help = "Try 'md5sum --help' for more information.\n";
+
 my @Tests =
     (
      ['1', {IN=> {f=> ''}},    {OUT=>"$degenerate  f\n"}],
@@ -120,6 +122,27 @@ my @Tests =
      ['check-openssl3', '--check', '--status',
                                 {IN=> {'f.md5' => "MD5(f)= $degenerate\n"}},
                                 {AUX=> {f=> 'bar'}}, {EXIT=> 1}],
+     ['check-ignore-missing-1', '--check', '--ignore-missing',
+                                {AUX=> {f=> ''}},
+                                {IN=> {'f.md5' => "$degenerate  f\n".
+                                                  "$degenerate  f.missing\n"}},
+                                {OUT=>"f: OK\n"}],
+     ['check-ignore-missing-2', '--check', '--ignore-missing',
+                                {AUX=> {f=> ''}},
+                                {IN=> {'f.md5' => "$degenerate  f\n".
+                                                  "$degenerate  f.missing\n"}},
+                                {OUT=>"f: OK\n"}],
+     ['check-ignore-missing-3', '--check', '--quiet', '--ignore-missing',
+                                {AUX=> {f=> ''}},
+                                {IN=> {'f.md5' => "$degenerate  f.missing\n".
+                                                  "$degenerate  f\n"}},
+                                {OUT=>""}],
+     ['check-ignore-missing-4', '--ignore-missing',
+                                {IN=> {f=> ''}},
+                                {ERR=>"md5sum: the --ignore-missing option is 
".
+                                   "meaningful only when verifying 
checksums\n".
+                                   $try_help},
+                                {EXIT=> 1}],
      ['bsd-segv', '--check', {IN=> {'z' => "MD5 ("}}, {EXIT=> 1},
       {ERR=> "$prog: z: no properly formatted MD5 checksum lines found\n"}],
 
-- 
2.5.0

Reply via email to