maint: go back to using ‘error’
[coreutils.git] / src / digest.c
blobbc8967e5671261e28e6662501b0f3f2b2f073689
1 /* Compute checksums of files or strings.
2 Copyright (C) 1995-2023 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */
19 #include <config.h>
21 #include <getopt.h>
22 #include <sys/types.h>
24 #include "system.h"
25 #include "argmatch.h"
26 #include "quote.h"
27 #include "xdectoint.h"
28 #include "xstrtol.h"
30 #if HASH_ALGO_SUM || HASH_ALGO_CKSUM
31 # include "sum.h"
32 #endif
33 #if HASH_ALGO_CKSUM
34 # include "cksum.h"
35 # include "base64.h"
36 #endif
37 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
38 # include "blake2/b2sum.h"
39 #endif
40 #if HASH_ALGO_MD5 || HASH_ALGO_CKSUM
41 # include "md5.h"
42 #endif
43 #if HASH_ALGO_SHA1 || HASH_ALGO_CKSUM
44 # include "sha1.h"
45 #endif
46 #if HASH_ALGO_SHA256 || HASH_ALGO_SHA224 || HASH_ALGO_CKSUM
47 # include "sha256.h"
48 #endif
49 #if HASH_ALGO_SHA512 || HASH_ALGO_SHA384 || HASH_ALGO_CKSUM
50 # include "sha512.h"
51 #endif
52 #if HASH_ALGO_CKSUM
53 # include "sm3.h"
54 #endif
55 #include "fadvise.h"
56 #include "stdio--.h"
57 #include "xbinary-io.h"
59 /* The official name of this program (e.g., no 'g' prefix). */
60 #if HASH_ALGO_SUM
61 # define PROGRAM_NAME "sum"
62 # define DIGEST_TYPE_STRING "BSD"
63 # define DIGEST_STREAM sumfns[sum_algorithm]
64 # define DIGEST_OUT sum_output_fns[sum_algorithm]
65 # define DIGEST_BITS 16
66 # define DIGEST_ALIGN 4
67 #elif HASH_ALGO_CKSUM
68 # define MAX_DIGEST_BITS 512
69 # define MAX_DIGEST_ALIGN 8
70 # define PROGRAM_NAME "cksum"
71 # define DIGEST_TYPE_STRING algorithm_tags[cksum_algorithm]
72 # define DIGEST_STREAM cksumfns[cksum_algorithm]
73 # define DIGEST_OUT cksum_output_fns[cksum_algorithm]
74 # define DIGEST_BITS MAX_DIGEST_BITS
75 # define DIGEST_ALIGN MAX_DIGEST_ALIGN
76 #elif HASH_ALGO_MD5
77 # define PROGRAM_NAME "md5sum"
78 # define DIGEST_TYPE_STRING "MD5"
79 # define DIGEST_STREAM md5_stream
80 # define DIGEST_BITS 128
81 # define DIGEST_REFERENCE "RFC 1321"
82 # define DIGEST_ALIGN 4
83 #elif HASH_ALGO_BLAKE2
84 # define PROGRAM_NAME "b2sum"
85 # define DIGEST_TYPE_STRING "BLAKE2b"
86 # define DIGEST_STREAM blake2b_stream
87 # define DIGEST_BITS 512
88 # define DIGEST_REFERENCE "RFC 7693"
89 # define DIGEST_ALIGN 8
90 #elif HASH_ALGO_SHA1
91 # define PROGRAM_NAME "sha1sum"
92 # define DIGEST_TYPE_STRING "SHA1"
93 # define DIGEST_STREAM sha1_stream
94 # define DIGEST_BITS 160
95 # define DIGEST_REFERENCE "FIPS-180-1"
96 # define DIGEST_ALIGN 4
97 #elif HASH_ALGO_SHA256
98 # define PROGRAM_NAME "sha256sum"
99 # define DIGEST_TYPE_STRING "SHA256"
100 # define DIGEST_STREAM sha256_stream
101 # define DIGEST_BITS 256
102 # define DIGEST_REFERENCE "FIPS-180-2"
103 # define DIGEST_ALIGN 4
104 #elif HASH_ALGO_SHA224
105 # define PROGRAM_NAME "sha224sum"
106 # define DIGEST_TYPE_STRING "SHA224"
107 # define DIGEST_STREAM sha224_stream
108 # define DIGEST_BITS 224
109 # define DIGEST_REFERENCE "RFC 3874"
110 # define DIGEST_ALIGN 4
111 #elif HASH_ALGO_SHA512
112 # define PROGRAM_NAME "sha512sum"
113 # define DIGEST_TYPE_STRING "SHA512"
114 # define DIGEST_STREAM sha512_stream
115 # define DIGEST_BITS 512
116 # define DIGEST_REFERENCE "FIPS-180-2"
117 # define DIGEST_ALIGN 8
118 #elif HASH_ALGO_SHA384
119 # define PROGRAM_NAME "sha384sum"
120 # define DIGEST_TYPE_STRING "SHA384"
121 # define DIGEST_STREAM sha384_stream
122 # define DIGEST_BITS 384
123 # define DIGEST_REFERENCE "FIPS-180-2"
124 # define DIGEST_ALIGN 8
125 #else
126 # error "Can't decide which hash algorithm to compile."
127 #endif
128 #if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM
129 # define DIGEST_OUT output_file
130 #endif
132 #if HASH_ALGO_SUM
133 # define AUTHORS \
134 proper_name ("Kayvan Aghaiepour"), \
135 proper_name ("David MacKenzie")
136 #elif HASH_ALGO_CKSUM
137 # define AUTHORS \
138 proper_name ("Padraig Brady"), \
139 proper_name ("Q. Frank Xia")
140 #elif HASH_ALGO_BLAKE2
141 # define AUTHORS \
142 proper_name ("Padraig Brady"), \
143 proper_name ("Samuel Neves")
144 #else
145 # define AUTHORS \
146 proper_name ("Ulrich Drepper"), \
147 proper_name ("Scott Miller"), \
148 proper_name ("David Madore")
149 #endif
150 #if !HASH_ALGO_BLAKE2 && !HASH_ALGO_CKSUM
151 # define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
152 #endif
153 #define DIGEST_BIN_BYTES (DIGEST_BITS / 8)
155 /* The minimum length of a valid digest line. This length does
156 not include any newline character at the end of a line. */
157 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
158 # define MIN_DIGEST_LINE_LENGTH 3 /* With -l 8. */
159 #else
160 # define MIN_DIGEST_LINE_LENGTH \
161 (DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
162 + 1 /* blank */ \
163 + 1 /* minimum filename length */ )
164 #endif
166 #if !HASH_ALGO_SUM
167 static void
168 output_file (char const *file, int binary_file, void const *digest,
169 bool raw, bool tagged, unsigned char delim, bool args,
170 uintmax_t length);
171 #endif
173 /* True if any of the files read were the standard input. */
174 static bool have_read_stdin;
176 /* The minimum length of a valid checksum line for the selected algorithm. */
177 static size_t min_digest_line_length;
179 /* Set to the length of a digest hex string for the selected algorithm. */
180 static size_t digest_hex_bytes;
182 /* With --check, don't generate any output.
183 The exit code indicates success or failure. */
184 static bool status_only = false;
186 /* With --check, print a message to standard error warning about each
187 improperly formatted checksum line. */
188 static bool warn = false;
190 /* With --check, ignore missing files. */
191 static bool ignore_missing = false;
193 /* With --check, suppress the "OK" printed for each verified file. */
194 static bool quiet = false;
196 /* With --check, exit with a non-zero return code if any line is
197 improperly formatted. */
198 static bool strict = false;
200 /* Whether a BSD reversed format checksum is detected. */
201 static int bsd_reversed = -1;
203 /* line delimiter. */
204 static unsigned char digest_delim = '\n';
206 #if HASH_ALGO_CKSUM
207 /* If true, print base64-encoded digests, not hex. */
208 static bool base64_digest = false;
209 #endif
211 /* If true, print binary digests, not hex. */
212 static bool raw_digest = false;
214 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
215 # define BLAKE2B_MAX_LEN BLAKE2B_OUTBYTES
216 static uintmax_t digest_length;
217 #endif /* HASH_ALGO_BLAKE2 */
219 typedef void (*digest_output_fn)(char const *, int, void const *, bool,
220 bool, unsigned char, bool, uintmax_t);
221 #if HASH_ALGO_SUM
222 enum Algorithm
224 bsd,
225 sysv,
228 static enum Algorithm sum_algorithm;
229 static sumfn sumfns[]=
231 bsd_sum_stream,
232 sysv_sum_stream,
234 static digest_output_fn sum_output_fns[]=
236 output_bsd,
237 output_sysv,
239 #endif
241 #if HASH_ALGO_CKSUM
242 static int
243 md5_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
245 return md5_stream (stream, resstream);
247 static int
248 sha1_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
250 return sha1_stream (stream, resstream);
252 static int
253 sha224_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
255 return sha224_stream (stream, resstream);
257 static int
258 sha256_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
260 return sha256_stream (stream, resstream);
262 static int
263 sha384_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
265 return sha384_stream (stream, resstream);
267 static int
268 sha512_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
270 return sha512_stream (stream, resstream);
272 static int
273 blake2b_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
275 return blake2b_stream (stream, resstream, *length);
277 static int
278 sm3_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
280 return sm3_stream (stream, resstream);
283 enum Algorithm
285 bsd,
286 sysv,
287 crc,
288 md5,
289 sha1,
290 sha224,
291 sha256,
292 sha384,
293 sha512,
294 blake2b,
295 sm3,
298 static char const *const algorithm_args[] =
300 "bsd", "sysv", "crc", "md5", "sha1", "sha224",
301 "sha256", "sha384", "sha512", "blake2b", "sm3", nullptr
303 static enum Algorithm const algorithm_types[] =
305 bsd, sysv, crc, md5, sha1, sha224,
306 sha256, sha384, sha512, blake2b, sm3,
308 ARGMATCH_VERIFY (algorithm_args, algorithm_types);
310 static char const *const algorithm_tags[] =
312 "BSD", "SYSV", "CRC", "MD5", "SHA1", "SHA224",
313 "SHA256", "SHA384", "SHA512", "BLAKE2b", "SM3", nullptr
315 static int const algorithm_bits[] =
317 16, 16, 32, 128, 160, 224,
318 256, 384, 512, 512, 256, 0
321 static_assert (ARRAY_CARDINALITY (algorithm_bits)
322 == ARRAY_CARDINALITY (algorithm_args));
324 static bool algorithm_specified = false;
325 static enum Algorithm cksum_algorithm = crc;
326 static sumfn cksumfns[]=
328 bsd_sum_stream,
329 sysv_sum_stream,
330 crc_sum_stream,
331 md5_sum_stream,
332 sha1_sum_stream,
333 sha224_sum_stream,
334 sha256_sum_stream,
335 sha384_sum_stream,
336 sha512_sum_stream,
337 blake2b_sum_stream,
338 sm3_sum_stream,
340 static digest_output_fn cksum_output_fns[]=
342 output_bsd,
343 output_sysv,
344 output_crc,
345 output_file,
346 output_file,
347 output_file,
348 output_file,
349 output_file,
350 output_file,
351 output_file,
352 output_file,
354 bool cksum_debug;
355 #endif
357 /* For long options that have no equivalent short option, use a
358 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
360 enum
362 IGNORE_MISSING_OPTION = CHAR_MAX + 1,
363 STATUS_OPTION,
364 QUIET_OPTION,
365 STRICT_OPTION,
366 TAG_OPTION,
367 UNTAG_OPTION,
368 DEBUG_PROGRAM_OPTION,
369 RAW_OPTION,
372 static struct option const long_options[] =
374 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
375 { "length", required_argument, nullptr, 'l'},
376 #endif
378 #if !HASH_ALGO_SUM
379 { "check", no_argument, nullptr, 'c' },
380 { "ignore-missing", no_argument, nullptr, IGNORE_MISSING_OPTION},
381 { "quiet", no_argument, nullptr, QUIET_OPTION },
382 { "status", no_argument, nullptr, STATUS_OPTION },
383 { "warn", no_argument, nullptr, 'w' },
384 { "strict", no_argument, nullptr, STRICT_OPTION },
385 { "tag", no_argument, nullptr, TAG_OPTION },
386 { "zero", no_argument, nullptr, 'z' },
388 # if HASH_ALGO_CKSUM
389 { "algorithm", required_argument, nullptr, 'a'},
390 { "base64", no_argument, nullptr, 'b' },
391 { "debug", no_argument, nullptr, DEBUG_PROGRAM_OPTION},
392 { "raw", no_argument, nullptr, RAW_OPTION},
393 { "untagged", no_argument, nullptr, UNTAG_OPTION },
394 # else
395 { "binary", no_argument, nullptr, 'b' },
396 { "text", no_argument, nullptr, 't' },
397 # endif
399 #else
400 {"sysv", no_argument, nullptr, 's'},
401 #endif
403 { GETOPT_HELP_OPTION_DECL },
404 { GETOPT_VERSION_OPTION_DECL },
405 { nullptr, 0, nullptr, 0 }
408 void
409 usage (int status)
411 if (status != EXIT_SUCCESS)
412 emit_try_help ();
413 else
415 printf (_("\
416 Usage: %s [OPTION]... [FILE]...\n\
417 "), program_name);
418 #if HASH_ALGO_CKSUM
419 fputs (_("\
420 Print or verify checksums.\n\
421 By default use the 32 bit CRC algorithm.\n\
422 "), stdout);
423 #else
424 printf (_("\
425 Print or check %s (%d-bit) checksums.\n\
427 DIGEST_TYPE_STRING,
428 DIGEST_BITS);
429 #endif
431 emit_stdin_note ();
432 #if HASH_ALGO_SUM
433 fputs (_("\
435 -r use BSD sum algorithm (the default), use 1K blocks\n\
436 -s, --sysv use System V sum algorithm, use 512 bytes blocks\n\
437 "), stdout);
438 #endif
439 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
440 emit_mandatory_arg_note ();
441 #endif
442 #if HASH_ALGO_CKSUM
443 fputs (_("\
444 -a, --algorithm=TYPE select the digest type to use. See DIGEST below.\
446 "), stdout);
447 fputs (_("\
448 -b, --base64 emit base64-encoded digests, not hexadecimal\
450 "), stdout);
451 #endif
452 #if !HASH_ALGO_SUM
453 # if !HASH_ALGO_CKSUM
454 if (O_BINARY)
455 fputs (_("\
456 -b, --binary read in binary mode (default unless reading tty stdin)\
458 "), stdout);
459 else
460 fputs (_("\
461 -b, --binary read in binary mode\n\
462 "), stdout);
463 # endif
464 fputs (_("\
465 -c, --check read checksums from the FILEs and check them\n\
466 "), stdout);
467 # if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
468 fputs (_("\
469 -l, --length=BITS digest length in bits; must not exceed the max for\n\
470 the blake2 algorithm and must be a multiple of 8\n\
471 "), stdout);
472 # endif
473 # if HASH_ALGO_CKSUM
474 fputs (_("\
475 --raw emit a raw binary digest, not hexadecimal\
477 "), stdout);
478 fputs (_("\
479 --tag create a BSD-style checksum (the default)\n\
480 "), stdout);
481 fputs (_("\
482 --untagged create a reversed style checksum, without digest type\n\
483 "), stdout);
484 # else
485 fputs (_("\
486 --tag create a BSD-style checksum\n\
487 "), stdout);
488 # endif
489 # if !HASH_ALGO_CKSUM
490 if (O_BINARY)
491 fputs (_("\
492 -t, --text read in text mode (default if reading tty stdin)\n\
493 "), stdout);
494 else
495 fputs (_("\
496 -t, --text read in text mode (default)\n\
497 "), stdout);
498 # endif
499 fputs (_("\
500 -z, --zero end each output line with NUL, not newline,\n\
501 and disable file name escaping\n\
502 "), stdout);
503 fputs (_("\
505 The following five options are useful only when verifying checksums:\n\
506 --ignore-missing don't fail or report status for missing files\n\
507 --quiet don't print OK for each successfully verified file\n\
508 --status don't output anything, status code shows success\n\
509 --strict exit non-zero for improperly formatted checksum lines\n\
510 -w, --warn warn about improperly formatted checksum lines\n\
512 "), stdout);
513 #endif
514 #if HASH_ALGO_CKSUM
515 fputs (_("\
516 --debug indicate which implementation used\n\
517 "), stdout);
518 #endif
519 fputs (HELP_OPTION_DESCRIPTION, stdout);
520 fputs (VERSION_OPTION_DESCRIPTION, stdout);
521 #if HASH_ALGO_CKSUM
522 fputs (_("\
524 DIGEST determines the digest algorithm and default output format:\n\
525 sysv (equivalent to sum -s)\n\
526 bsd (equivalent to sum -r)\n\
527 crc (equivalent to cksum)\n\
528 md5 (equivalent to md5sum)\n\
529 sha1 (equivalent to sha1sum)\n\
530 sha224 (equivalent to sha224sum)\n\
531 sha256 (equivalent to sha256sum)\n\
532 sha384 (equivalent to sha384sum)\n\
533 sha512 (equivalent to sha512sum)\n\
534 blake2b (equivalent to b2sum)\n\
535 sm3 (only available through cksum)\n\
536 \n"), stdout);
537 #endif
538 #if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM
539 printf (_("\
541 The sums are computed as described in %s.\n"), DIGEST_REFERENCE);
542 fputs (_("\
543 When checking, the input should be a former output of this program.\n\
544 The default mode is to print a line with: checksum, a space,\n\
545 a character indicating input mode ('*' for binary, ' ' for text\n\
546 or where binary is insignificant), and name for each FILE.\n\
548 Note: There is no difference between binary mode and text mode on GNU systems.\
549 \n"), stdout);
550 #endif
551 #if HASH_ALGO_CKSUM
552 fputs (_("\
553 When checking, the input should be a former output of this program,\n\
554 or equivalent standalone program.\
555 \n"), stdout);
556 #endif
557 emit_ancillary_info (PROGRAM_NAME);
560 exit (status);
563 #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
565 /* Given a file name, S of length S_LEN, that is not NUL-terminated,
566 modify it in place, performing the equivalent of this sed substitution:
567 's/\\n/\n/g;s/\\r/\r/g;s/\\\\/\\/g' i.e., replacing each "\\n" string
568 with a newline, each "\\r" string with a carriage return,
569 and each "\\\\" with a single backslash, NUL-terminate it and return S.
570 If S is not a valid escaped file name, i.e., if it ends with an odd number
571 of backslashes or if it contains a backslash followed by anything other
572 than "n" or another backslash, return nullptr. */
574 static char *
575 filename_unescape (char *s, size_t s_len)
577 char *dst = s;
579 for (size_t i = 0; i < s_len; i++)
581 switch (s[i])
583 case '\\':
584 if (i == s_len - 1)
586 /* File name ends with an unescaped backslash: invalid. */
587 return nullptr;
589 ++i;
590 switch (s[i])
592 case 'n':
593 *dst++ = '\n';
594 break;
595 case 'r':
596 *dst++ = '\r';
597 break;
598 case '\\':
599 *dst++ = '\\';
600 break;
601 default:
602 /* Only '\', 'n' or 'r' may follow a backslash. */
603 return nullptr;
605 break;
607 case '\0':
608 /* The file name may not contain a NUL. */
609 return nullptr;
611 default:
612 *dst++ = s[i];
613 break;
616 if (dst < s + s_len)
617 *dst = '\0';
619 return s;
622 /* Return true if S is a LEN-byte NUL-terminated string of hex or base64
623 digits and has the expected length. Otherwise, return false. */
624 ATTRIBUTE_PURE
625 static bool
626 valid_digits (unsigned char const *s, size_t len)
628 #if HASH_ALGO_CKSUM
629 if (len == BASE64_LENGTH (digest_length / 8))
631 size_t i;
632 for (i = 0; i < len - digest_length % 3; i++)
634 if (!isbase64 (*s))
635 return false;
636 ++s;
638 for ( ; i < len; i++)
640 if (*s != '=')
641 return false;
642 ++s;
645 else
646 #endif
647 if (len == digest_hex_bytes)
649 for (unsigned int i = 0; i < digest_hex_bytes; i++)
651 if (!isxdigit (*s))
652 return false;
653 ++s;
656 else
657 return false;
659 return *s == '\0';
662 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
663 'sha1' command into two parts: a hexadecimal digest, and the file
664 name. S is modified. Set *D_LEN to the length of the digest string.
665 Return true if successful. */
667 static bool
668 bsd_split_3 (char *s, size_t s_len,
669 unsigned char **digest, size_t *d_len,
670 char **file_name, bool escaped_filename)
672 if (s_len == 0)
673 return false;
675 /* Find end of filename. */
676 size_t i = s_len - 1;
677 while (i && s[i] != ')')
678 i--;
680 if (s[i] != ')')
681 return false;
683 *file_name = s;
685 if (escaped_filename && filename_unescape (s, i) == nullptr)
686 return false;
688 s[i++] = '\0';
690 while (ISWHITE (s[i]))
691 i++;
693 if (s[i] != '=')
694 return false;
696 i++;
698 while (ISWHITE (s[i]))
699 i++;
701 *digest = (unsigned char *) &s[i];
703 *d_len = s_len - i;
704 return valid_digits (*digest, *d_len);
707 #if HASH_ALGO_CKSUM
708 /* Return the corresponding Algorithm for the string S,
709 or -1 for no match. */
711 static ptrdiff_t
712 algorithm_from_tag (char *s)
714 /* Limit check size to this length for perf reasons. */
715 static size_t max_tag_len;
716 if (! max_tag_len)
718 char const * const * tag = algorithm_tags;
719 while (*tag)
721 size_t tag_len = strlen (*tag++);
722 max_tag_len = MAX (tag_len, max_tag_len);
726 size_t i = 0;
728 /* Find end of tag */
729 while (i <= max_tag_len && s[i] && ! ISWHITE (s[i])
730 && s[i] != '-' && s[i] != '(')
731 ++i;
733 if (i > max_tag_len)
734 return -1;
736 /* Terminate tag, and lookup. */
737 char sep = s[i];
738 s[i] = '\0';
739 ptrdiff_t algo = argmatch_exact (s, algorithm_tags);
740 s[i] = sep;
742 return algo;
744 #endif
746 /* Split the string S (of length S_LEN) into three parts:
747 a hexadecimal digest, binary flag, and the file name.
748 S is modified. Set *D_LEN to the length of the digest string.
749 Return true if successful. */
751 static bool
752 split_3 (char *s, size_t s_len,
753 unsigned char **digest, size_t *d_len, int *binary, char **file_name)
755 bool escaped_filename = false;
756 size_t algo_name_len;
758 size_t i = 0;
759 while (ISWHITE (s[i]))
760 ++i;
762 if (s[i] == '\\')
764 ++i;
765 escaped_filename = true;
768 /* Check for BSD-style checksum line. */
770 #if HASH_ALGO_CKSUM
771 if (! algorithm_specified)
773 ptrdiff_t algo_tag = algorithm_from_tag (s + i);
774 if (algo_tag >= 0)
776 if (algo_tag <= crc)
777 return false; /* We don't support checking these older formats. */
778 cksum_algorithm = algo_tag;
780 else
781 return false; /* We only support tagged format without -a. */
783 #endif
785 algo_name_len = strlen (DIGEST_TYPE_STRING);
786 if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
788 i += algo_name_len;
789 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
790 /* Terminate and match algorithm name. */
791 char const *algo_name = &s[i - algo_name_len];
792 bool length_specified = s[i] == '-';
793 bool openssl_format = s[i] == '('; /* and no length_specified */
794 s[i++] = '\0';
795 if (!STREQ (algo_name, DIGEST_TYPE_STRING))
796 return false;
797 if (openssl_format)
798 s[--i] = '(';
800 # if HASH_ALGO_BLAKE2
801 digest_length = BLAKE2B_MAX_LEN * 8;
802 # else
803 digest_length = algorithm_bits[cksum_algorithm];
804 # endif
805 if (length_specified)
807 uintmax_t length;
808 char *siend;
809 if (! (xstrtoumax (s + i, &siend, 0, &length, nullptr) == LONGINT_OK
810 && 0 < length && length <= digest_length
811 && length % 8 == 0))
812 return false;
814 i = siend - s;
815 digest_length = length;
817 digest_hex_bytes = digest_length / 4;
818 #endif
819 if (s[i] == ' ')
820 ++i;
821 if (s[i] == '(')
823 ++i;
824 *binary = 0;
825 return bsd_split_3 (s + i, s_len - i,
826 digest, d_len, file_name, escaped_filename);
828 return false;
831 /* Ignore this line if it is too short.
832 Each line must have at least 'min_digest_line_length - 1' (or one more, if
833 the first is a backslash) more characters to contain correct message digest
834 information. */
835 if (s_len - i < min_digest_line_length + (s[i] == '\\'))
836 return false;
838 *digest = (unsigned char *) &s[i];
840 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
841 /* Auto determine length. */
842 # if HASH_ALGO_CKSUM
843 if (cksum_algorithm == blake2b) {
844 # endif
845 unsigned char const *hp = *digest;
846 digest_hex_bytes = 0;
847 while (isxdigit (*hp++))
848 digest_hex_bytes++;
849 if (digest_hex_bytes < 2 || digest_hex_bytes % 2
850 || BLAKE2B_MAX_LEN * 2 < digest_hex_bytes)
851 return false;
852 digest_length = digest_hex_bytes * 4;
853 # if HASH_ALGO_CKSUM
855 # endif
856 #endif
858 /* This field must be the hexadecimal or base64 representation
859 of the message digest. */
860 while (s[i] && !ISWHITE (s[i]))
861 i++;
863 /* The digest must be followed by at least one whitespace character. */
864 if (i == s_len)
865 return false;
867 *d_len = &s[i] - (char *) *digest;
868 s[i++] = '\0';
870 if (! valid_digits (*digest, *d_len))
871 return false;
873 /* If "bsd reversed" format detected. */
874 if ((s_len - i == 1) || (s[i] != ' ' && s[i] != '*'))
876 /* Don't allow mixing bsd and standard formats,
877 to minimize security issues with attackers
878 renaming files with leading spaces.
879 This assumes that with bsd format checksums
880 that the first file name does not have
881 a leading ' ' or '*'. */
882 if (bsd_reversed == 0)
883 return false;
884 bsd_reversed = 1;
886 else if (bsd_reversed != 1)
888 bsd_reversed = 0;
889 *binary = (s[i++] == '*');
892 /* All characters between the type indicator and end of line are
893 significant -- that includes leading and trailing white space. */
894 *file_name = &s[i];
896 if (escaped_filename)
897 return filename_unescape (&s[i], s_len - i) != nullptr;
899 return true;
902 /* If ESCAPE is true, then translate each:
903 NEWLINE byte to the string, "\\n",
904 CARRIAGE RETURN byte to the string, "\\r",
905 and each backslash to "\\\\". */
906 static void
907 print_filename (char const *file, bool escape)
909 if (! escape)
911 fputs (file, stdout);
912 return;
915 while (*file)
917 switch (*file)
919 case '\n':
920 fputs ("\\n", stdout);
921 break;
923 case '\r':
924 fputs ("\\r", stdout);
925 break;
927 case '\\':
928 fputs ("\\\\", stdout);
929 break;
931 default:
932 putchar (*file);
933 break;
935 file++;
939 /* An interface to the function, DIGEST_STREAM.
940 Operate on FILENAME (it may be "-").
942 *BINARY indicates whether the file is binary. BINARY < 0 means it
943 depends on whether binary mode makes any difference and the file is
944 a terminal; in that case, clear *BINARY if the file was treated as
945 text because it was a terminal.
947 Put the checksum in *BIN_RESULT, which must be properly aligned.
948 Put true in *MISSING if the file can't be opened due to ENOENT.
949 Return true if successful. */
951 static bool
952 digest_file (char const *filename, int *binary, unsigned char *bin_result,
953 bool *missing, MAYBE_UNUSED uintmax_t *length)
955 FILE *fp;
956 int err;
957 bool is_stdin = STREQ (filename, "-");
959 *missing = false;
961 if (is_stdin)
963 have_read_stdin = true;
964 fp = stdin;
965 if (O_BINARY && *binary)
967 if (*binary < 0)
968 *binary = ! isatty (STDIN_FILENO);
969 if (*binary)
970 xset_binary_mode (STDIN_FILENO, O_BINARY);
973 else
975 fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r"));
976 if (fp == nullptr)
978 if (ignore_missing && errno == ENOENT)
980 *missing = true;
981 return true;
983 error (0, errno, "%s", quotef (filename));
984 return false;
988 fadvise (fp, FADVISE_SEQUENTIAL);
990 #if HASH_ALGO_CKSUM
991 if (cksum_algorithm == blake2b)
992 *length = digest_length / 8;
993 err = DIGEST_STREAM (fp, bin_result, length);
994 #elif HASH_ALGO_SUM
995 err = DIGEST_STREAM (fp, bin_result, length);
996 #elif HASH_ALGO_BLAKE2
997 err = DIGEST_STREAM (fp, bin_result, digest_length / 8);
998 #else
999 err = DIGEST_STREAM (fp, bin_result);
1000 #endif
1001 err = err ? errno : 0;
1002 if (is_stdin)
1003 clearerr (fp);
1004 else if (fclose (fp) != 0 && !err)
1005 err = errno;
1007 if (err)
1009 error (0, err, "%s", quotef (filename));
1010 return false;
1013 return true;
1016 #if !HASH_ALGO_SUM
1017 static void
1018 output_file (char const *file, int binary_file, void const *digest,
1019 bool raw, bool tagged, unsigned char delim, MAYBE_UNUSED bool args,
1020 MAYBE_UNUSED uintmax_t length)
1022 # if HASH_ALGO_CKSUM
1023 if (raw)
1025 fwrite (digest, 1, digest_length / 8, stdout);
1026 return;
1028 # endif
1030 unsigned char const *bin_buffer = digest;
1032 /* Output a leading backslash if the file name contains problematic chars.
1033 Note we escape '\' itself to provide some forward compat to introduce
1034 escaping of other characters. */
1035 bool needs_escape = delim == '\n' && (strchr (file, '\\')
1036 || strchr (file, '\n')
1037 || strchr (file, '\r'));
1038 if (needs_escape)
1039 putchar ('\\');
1041 if (tagged)
1043 fputs (DIGEST_TYPE_STRING, stdout);
1044 # if HASH_ALGO_BLAKE2
1045 if (digest_length < BLAKE2B_MAX_LEN * 8)
1046 printf ("-%"PRIuMAX, digest_length);
1047 # elif HASH_ALGO_CKSUM
1048 if (cksum_algorithm == blake2b)
1050 if (digest_length < BLAKE2B_MAX_LEN * 8)
1051 printf ("-%"PRIuMAX, digest_length);
1053 # endif
1054 fputs (" (", stdout);
1055 print_filename (file, needs_escape);
1056 fputs (") = ", stdout);
1059 # if HASH_ALGO_CKSUM
1060 if (base64_digest)
1062 char b64[BASE64_LENGTH (DIGEST_BIN_BYTES) + 1];
1063 base64_encode ((char const *) bin_buffer, digest_length / 8,
1064 b64, sizeof b64);
1065 fputs (b64, stdout);
1067 else
1068 # endif
1070 for (size_t i = 0; i < (digest_hex_bytes / 2); ++i)
1071 printf ("%02x", bin_buffer[i]);
1074 if (!tagged)
1076 putchar (' ');
1078 # if HASH_ALGO_CKSUM
1079 /* Simplify output as always in binary mode. */
1080 putchar (' ');
1081 # else
1082 putchar (binary_file ? '*' : ' ');
1083 # endif
1085 print_filename (file, needs_escape);
1088 putchar (delim);
1090 #endif
1092 #if HASH_ALGO_CKSUM
1093 /* Return true if B64_DIGEST is the same as the base64 digest of the
1094 DIGEST_LENGTH/8 bytes at BIN_BUFFER. */
1095 static bool
1096 b64_equal (unsigned char const *b64_digest, unsigned char const *bin_buffer)
1098 size_t b64_n_bytes = BASE64_LENGTH (digest_length / 8);
1099 char b64[BASE64_LENGTH (DIGEST_BIN_BYTES) + 1];
1100 base64_encode ((char const *) bin_buffer, digest_length / 8, b64, sizeof b64);
1101 return memcmp (b64_digest, b64, b64_n_bytes + 1) == 0;
1103 #endif
1105 /* Return true if HEX_DIGEST is the same as the hex-encoded digest of the
1106 DIGEST_LENGTH/8 bytes at BIN_BUFFER. */
1107 static bool
1108 hex_equal (unsigned char const *hex_digest, unsigned char const *bin_buffer)
1110 static const char bin2hex[] = { '0', '1', '2', '3',
1111 '4', '5', '6', '7',
1112 '8', '9', 'a', 'b',
1113 'c', 'd', 'e', 'f' };
1114 size_t digest_bin_bytes = digest_hex_bytes / 2;
1116 /* Compare generated binary number with text representation
1117 in check file. Ignore case of hex digits. */
1118 size_t cnt;
1119 for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
1121 if (tolower (hex_digest[2 * cnt])
1122 != bin2hex[bin_buffer[cnt] >> 4]
1123 || (tolower (hex_digest[2 * cnt + 1])
1124 != (bin2hex[bin_buffer[cnt] & 0xf])))
1125 break;
1127 return cnt == digest_bin_bytes;
1130 static bool
1131 digest_check (char const *checkfile_name)
1133 FILE *checkfile_stream;
1134 uintmax_t n_misformatted_lines = 0;
1135 uintmax_t n_mismatched_checksums = 0;
1136 uintmax_t n_open_or_read_failures = 0;
1137 bool properly_formatted_lines = false;
1138 bool matched_checksums = false;
1139 unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
1140 /* Make sure bin_buffer is properly aligned. */
1141 unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
1142 uintmax_t line_number;
1143 char *line;
1144 size_t line_chars_allocated;
1145 bool is_stdin = STREQ (checkfile_name, "-");
1147 if (is_stdin)
1149 have_read_stdin = true;
1150 checkfile_name = _("standard input");
1151 checkfile_stream = stdin;
1153 else
1155 checkfile_stream = fopen (checkfile_name, "r");
1156 if (checkfile_stream == nullptr)
1158 error (0, errno, "%s", quotef (checkfile_name));
1159 return false;
1163 line_number = 0;
1164 line = nullptr;
1165 line_chars_allocated = 0;
1168 char *filename;
1169 int binary;
1170 unsigned char *digest;
1171 ssize_t line_length;
1173 ++line_number;
1174 if (line_number == 0)
1175 error (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
1176 quotef (checkfile_name));
1178 line_length = getline (&line, &line_chars_allocated, checkfile_stream);
1179 if (line_length <= 0)
1180 break;
1182 /* Ignore comment lines, which begin with a '#' character. */
1183 if (line[0] == '#')
1184 continue;
1186 /* Remove any trailing newline. */
1187 line_length -= line[line_length - 1] == '\n';
1188 /* Remove any trailing carriage return. */
1189 line_length -= line[line_length - (0 < line_length)] == '\r';
1191 /* Ignore empty lines. */
1192 if (line_length == 0)
1193 continue;
1195 line[line_length] = '\0';
1197 size_t d_len;
1198 if (! (split_3 (line, line_length, &digest, &d_len, &binary, &filename)
1199 && ! (is_stdin && STREQ (filename, "-"))))
1201 ++n_misformatted_lines;
1203 if (warn)
1205 error (0, 0,
1206 _("%s: %" PRIuMAX
1207 ": improperly formatted %s checksum line"),
1208 quotef (checkfile_name), line_number,
1209 DIGEST_TYPE_STRING);
1212 else
1214 bool ok;
1215 bool missing;
1216 /* Only escape in the edge case producing multiple lines,
1217 to ease automatic processing of status output. */
1218 bool needs_escape = ! status_only && strchr (filename, '\n');
1220 properly_formatted_lines = true;
1222 uintmax_t length;
1223 ok = digest_file (filename, &binary, bin_buffer, &missing, &length);
1225 if (!ok)
1227 ++n_open_or_read_failures;
1228 if (!status_only)
1230 if (needs_escape)
1231 putchar ('\\');
1232 print_filename (filename, needs_escape);
1233 printf (": %s\n", _("FAILED open or read"));
1236 else if (ignore_missing && missing)
1238 /* Ignore missing files with --ignore-missing. */
1241 else
1243 bool match = false;
1244 #if HASH_ALGO_CKSUM
1245 if (d_len < digest_hex_bytes)
1246 match = b64_equal (digest, bin_buffer);
1247 else
1248 #endif
1249 if (d_len == digest_hex_bytes)
1250 match = hex_equal (digest, bin_buffer);
1252 if (match)
1253 matched_checksums = true;
1254 else
1255 ++n_mismatched_checksums;
1257 if (!status_only)
1259 if (! match || ! quiet)
1261 if (needs_escape)
1262 putchar ('\\');
1263 print_filename (filename, needs_escape);
1266 if (! match)
1267 printf (": %s\n", _("FAILED"));
1268 else if (!quiet)
1269 printf (": %s\n", _("OK"));
1274 while (!feof (checkfile_stream) && !ferror (checkfile_stream));
1276 free (line);
1278 int err = ferror (checkfile_stream) ? 0 : -1;
1279 if (is_stdin)
1280 clearerr (checkfile_stream);
1281 else if (fclose (checkfile_stream) != 0 && err < 0)
1282 err = errno;
1284 if (0 <= err)
1286 error (0, err, err ? "%s" : _("%s: read error"),
1287 quotef (checkfile_name));
1288 return false;
1291 if (! properly_formatted_lines)
1293 /* Warn if no tests are found. */
1294 error (0, 0, _("%s: no properly formatted checksum lines found"),
1295 quotef (checkfile_name));
1297 else
1299 if (!status_only)
1301 if (n_misformatted_lines != 0)
1302 error (0, 0,
1303 (ngettext
1304 ("WARNING: %" PRIuMAX " line is improperly formatted",
1305 "WARNING: %" PRIuMAX " lines are improperly formatted",
1306 select_plural (n_misformatted_lines))),
1307 n_misformatted_lines);
1309 if (n_open_or_read_failures != 0)
1310 error (0, 0,
1311 (ngettext
1312 ("WARNING: %" PRIuMAX " listed file could not be read",
1313 "WARNING: %" PRIuMAX " listed files could not be read",
1314 select_plural (n_open_or_read_failures))),
1315 n_open_or_read_failures);
1317 if (n_mismatched_checksums != 0)
1318 error (0, 0,
1319 (ngettext
1320 ("WARNING: %" PRIuMAX " computed checksum did NOT match",
1321 "WARNING: %" PRIuMAX " computed checksums did NOT match",
1322 select_plural (n_mismatched_checksums))),
1323 n_mismatched_checksums);
1325 if (ignore_missing && ! matched_checksums)
1326 error (0, 0, _("%s: no file was verified"),
1327 quotef (checkfile_name));
1331 return (properly_formatted_lines
1332 && matched_checksums
1333 && n_mismatched_checksums == 0
1334 && n_open_or_read_failures == 0
1335 && (!strict || n_misformatted_lines == 0));
1339 main (int argc, char **argv)
1341 unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
1342 /* Make sure bin_buffer is properly aligned. */
1343 unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
1344 bool do_check = false;
1345 int opt;
1346 bool ok = true;
1347 #if HASH_ALGO_CKSUM
1348 int binary = 1;
1349 bool prefix_tag = true;
1350 #else
1351 int binary = -1;
1352 bool prefix_tag = false;
1353 #endif
1355 /* Setting values of global variables. */
1356 initialize_main (&argc, &argv);
1357 set_program_name (argv[0]);
1358 setlocale (LC_ALL, "");
1359 bindtextdomain (PACKAGE, LOCALEDIR);
1360 textdomain (PACKAGE);
1362 atexit (close_stdout);
1364 /* Line buffer stdout to ensure lines are written atomically and immediately
1365 so that processes running in parallel do not intersperse their output. */
1366 setvbuf (stdout, nullptr, _IOLBF, 0);
1368 #if HASH_ALGO_SUM
1369 char const *short_opts = "rs";
1370 #elif HASH_ALGO_CKSUM
1371 char const *short_opts = "a:l:bctwz";
1372 char const *digest_length_str = "";
1373 #elif HASH_ALGO_BLAKE2
1374 char const *short_opts = "l:bctwz";
1375 char const *digest_length_str = "";
1376 #else
1377 char const *short_opts = "bctwz";
1378 #endif
1380 while ((opt = getopt_long (argc, argv, short_opts, long_options, nullptr))
1381 != -1)
1382 switch (opt)
1384 #if HASH_ALGO_CKSUM
1385 case 'a':
1386 cksum_algorithm = XARGMATCH_EXACT ("--algorithm", optarg,
1387 algorithm_args, algorithm_types);
1388 algorithm_specified = true;
1389 break;
1391 case DEBUG_PROGRAM_OPTION:
1392 cksum_debug = true;
1393 break;
1394 #endif
1395 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
1396 case 'l':
1397 digest_length = xdectoumax (optarg, 0, UINTMAX_MAX, "",
1398 _("invalid length"), 0);
1399 digest_length_str = optarg;
1400 if (digest_length % 8 != 0)
1402 error (0, 0, _("invalid length: %s"), quote (digest_length_str));
1403 error (EXIT_FAILURE, 0, _("length is not a multiple of 8"));
1405 break;
1406 #endif
1407 #if !HASH_ALGO_SUM
1408 case 'c':
1409 do_check = true;
1410 break;
1411 case STATUS_OPTION:
1412 status_only = true;
1413 warn = false;
1414 quiet = false;
1415 break;
1416 # if !HASH_ALGO_CKSUM
1417 case 'b':
1418 binary = 1;
1419 break;
1420 case 't':
1421 binary = 0;
1422 break;
1423 # endif
1424 case 'w':
1425 status_only = false;
1426 warn = true;
1427 quiet = false;
1428 break;
1429 case IGNORE_MISSING_OPTION:
1430 ignore_missing = true;
1431 break;
1432 case QUIET_OPTION:
1433 status_only = false;
1434 warn = false;
1435 quiet = true;
1436 break;
1437 case STRICT_OPTION:
1438 strict = true;
1439 break;
1440 # if HASH_ALGO_CKSUM
1441 case 'b':
1442 base64_digest = true;
1443 break;
1444 case RAW_OPTION:
1445 raw_digest = true;
1446 break;
1447 case UNTAG_OPTION:
1448 prefix_tag = false;
1449 break;
1450 # endif
1451 case TAG_OPTION:
1452 prefix_tag = true;
1453 binary = 1;
1454 break;
1455 case 'z':
1456 digest_delim = '\0';
1457 break;
1458 #endif
1459 #if HASH_ALGO_SUM
1460 case 'r': /* For SysV compatibility. */
1461 sum_algorithm = bsd;
1462 break;
1464 case 's':
1465 sum_algorithm = sysv;
1466 break;
1467 #endif
1468 case_GETOPT_HELP_CHAR;
1469 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1470 default:
1471 usage (EXIT_FAILURE);
1474 min_digest_line_length = MIN_DIGEST_LINE_LENGTH;
1475 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
1476 # if HASH_ALGO_CKSUM
1477 if (digest_length && cksum_algorithm != blake2b)
1478 error (EXIT_FAILURE, 0,
1479 _("--length is only supported with --algorithm=blake2b"));
1480 # endif
1481 if (digest_length > BLAKE2B_MAX_LEN * 8)
1483 error (0, 0, _("invalid length: %s"), quote (digest_length_str));
1484 error (EXIT_FAILURE, 0,
1485 _("maximum digest length for %s is %d bits"),
1486 quote (DIGEST_TYPE_STRING),
1487 BLAKE2B_MAX_LEN * 8);
1489 if (digest_length == 0)
1491 # if HASH_ALGO_BLAKE2
1492 digest_length = BLAKE2B_MAX_LEN * 8;
1493 # else
1494 digest_length = algorithm_bits[cksum_algorithm];
1495 # endif
1497 digest_hex_bytes = digest_length / 4;
1498 #else
1499 digest_hex_bytes = DIGEST_HEX_BYTES;
1500 #endif
1502 #if HASH_ALGO_CKSUM
1503 switch (cksum_algorithm)
1505 case bsd:
1506 case sysv:
1507 case crc:
1508 if (do_check && algorithm_specified)
1509 error (EXIT_FAILURE, 0,
1510 _("--check is not supported with --algorithm={bsd,sysv,crc}"));
1511 break;
1512 default:
1513 break;
1516 if (base64_digest && raw_digest)
1518 error (0, 0, _("--base64 and --raw are mutually exclusive"));
1519 usage (EXIT_FAILURE);
1521 #endif
1523 if (prefix_tag && !binary)
1525 /* This could be supported in a backwards compatible way
1526 by prefixing the output line with a space in text mode.
1527 However that's invasive enough that it was agreed to
1528 not support this mode with --tag, as --text use cases
1529 are adequately supported by the default output format. */
1530 error (0, 0, _("--tag does not support --text mode"));
1531 usage (EXIT_FAILURE);
1534 if (digest_delim != '\n' && do_check)
1536 error (0, 0, _("the --zero option is not supported when "
1537 "verifying checksums"));
1538 usage (EXIT_FAILURE);
1540 #if !HASH_ALGO_CKSUM
1541 if (prefix_tag && do_check)
1543 error (0, 0, _("the --tag option is meaningless when "
1544 "verifying checksums"));
1545 usage (EXIT_FAILURE);
1547 #endif
1549 #if !HASH_ALGO_CKSUM
1550 if (0 <= binary && do_check)
1552 error (0, 0, _("the --binary and --text options are meaningless when "
1553 "verifying checksums"));
1554 usage (EXIT_FAILURE);
1556 #endif
1558 if (ignore_missing && !do_check)
1560 error (0, 0,
1561 _("the --ignore-missing option is meaningful only when "
1562 "verifying checksums"));
1563 usage (EXIT_FAILURE);
1566 if (status_only && !do_check)
1568 error (0, 0,
1569 _("the --status option is meaningful only when verifying checksums"));
1570 usage (EXIT_FAILURE);
1573 if (warn && !do_check)
1575 error (0, 0,
1576 _("the --warn option is meaningful only when verifying checksums"));
1577 usage (EXIT_FAILURE);
1580 if (quiet && !do_check)
1582 error (0, 0,
1583 _("the --quiet option is meaningful only when verifying checksums"));
1584 usage (EXIT_FAILURE);
1587 if (strict & !do_check)
1589 error (0, 0,
1590 _("the --strict option is meaningful only when verifying checksums"));
1591 usage (EXIT_FAILURE);
1594 if (!O_BINARY && binary < 0)
1595 binary = 0;
1597 char **operand_lim = argv + argc;
1598 if (optind == argc)
1599 *operand_lim++ = bad_cast ("-");
1600 else if (1 < argc - optind && raw_digest)
1601 error (EXIT_FAILURE, 0,
1602 _("the --raw option is not supported with multiple files"));
1604 for (char **operandp = argv + optind; operandp < operand_lim; operandp++)
1606 char *file = *operandp;
1607 if (do_check)
1608 ok &= digest_check (file);
1609 else
1611 int binary_file = binary;
1612 bool missing;
1613 uintmax_t length;
1615 if (! digest_file (file, &binary_file, bin_buffer, &missing, &length))
1616 ok = false;
1617 else
1619 DIGEST_OUT (file, binary_file, bin_buffer, raw_digest, prefix_tag,
1620 digest_delim, optind != argc, length);
1625 if (have_read_stdin && fclose (stdin) == EOF)
1626 error (EXIT_FAILURE, errno, _("standard input"));
1628 return ok ? EXIT_SUCCESS : EXIT_FAILURE;