maint: avoid a syntax-check failure
[coreutils.git] / src / digest.c
blob399a97a565a0563031cf7d0e741e43e7a71609db
1 /* Compute checksums of files or strings.
2 Copyright (C) 1995-2024 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 "c-ctype.h"
27 #include "quote.h"
28 #include "xdectoint.h"
29 #include "xstrtol.h"
31 #ifndef HASH_ALGO_CKSUM
32 # define HASH_ALGO_CKSUM 0
33 #endif
35 #if HASH_ALGO_SUM || HASH_ALGO_CKSUM
36 # include "sum.h"
37 #endif
38 #if HASH_ALGO_CKSUM
39 # include "cksum.h"
40 # include "base64.h"
41 #endif
42 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
43 # include "blake2/b2sum.h"
44 #endif
45 #if HASH_ALGO_MD5 || HASH_ALGO_CKSUM
46 # include "md5.h"
47 #endif
48 #if HASH_ALGO_SHA1 || HASH_ALGO_CKSUM
49 # include "sha1.h"
50 #endif
51 #if HASH_ALGO_SHA256 || HASH_ALGO_SHA224 || HASH_ALGO_CKSUM
52 # include "sha256.h"
53 #endif
54 #if HASH_ALGO_SHA512 || HASH_ALGO_SHA384 || HASH_ALGO_CKSUM
55 # include "sha512.h"
56 #endif
57 #if HASH_ALGO_CKSUM
58 # include "sm3.h"
59 #endif
60 #include "fadvise.h"
61 #include "stdio--.h"
62 #include "xbinary-io.h"
64 /* The official name of this program (e.g., no 'g' prefix). */
65 #if HASH_ALGO_SUM
66 # define PROGRAM_NAME "sum"
67 # define DIGEST_TYPE_STRING "BSD"
68 # define DIGEST_STREAM sumfns[sum_algorithm]
69 # define DIGEST_OUT sum_output_fns[sum_algorithm]
70 # define DIGEST_BITS 16
71 # define DIGEST_ALIGN 4
72 #elif HASH_ALGO_CKSUM
73 # define MAX_DIGEST_BITS 512
74 # define MAX_DIGEST_ALIGN 8
75 # define PROGRAM_NAME "cksum"
76 # define DIGEST_TYPE_STRING algorithm_tags[cksum_algorithm]
77 # define DIGEST_STREAM cksumfns[cksum_algorithm]
78 # define DIGEST_OUT cksum_output_fns[cksum_algorithm]
79 # define DIGEST_BITS MAX_DIGEST_BITS
80 # define DIGEST_ALIGN MAX_DIGEST_ALIGN
81 #elif HASH_ALGO_MD5
82 # define PROGRAM_NAME "md5sum"
83 # define DIGEST_TYPE_STRING "MD5"
84 # define DIGEST_STREAM md5_stream
85 # define DIGEST_BITS 128
86 # define DIGEST_REFERENCE "RFC 1321"
87 # define DIGEST_ALIGN 4
88 #elif HASH_ALGO_BLAKE2
89 # define PROGRAM_NAME "b2sum"
90 # define DIGEST_TYPE_STRING "BLAKE2b"
91 # define DIGEST_STREAM blake2b_stream
92 # define DIGEST_BITS 512
93 # define DIGEST_REFERENCE "RFC 7693"
94 # define DIGEST_ALIGN 8
95 #elif HASH_ALGO_SHA1
96 # define PROGRAM_NAME "sha1sum"
97 # define DIGEST_TYPE_STRING "SHA1"
98 # define DIGEST_STREAM sha1_stream
99 # define DIGEST_BITS 160
100 # define DIGEST_REFERENCE "FIPS-180-1"
101 # define DIGEST_ALIGN 4
102 #elif HASH_ALGO_SHA256
103 # define PROGRAM_NAME "sha256sum"
104 # define DIGEST_TYPE_STRING "SHA256"
105 # define DIGEST_STREAM sha256_stream
106 # define DIGEST_BITS 256
107 # define DIGEST_REFERENCE "FIPS-180-2"
108 # define DIGEST_ALIGN 4
109 #elif HASH_ALGO_SHA224
110 # define PROGRAM_NAME "sha224sum"
111 # define DIGEST_TYPE_STRING "SHA224"
112 # define DIGEST_STREAM sha224_stream
113 # define DIGEST_BITS 224
114 # define DIGEST_REFERENCE "RFC 3874"
115 # define DIGEST_ALIGN 4
116 #elif HASH_ALGO_SHA512
117 # define PROGRAM_NAME "sha512sum"
118 # define DIGEST_TYPE_STRING "SHA512"
119 # define DIGEST_STREAM sha512_stream
120 # define DIGEST_BITS 512
121 # define DIGEST_REFERENCE "FIPS-180-2"
122 # define DIGEST_ALIGN 8
123 #elif HASH_ALGO_SHA384
124 # define PROGRAM_NAME "sha384sum"
125 # define DIGEST_TYPE_STRING "SHA384"
126 # define DIGEST_STREAM sha384_stream
127 # define DIGEST_BITS 384
128 # define DIGEST_REFERENCE "FIPS-180-2"
129 # define DIGEST_ALIGN 8
130 #else
131 # error "Can't decide which hash algorithm to compile."
132 #endif
133 #if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM
134 # define DIGEST_OUT output_file
135 #endif
137 #if HASH_ALGO_SUM
138 # define AUTHORS \
139 proper_name ("Kayvan Aghaiepour"), \
140 proper_name ("David MacKenzie")
141 #elif HASH_ALGO_CKSUM
142 # define AUTHORS \
143 proper_name_lite ("Padraig Brady", "P\303\241draig Brady"), \
144 proper_name ("Q. Frank Xia")
145 #elif HASH_ALGO_BLAKE2
146 # define AUTHORS \
147 proper_name_lite ("Padraig Brady", "P\303\241draig Brady"), \
148 proper_name ("Samuel Neves")
149 #else
150 # define AUTHORS \
151 proper_name ("Ulrich Drepper"), \
152 proper_name ("Scott Miller"), \
153 proper_name ("David Madore")
154 #endif
155 #if !HASH_ALGO_BLAKE2 && !HASH_ALGO_CKSUM
156 # define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
157 #endif
158 #define DIGEST_BIN_BYTES (DIGEST_BITS / 8)
160 /* The minimum length of a valid digest line. This length does
161 not include any newline character at the end of a line. */
162 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
163 # define MIN_DIGEST_LINE_LENGTH 3 /* With -l 8. */
164 #else
165 # define MIN_DIGEST_LINE_LENGTH \
166 (DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
167 + 1 /* blank */ \
168 + 1 /* minimum filename length */ )
169 #endif
171 #if !HASH_ALGO_SUM
172 static void
173 output_file (char const *file, int binary_file, void const *digest,
174 bool raw, bool tagged, unsigned char delim, bool args,
175 uintmax_t length);
176 #endif
178 /* True if any of the files read were the standard input. */
179 static bool have_read_stdin;
181 /* The minimum length of a valid checksum line for the selected algorithm. */
182 static size_t min_digest_line_length;
184 /* Set to the length of a digest hex string for the selected algorithm. */
185 static size_t digest_hex_bytes;
187 /* With --check, don't generate any output.
188 The exit code indicates success or failure. */
189 static bool status_only = false;
191 /* With --check, print a message to standard error warning about each
192 improperly formatted checksum line. */
193 static bool warn = false;
195 /* With --check, ignore missing files. */
196 static bool ignore_missing = false;
198 /* With --check, suppress the "OK" printed for each verified file. */
199 static bool quiet = false;
201 /* With --check, exit with a non-zero return code if any line is
202 improperly formatted. */
203 static bool strict = false;
205 /* Whether a BSD reversed format checksum is detected. */
206 static int bsd_reversed = -1;
208 /* line delimiter. */
209 static unsigned char digest_delim = '\n';
211 #if HASH_ALGO_CKSUM
212 /* If true, print base64-encoded digests, not hex. */
213 static bool base64_digest = false;
214 #endif
216 /* If true, print binary digests, not hex. */
217 static bool raw_digest = false;
219 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
220 # define BLAKE2B_MAX_LEN BLAKE2B_OUTBYTES
221 static uintmax_t digest_length;
222 #endif /* HASH_ALGO_BLAKE2 */
224 typedef void (*digest_output_fn)(char const *, int, void const *, bool,
225 bool, unsigned char, bool, uintmax_t);
226 #if HASH_ALGO_SUM
227 enum Algorithm
229 bsd,
230 sysv,
233 static enum Algorithm sum_algorithm;
234 static sumfn sumfns[]=
236 bsd_sum_stream,
237 sysv_sum_stream,
239 static digest_output_fn sum_output_fns[]=
241 output_bsd,
242 output_sysv,
244 #endif
246 #if HASH_ALGO_CKSUM
247 static int
248 md5_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
250 return md5_stream (stream, resstream);
252 static int
253 sha1_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
255 return sha1_stream (stream, resstream);
257 static int
258 sha224_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
260 return sha224_stream (stream, resstream);
262 static int
263 sha256_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
265 return sha256_stream (stream, resstream);
267 static int
268 sha384_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
270 return sha384_stream (stream, resstream);
272 static int
273 sha512_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
275 return sha512_stream (stream, resstream);
277 static int
278 blake2b_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
280 return blake2b_stream (stream, resstream, *length);
282 static int
283 sm3_sum_stream (FILE *stream, void *resstream, uintmax_t *length)
285 return sm3_stream (stream, resstream);
288 enum Algorithm
290 bsd,
291 sysv,
292 crc,
293 crc32b,
294 md5,
295 sha1,
296 sha224,
297 sha256,
298 sha384,
299 sha512,
300 blake2b,
301 sm3,
304 static char const *const algorithm_args[] =
306 "bsd", "sysv", "crc", "crc32b", "md5", "sha1", "sha224",
307 "sha256", "sha384", "sha512", "blake2b", "sm3", nullptr
309 static enum Algorithm const algorithm_types[] =
311 bsd, sysv, crc, crc32b, md5, sha1, sha224,
312 sha256, sha384, sha512, blake2b, sm3,
314 ARGMATCH_VERIFY (algorithm_args, algorithm_types);
316 static char const *const algorithm_tags[] =
318 "BSD", "SYSV", "CRC", "CRC32B", "MD5", "SHA1", "SHA224",
319 "SHA256", "SHA384", "SHA512", "BLAKE2b", "SM3", nullptr
321 static int const algorithm_bits[] =
323 16, 16, 32, 32, 128, 160, 224,
324 256, 384, 512, 512, 256, 0
327 static_assert (ARRAY_CARDINALITY (algorithm_bits)
328 == ARRAY_CARDINALITY (algorithm_args));
330 static bool algorithm_specified = false;
331 static enum Algorithm cksum_algorithm = crc;
332 static sumfn cksumfns[]=
334 bsd_sum_stream,
335 sysv_sum_stream,
336 crc_sum_stream,
337 crc32b_sum_stream,
338 md5_sum_stream,
339 sha1_sum_stream,
340 sha224_sum_stream,
341 sha256_sum_stream,
342 sha384_sum_stream,
343 sha512_sum_stream,
344 blake2b_sum_stream,
345 sm3_sum_stream,
347 static digest_output_fn cksum_output_fns[]=
349 output_bsd,
350 output_sysv,
351 output_crc,
352 output_crc,
353 output_file,
354 output_file,
355 output_file,
356 output_file,
357 output_file,
358 output_file,
359 output_file,
360 output_file,
362 bool cksum_debug;
363 #endif
365 /* For long options that have no equivalent short option, use a
366 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
368 enum
370 IGNORE_MISSING_OPTION = CHAR_MAX + 1,
371 STATUS_OPTION,
372 QUIET_OPTION,
373 STRICT_OPTION,
374 TAG_OPTION,
375 UNTAG_OPTION,
376 DEBUG_PROGRAM_OPTION,
377 RAW_OPTION,
378 BASE64_OPTION,
381 static struct option const long_options[] =
383 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
384 { "length", required_argument, nullptr, 'l'},
385 #endif
387 #if !HASH_ALGO_SUM
388 { "check", no_argument, nullptr, 'c' },
389 { "ignore-missing", no_argument, nullptr, IGNORE_MISSING_OPTION},
390 { "quiet", no_argument, nullptr, QUIET_OPTION },
391 { "status", no_argument, nullptr, STATUS_OPTION },
392 { "warn", no_argument, nullptr, 'w' },
393 { "strict", no_argument, nullptr, STRICT_OPTION },
394 { "tag", no_argument, nullptr, TAG_OPTION },
395 { "zero", no_argument, nullptr, 'z' },
397 # if HASH_ALGO_CKSUM
398 { "algorithm", required_argument, nullptr, 'a'},
399 { "base64", no_argument, nullptr, BASE64_OPTION },
400 { "debug", no_argument, nullptr, DEBUG_PROGRAM_OPTION},
401 { "raw", no_argument, nullptr, RAW_OPTION},
402 { "untagged", no_argument, nullptr, UNTAG_OPTION },
403 # endif
404 { "binary", no_argument, nullptr, 'b' },
405 { "text", no_argument, nullptr, 't' },
407 #else
408 {"sysv", no_argument, nullptr, 's'},
409 #endif
411 { GETOPT_HELP_OPTION_DECL },
412 { GETOPT_VERSION_OPTION_DECL },
413 { nullptr, 0, nullptr, 0 }
416 void
417 usage (int status)
419 if (status != EXIT_SUCCESS)
420 emit_try_help ();
421 else
423 printf (_("\
424 Usage: %s [OPTION]... [FILE]...\n\
425 "), program_name);
426 #if HASH_ALGO_CKSUM
427 fputs (_("\
428 Print or verify checksums.\n\
429 By default use the 32 bit CRC algorithm.\n\
430 "), stdout);
431 #else
432 printf (_("\
433 Print or check %s (%d-bit) checksums.\n\
435 DIGEST_TYPE_STRING,
436 DIGEST_BITS);
437 #endif
439 emit_stdin_note ();
440 #if HASH_ALGO_SUM
441 fputs (_("\
443 -r use BSD sum algorithm (the default), use 1K blocks\n\
444 -s, --sysv use System V sum algorithm, use 512 bytes blocks\n\
445 "), stdout);
446 #endif
447 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
448 emit_mandatory_arg_note ();
449 #endif
450 #if HASH_ALGO_CKSUM
451 fputs (_("\
452 -a, --algorithm=TYPE select the digest type to use. See DIGEST below\
454 "), stdout);
455 fputs (_("\
456 --base64 emit base64-encoded digests, not hexadecimal\
458 "), stdout);
459 #endif
460 #if !HASH_ALGO_SUM
461 # if !HASH_ALGO_CKSUM
462 if (O_BINARY)
463 fputs (_("\
464 -b, --binary read in binary mode (default unless reading tty stdin)\
466 "), stdout);
467 else
468 fputs (_("\
469 -b, --binary read in binary mode\n\
470 "), stdout);
471 # endif
472 fputs (_("\
473 -c, --check read checksums from the FILEs and check them\n\
474 "), stdout);
475 # if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
476 fputs (_("\
477 -l, --length=BITS digest length in bits; must not exceed the max for\n\
478 the blake2 algorithm and must be a multiple of 8\n\
479 "), stdout);
480 # endif
481 # if HASH_ALGO_CKSUM
482 fputs (_("\
483 --raw emit a raw binary digest, not hexadecimal\
485 "), stdout);
486 fputs (_("\
487 --tag create a BSD-style checksum (the default)\n\
488 "), stdout);
489 fputs (_("\
490 --untagged create a reversed style checksum, without digest type\n\
491 "), stdout);
492 # else
493 fputs (_("\
494 --tag create a BSD-style checksum\n\
495 "), stdout);
496 # endif
497 # if !HASH_ALGO_CKSUM
498 if (O_BINARY)
499 fputs (_("\
500 -t, --text read in text mode (default if reading tty stdin)\n\
501 "), stdout);
502 else
503 fputs (_("\
504 -t, --text read in text mode (default)\n\
505 "), stdout);
506 # endif
507 fputs (_("\
508 -z, --zero end each output line with NUL, not newline,\n\
509 and disable file name escaping\n\
510 "), stdout);
511 fputs (_("\
513 The following five options are useful only when verifying checksums:\n\
514 --ignore-missing don't fail or report status for missing files\n\
515 --quiet don't print OK for each successfully verified file\n\
516 --status don't output anything, status code shows success\n\
517 --strict exit non-zero for improperly formatted checksum lines\n\
518 -w, --warn warn about improperly formatted checksum lines\n\
520 "), stdout);
521 #endif
522 #if HASH_ALGO_CKSUM
523 fputs (_("\
524 --debug indicate which implementation used\n\
525 "), stdout);
526 #endif
527 fputs (HELP_OPTION_DESCRIPTION, stdout);
528 fputs (VERSION_OPTION_DESCRIPTION, stdout);
529 #if HASH_ALGO_CKSUM
530 fputs (_("\
532 DIGEST determines the digest algorithm and default output format:\n\
533 sysv (equivalent to sum -s)\n\
534 bsd (equivalent to sum -r)\n\
535 crc (equivalent to cksum)\n\
536 crc32b (only available through cksum)\n\
537 md5 (equivalent to md5sum)\n\
538 sha1 (equivalent to sha1sum)\n\
539 sha224 (equivalent to sha224sum)\n\
540 sha256 (equivalent to sha256sum)\n\
541 sha384 (equivalent to sha384sum)\n\
542 sha512 (equivalent to sha512sum)\n\
543 blake2b (equivalent to b2sum)\n\
544 sm3 (only available through cksum)\n\
545 \n"), stdout);
546 #endif
547 #if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM
548 printf (_("\
550 The sums are computed as described in %s.\n"), DIGEST_REFERENCE);
551 fputs (_("\
552 When checking, the input should be a former output of this program.\n\
553 The default mode is to print a line with: checksum, a space,\n\
554 a character indicating input mode ('*' for binary, ' ' for text\n\
555 or where binary is insignificant), and name for each FILE.\n\
557 There is no difference between binary mode and text mode on GNU systems.\
558 \n"), stdout);
559 #endif
560 #if HASH_ALGO_CKSUM
561 fputs (_("\
562 When checking, the input should be a former output of this program,\n\
563 or equivalent standalone program.\
564 \n"), stdout);
565 #endif
566 emit_ancillary_info (PROGRAM_NAME);
569 exit (status);
572 /* Given a string S, return TRUE if it contains problematic characters
573 that need escaping. Note we escape '\' itself to provide some forward
574 compat to introduce escaping of other characters. */
576 ATTRIBUTE_PURE
577 static bool
578 problematic_chars (char const *s)
580 size_t length = strcspn (s, "\\\n\r");
581 return s[length] != '\0';
584 #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
586 /* Given a file name, S of length S_LEN, that is not NUL-terminated,
587 modify it in place, performing the equivalent of this sed substitution:
588 's/\\n/\n/g;s/\\r/\r/g;s/\\\\/\\/g' i.e., replacing each "\\n" string
589 with a newline, each "\\r" string with a carriage return,
590 and each "\\\\" with a single backslash, NUL-terminate it and return S.
591 If S is not a valid escaped file name, i.e., if it ends with an odd number
592 of backslashes or if it contains a backslash followed by anything other
593 than "n" or another backslash, return nullptr. */
595 static char *
596 filename_unescape (char *s, size_t s_len)
598 char *dst = s;
600 for (size_t i = 0; i < s_len; i++)
602 switch (s[i])
604 case '\\':
605 if (i == s_len - 1)
607 /* File name ends with an unescaped backslash: invalid. */
608 return nullptr;
610 ++i;
611 switch (s[i])
613 case 'n':
614 *dst++ = '\n';
615 break;
616 case 'r':
617 *dst++ = '\r';
618 break;
619 case '\\':
620 *dst++ = '\\';
621 break;
622 default:
623 /* Only '\', 'n' or 'r' may follow a backslash. */
624 return nullptr;
626 break;
628 case '\0':
629 /* The file name may not contain a NUL. */
630 return nullptr;
632 default:
633 *dst++ = s[i];
634 break;
637 if (dst < s + s_len)
638 *dst = '\0';
640 return s;
643 /* Return true if S is a LEN-byte NUL-terminated string of hex or base64
644 digits and has the expected length. Otherwise, return false. */
645 ATTRIBUTE_PURE
646 static bool
647 valid_digits (unsigned char const *s, size_t len)
649 #if HASH_ALGO_CKSUM
650 if (len == BASE64_LENGTH (digest_length / 8))
652 size_t i;
653 for (i = 0; i < len - digest_length % 3; i++)
655 if (!isbase64 (*s))
656 return false;
657 ++s;
659 for ( ; i < len; i++)
661 if (*s != '=')
662 return false;
663 ++s;
666 else
667 #endif
668 if (len == digest_hex_bytes)
670 for (idx_t i = 0; i < digest_hex_bytes; i++)
672 if (!c_isxdigit (*s))
673 return false;
674 ++s;
677 else
678 return false;
680 return *s == '\0';
683 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
684 'sha1' command into two parts: a hexadecimal digest, and the file
685 name. S is modified. Set *D_LEN to the length of the digest string.
686 Return true if successful. */
688 static bool
689 bsd_split_3 (char *s, size_t s_len,
690 unsigned char **digest, size_t *d_len,
691 char **file_name, bool escaped_filename)
693 if (s_len == 0)
694 return false;
696 /* Find end of filename. */
697 size_t i = s_len - 1;
698 while (i && s[i] != ')')
699 i--;
701 if (s[i] != ')')
702 return false;
704 *file_name = s;
706 if (escaped_filename && filename_unescape (s, i) == nullptr)
707 return false;
709 s[i++] = '\0';
711 while (ISWHITE (s[i]))
712 i++;
714 if (s[i] != '=')
715 return false;
717 i++;
719 while (ISWHITE (s[i]))
720 i++;
722 *digest = (unsigned char *) &s[i];
724 *d_len = s_len - i;
725 return valid_digits (*digest, *d_len);
728 #if HASH_ALGO_CKSUM
729 /* Return the corresponding Algorithm for the string S,
730 or -1 for no match. */
732 static ptrdiff_t
733 algorithm_from_tag (char *s)
735 /* Limit check size to this length for perf reasons. */
736 static size_t max_tag_len;
737 if (! max_tag_len)
739 char const * const * tag = algorithm_tags;
740 while (*tag)
742 size_t tag_len = strlen (*tag++);
743 max_tag_len = MAX (tag_len, max_tag_len);
747 size_t i = 0;
749 /* Find end of tag */
750 while (i <= max_tag_len && s[i] && ! ISWHITE (s[i])
751 && s[i] != '-' && s[i] != '(')
752 ++i;
754 if (i > max_tag_len)
755 return -1;
757 /* Terminate tag, and lookup. */
758 char sep = s[i];
759 s[i] = '\0';
760 ptrdiff_t algo = argmatch_exact (s, algorithm_tags);
761 s[i] = sep;
763 return algo;
765 #endif
767 /* Split the string S (of length S_LEN) into three parts:
768 a hexadecimal digest, binary flag, and the file name.
769 S is modified. Set *D_LEN to the length of the digest string.
770 Return true if successful. */
772 static bool
773 split_3 (char *s, size_t s_len,
774 unsigned char **digest, size_t *d_len, int *binary, char **file_name)
776 bool escaped_filename = false;
777 size_t algo_name_len;
779 size_t i = 0;
780 while (ISWHITE (s[i]))
781 ++i;
783 if (s[i] == '\\')
785 ++i;
786 escaped_filename = true;
789 /* Check for BSD-style checksum line. */
791 #if HASH_ALGO_CKSUM
792 if (! algorithm_specified)
794 ptrdiff_t algo_tag = algorithm_from_tag (s + i);
795 if (algo_tag >= 0)
797 if (algo_tag <= crc32b)
798 return false; /* We don't support checking these older formats. */
799 cksum_algorithm = algo_tag;
801 else
802 return false; /* We only support tagged format without -a. */
804 #endif
806 algo_name_len = strlen (DIGEST_TYPE_STRING);
807 if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
809 i += algo_name_len;
810 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
811 /* Terminate and match algorithm name. */
812 char const *algo_name = &s[i - algo_name_len];
813 bool length_specified = s[i] == '-';
814 bool openssl_format = s[i] == '('; /* and no length_specified */
815 s[i++] = '\0';
816 if (!STREQ (algo_name, DIGEST_TYPE_STRING))
817 return false;
818 if (openssl_format)
819 s[--i] = '(';
821 # if HASH_ALGO_BLAKE2
822 digest_length = BLAKE2B_MAX_LEN * 8;
823 # else
824 digest_length = algorithm_bits[cksum_algorithm];
825 # endif
826 if (length_specified)
828 uintmax_t length;
829 char *siend;
830 if (! (xstrtoumax (s + i, &siend, 0, &length, nullptr) == LONGINT_OK
831 && 0 < length && length <= digest_length
832 && length % 8 == 0))
833 return false;
835 i = siend - s;
836 digest_length = length;
838 digest_hex_bytes = digest_length / 4;
839 #endif
840 if (s[i] == ' ')
841 ++i;
842 if (s[i] == '(')
844 ++i;
845 *binary = 0;
846 return bsd_split_3 (s + i, s_len - i,
847 digest, d_len, file_name, escaped_filename);
849 return false;
852 /* Ignore this line if it is too short.
853 Each line must have at least 'min_digest_line_length - 1' (or one more, if
854 the first is a backslash) more characters to contain correct message digest
855 information. */
856 if (s_len - i < min_digest_line_length + (s[i] == '\\'))
857 return false;
859 *digest = (unsigned char *) &s[i];
861 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
862 /* Auto determine length. */
863 # if HASH_ALGO_CKSUM
864 if (cksum_algorithm == blake2b) {
865 # endif
866 unsigned char const *hp = *digest;
867 digest_hex_bytes = 0;
868 while (c_isxdigit (*hp++))
869 digest_hex_bytes++;
870 if (digest_hex_bytes < 2 || digest_hex_bytes % 2
871 || BLAKE2B_MAX_LEN * 2 < digest_hex_bytes)
872 return false;
873 digest_length = digest_hex_bytes * 4;
874 # if HASH_ALGO_CKSUM
876 # endif
877 #endif
879 /* This field must be the hexadecimal or base64 representation
880 of the message digest. */
881 while (s[i] && !ISWHITE (s[i]))
882 i++;
884 /* The digest must be followed by at least one whitespace character. */
885 if (i == s_len)
886 return false;
888 *d_len = &s[i] - (char *) *digest;
889 s[i++] = '\0';
891 if (! valid_digits (*digest, *d_len))
892 return false;
894 /* If "bsd reversed" format detected. */
895 if ((s_len - i == 1) || (s[i] != ' ' && s[i] != '*'))
897 /* Don't allow mixing bsd and standard formats,
898 to minimize security issues with attackers
899 renaming files with leading spaces.
900 This assumes that with bsd format checksums
901 that the first file name does not have
902 a leading ' ' or '*'. */
903 if (bsd_reversed == 0)
904 return false;
905 bsd_reversed = 1;
907 else if (bsd_reversed != 1)
909 bsd_reversed = 0;
910 *binary = (s[i++] == '*');
913 /* All characters between the type indicator and end of line are
914 significant -- that includes leading and trailing white space. */
915 *file_name = &s[i];
917 if (escaped_filename)
918 return filename_unescape (&s[i], s_len - i) != nullptr;
920 return true;
923 /* If ESCAPE is true, then translate each:
924 NEWLINE byte to the string, "\\n",
925 CARRIAGE RETURN byte to the string, "\\r",
926 and each backslash to "\\\\". */
927 static void
928 print_filename (char const *file, bool escape)
930 if (! escape)
932 fputs (file, stdout);
933 return;
936 while (*file)
938 switch (*file)
940 case '\n':
941 fputs ("\\n", stdout);
942 break;
944 case '\r':
945 fputs ("\\r", stdout);
946 break;
948 case '\\':
949 fputs ("\\\\", stdout);
950 break;
952 default:
953 putchar (*file);
954 break;
956 file++;
960 /* An interface to the function, DIGEST_STREAM.
961 Operate on FILENAME (it may be "-").
963 *BINARY indicates whether the file is binary. BINARY < 0 means it
964 depends on whether binary mode makes any difference and the file is
965 a terminal; in that case, clear *BINARY if the file was treated as
966 text because it was a terminal.
968 Put the checksum in *BIN_RESULT, which must be properly aligned.
969 Put true in *MISSING if the file can't be opened due to ENOENT.
970 Return true if successful. */
972 static bool
973 digest_file (char const *filename, int *binary, unsigned char *bin_result,
974 bool *missing, MAYBE_UNUSED uintmax_t *length)
976 FILE *fp;
977 int err;
978 bool is_stdin = STREQ (filename, "-");
980 *missing = false;
982 if (is_stdin)
984 have_read_stdin = true;
985 fp = stdin;
986 if (O_BINARY && *binary)
988 if (*binary < 0)
989 *binary = ! isatty (STDIN_FILENO);
990 if (*binary)
991 xset_binary_mode (STDIN_FILENO, O_BINARY);
994 else
996 fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r"));
997 if (fp == nullptr)
999 if (ignore_missing && errno == ENOENT)
1001 *missing = true;
1002 return true;
1004 error (0, errno, "%s", quotef (filename));
1005 return false;
1009 fadvise (fp, FADVISE_SEQUENTIAL);
1011 #if HASH_ALGO_CKSUM
1012 if (cksum_algorithm == blake2b)
1013 *length = digest_length / 8;
1014 err = DIGEST_STREAM (fp, bin_result, length);
1015 #elif HASH_ALGO_SUM
1016 err = DIGEST_STREAM (fp, bin_result, length);
1017 #elif HASH_ALGO_BLAKE2
1018 err = DIGEST_STREAM (fp, bin_result, digest_length / 8);
1019 #else
1020 err = DIGEST_STREAM (fp, bin_result);
1021 #endif
1022 err = err ? errno : 0;
1023 if (is_stdin)
1024 clearerr (fp);
1025 else if (fclose (fp) != 0 && !err)
1026 err = errno;
1028 if (err)
1030 error (0, err, "%s", quotef (filename));
1031 return false;
1034 return true;
1037 #if !HASH_ALGO_SUM
1038 static void
1039 output_file (char const *file, int binary_file, void const *digest,
1040 bool raw, bool tagged, unsigned char delim, MAYBE_UNUSED bool args,
1041 MAYBE_UNUSED uintmax_t length)
1043 # if HASH_ALGO_CKSUM
1044 if (raw)
1046 fwrite (digest, 1, digest_length / 8, stdout);
1047 return;
1049 # endif
1051 unsigned char const *bin_buffer = digest;
1053 /* Output a leading backslash if the file name contains problematic chars. */
1054 bool needs_escape = delim == '\n' && problematic_chars (file);
1056 if (needs_escape)
1057 putchar ('\\');
1059 if (tagged)
1061 fputs (DIGEST_TYPE_STRING, stdout);
1062 # if HASH_ALGO_BLAKE2
1063 if (digest_length < BLAKE2B_MAX_LEN * 8)
1064 printf ("-%ju", digest_length);
1065 # elif HASH_ALGO_CKSUM
1066 if (cksum_algorithm == blake2b)
1068 if (digest_length < BLAKE2B_MAX_LEN * 8)
1069 printf ("-%ju", digest_length);
1071 # endif
1072 fputs (" (", stdout);
1073 print_filename (file, needs_escape);
1074 fputs (") = ", stdout);
1077 # if HASH_ALGO_CKSUM
1078 if (base64_digest)
1080 char b64[BASE64_LENGTH (DIGEST_BIN_BYTES) + 1];
1081 base64_encode ((char const *) bin_buffer, digest_length / 8,
1082 b64, sizeof b64);
1083 fputs (b64, stdout);
1085 else
1086 # endif
1088 for (size_t i = 0; i < (digest_hex_bytes / 2); ++i)
1089 printf ("%02x", bin_buffer[i]);
1092 if (!tagged)
1094 putchar (' ');
1095 putchar (binary_file ? '*' : ' ');
1096 print_filename (file, needs_escape);
1099 putchar (delim);
1101 #endif
1103 #if HASH_ALGO_CKSUM
1104 /* Return true if B64_DIGEST is the same as the base64 digest of the
1105 DIGEST_LENGTH/8 bytes at BIN_BUFFER. */
1106 static bool
1107 b64_equal (unsigned char const *b64_digest, unsigned char const *bin_buffer)
1109 size_t b64_n_bytes = BASE64_LENGTH (digest_length / 8);
1110 char b64[BASE64_LENGTH (DIGEST_BIN_BYTES) + 1];
1111 base64_encode ((char const *) bin_buffer, digest_length / 8, b64, sizeof b64);
1112 return memcmp (b64_digest, b64, b64_n_bytes + 1) == 0;
1114 #endif
1116 /* Return true if HEX_DIGEST is the same as the hex-encoded digest of the
1117 DIGEST_LENGTH/8 bytes at BIN_BUFFER. */
1118 static bool
1119 hex_equal (unsigned char const *hex_digest, unsigned char const *bin_buffer)
1121 static const char bin2hex[] = { '0', '1', '2', '3',
1122 '4', '5', '6', '7',
1123 '8', '9', 'a', 'b',
1124 'c', 'd', 'e', 'f' };
1125 size_t digest_bin_bytes = digest_hex_bytes / 2;
1127 /* Compare generated binary number with text representation
1128 in check file. Ignore case of hex digits. */
1129 size_t cnt;
1130 for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
1132 if (c_tolower (hex_digest[2 * cnt])
1133 != bin2hex[bin_buffer[cnt] >> 4]
1134 || (c_tolower (hex_digest[2 * cnt + 1])
1135 != (bin2hex[bin_buffer[cnt] & 0xf])))
1136 break;
1138 return cnt == digest_bin_bytes;
1141 static bool
1142 digest_check (char const *checkfile_name)
1144 FILE *checkfile_stream;
1145 uintmax_t n_misformatted_lines = 0;
1146 uintmax_t n_mismatched_checksums = 0;
1147 uintmax_t n_open_or_read_failures = 0;
1148 bool properly_formatted_lines = false;
1149 bool matched_checksums = false;
1150 unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
1151 /* Make sure bin_buffer is properly aligned. */
1152 unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
1153 uintmax_t line_number;
1154 char *line;
1155 size_t line_chars_allocated;
1156 bool is_stdin = STREQ (checkfile_name, "-");
1158 if (is_stdin)
1160 have_read_stdin = true;
1161 checkfile_name = _("standard input");
1162 checkfile_stream = stdin;
1164 else
1166 checkfile_stream = fopen (checkfile_name, "r");
1167 if (checkfile_stream == nullptr)
1169 error (0, errno, "%s", quotef (checkfile_name));
1170 return false;
1174 line_number = 0;
1175 line = nullptr;
1176 line_chars_allocated = 0;
1179 char *filename;
1180 int binary;
1181 unsigned char *digest;
1182 ssize_t line_length;
1184 ++line_number;
1185 if (line_number == 0)
1186 error (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
1187 quotef (checkfile_name));
1189 line_length = getline (&line, &line_chars_allocated, checkfile_stream);
1190 if (line_length <= 0)
1191 break;
1193 /* Ignore comment lines, which begin with a '#' character. */
1194 if (line[0] == '#')
1195 continue;
1197 /* Remove any trailing newline. */
1198 line_length -= line[line_length - 1] == '\n';
1199 /* Remove any trailing carriage return. */
1200 line_length -= line[line_length - (0 < line_length)] == '\r';
1202 /* Ignore empty lines. */
1203 if (line_length == 0)
1204 continue;
1206 line[line_length] = '\0';
1208 size_t d_len;
1209 if (! (split_3 (line, line_length, &digest, &d_len, &binary, &filename)
1210 && ! (is_stdin && STREQ (filename, "-"))))
1212 ++n_misformatted_lines;
1214 if (warn)
1216 error (0, 0,
1217 _("%s: %ju"
1218 ": improperly formatted %s checksum line"),
1219 quotef (checkfile_name), line_number,
1220 DIGEST_TYPE_STRING);
1223 else
1225 bool ok;
1226 bool missing;
1227 bool needs_escape = ! status_only && problematic_chars (filename);
1229 properly_formatted_lines = true;
1231 uintmax_t length;
1232 ok = digest_file (filename, &binary, bin_buffer, &missing, &length);
1234 if (!ok)
1236 ++n_open_or_read_failures;
1237 if (!status_only)
1239 if (needs_escape)
1240 putchar ('\\');
1241 print_filename (filename, needs_escape);
1242 printf (": %s\n", _("FAILED open or read"));
1245 else if (ignore_missing && missing)
1247 /* Ignore missing files with --ignore-missing. */
1250 else
1252 bool match = false;
1253 #if HASH_ALGO_CKSUM
1254 if (d_len < digest_hex_bytes)
1255 match = b64_equal (digest, bin_buffer);
1256 else
1257 #endif
1258 if (d_len == digest_hex_bytes)
1259 match = hex_equal (digest, bin_buffer);
1261 if (match)
1262 matched_checksums = true;
1263 else
1264 ++n_mismatched_checksums;
1266 if (!status_only)
1268 if (! match || ! quiet)
1270 if (needs_escape)
1271 putchar ('\\');
1272 print_filename (filename, needs_escape);
1275 if (! match)
1276 printf (": %s\n", _("FAILED"));
1277 else if (!quiet)
1278 printf (": %s\n", _("OK"));
1283 while (!feof (checkfile_stream) && !ferror (checkfile_stream));
1285 free (line);
1287 int err = ferror (checkfile_stream) ? 0 : -1;
1288 if (is_stdin)
1289 clearerr (checkfile_stream);
1290 else if (fclose (checkfile_stream) != 0 && err < 0)
1291 err = errno;
1293 if (0 <= err)
1295 error (0, err, err ? "%s" : _("%s: read error"),
1296 quotef (checkfile_name));
1297 return false;
1300 if (! properly_formatted_lines)
1302 /* Warn if no tests are found. */
1303 error (0, 0, _("%s: no properly formatted checksum lines found"),
1304 quotef (checkfile_name));
1306 else
1308 if (!status_only)
1310 if (n_misformatted_lines != 0)
1311 error (0, 0,
1312 (ngettext
1313 ("WARNING: %ju line is improperly formatted",
1314 "WARNING: %ju lines are improperly formatted",
1315 select_plural (n_misformatted_lines))),
1316 n_misformatted_lines);
1318 if (n_open_or_read_failures != 0)
1319 error (0, 0,
1320 (ngettext
1321 ("WARNING: %ju listed file could not be read",
1322 "WARNING: %ju listed files could not be read",
1323 select_plural (n_open_or_read_failures))),
1324 n_open_or_read_failures);
1326 if (n_mismatched_checksums != 0)
1327 error (0, 0,
1328 (ngettext
1329 ("WARNING: %ju computed checksum did NOT match",
1330 "WARNING: %ju computed checksums did NOT match",
1331 select_plural (n_mismatched_checksums))),
1332 n_mismatched_checksums);
1334 if (ignore_missing && ! matched_checksums)
1335 error (0, 0, _("%s: no file was verified"),
1336 quotef (checkfile_name));
1340 return (properly_formatted_lines
1341 && matched_checksums
1342 && n_mismatched_checksums == 0
1343 && n_open_or_read_failures == 0
1344 && (!strict || n_misformatted_lines == 0));
1348 main (int argc, char **argv)
1350 unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
1351 /* Make sure bin_buffer is properly aligned. */
1352 unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
1353 bool do_check = false;
1354 int opt;
1355 bool ok = true;
1356 int binary = -1;
1357 int prefix_tag = -1;
1359 /* Setting values of global variables. */
1360 initialize_main (&argc, &argv);
1361 set_program_name (argv[0]);
1362 setlocale (LC_ALL, "");
1363 bindtextdomain (PACKAGE, LOCALEDIR);
1364 textdomain (PACKAGE);
1366 atexit (close_stdout);
1368 /* Line buffer stdout to ensure lines are written atomically and immediately
1369 so that processes running in parallel do not intersperse their output. */
1370 setvbuf (stdout, nullptr, _IOLBF, 0);
1372 #if HASH_ALGO_SUM
1373 char const *short_opts = "rs";
1374 #elif HASH_ALGO_CKSUM
1375 char const *short_opts = "a:l:bctwz";
1376 char const *digest_length_str = "";
1377 #elif HASH_ALGO_BLAKE2
1378 char const *short_opts = "l:bctwz";
1379 char const *digest_length_str = "";
1380 #else
1381 char const *short_opts = "bctwz";
1382 #endif
1384 while ((opt = getopt_long (argc, argv, short_opts, long_options, nullptr))
1385 != -1)
1386 switch (opt)
1388 #if HASH_ALGO_CKSUM
1389 case 'a':
1390 cksum_algorithm = XARGMATCH_EXACT ("--algorithm", optarg,
1391 algorithm_args, algorithm_types);
1392 algorithm_specified = true;
1393 break;
1395 case DEBUG_PROGRAM_OPTION:
1396 cksum_debug = true;
1397 break;
1398 #endif
1399 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
1400 case 'l':
1401 digest_length = xnumtoumax (optarg, 10, 0, BLAKE2B_MAX_LEN * 8, "",
1402 _("invalid length"), 0,
1403 XTOINT_MAX_QUIET);
1404 digest_length_str = optarg;
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 case 'b':
1417 binary = 1;
1418 break;
1419 case 't':
1420 binary = 0;
1421 break;
1422 case 'w':
1423 status_only = false;
1424 warn = true;
1425 quiet = false;
1426 break;
1427 case IGNORE_MISSING_OPTION:
1428 ignore_missing = true;
1429 break;
1430 case QUIET_OPTION:
1431 status_only = false;
1432 warn = false;
1433 quiet = true;
1434 break;
1435 case STRICT_OPTION:
1436 strict = true;
1437 break;
1438 # if HASH_ALGO_CKSUM
1439 case BASE64_OPTION:
1440 base64_digest = true;
1441 break;
1442 case RAW_OPTION:
1443 raw_digest = true;
1444 break;
1445 case UNTAG_OPTION:
1446 if (prefix_tag == 1)
1447 binary = -1;
1448 prefix_tag = 0;
1449 break;
1450 # endif
1451 case TAG_OPTION:
1452 prefix_tag = 1;
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 % 8 != 0)
1491 error (0, 0, _("invalid length: %s"), quote (digest_length_str));
1492 error (EXIT_FAILURE, 0, _("length is not a multiple of 8"));
1494 if (digest_length == 0)
1496 # if HASH_ALGO_BLAKE2
1497 digest_length = BLAKE2B_MAX_LEN * 8;
1498 # else
1499 digest_length = algorithm_bits[cksum_algorithm];
1500 # endif
1502 digest_hex_bytes = digest_length / 4;
1503 #else
1504 digest_hex_bytes = DIGEST_HEX_BYTES;
1505 #endif
1507 #if HASH_ALGO_CKSUM
1508 switch (cksum_algorithm)
1510 case bsd:
1511 case sysv:
1512 case crc:
1513 case crc32b:
1514 if (do_check && algorithm_specified)
1515 error (EXIT_FAILURE, 0,
1516 _("--check is not supported with "
1517 "--algorithm={bsd,sysv,crc,crc32b}"));
1518 break;
1519 default:
1520 break;
1523 if (base64_digest && raw_digest)
1525 error (0, 0, _("--base64 and --raw are mutually exclusive"));
1526 usage (EXIT_FAILURE);
1528 #endif
1530 if (prefix_tag == -1)
1531 prefix_tag = HASH_ALGO_CKSUM;
1533 if (prefix_tag && !binary)
1535 /* This could be supported in a backwards compatible way
1536 by prefixing the output line with a space in text mode.
1537 However that's invasive enough that it was agreed to
1538 not support this mode with --tag, as --text use cases
1539 are adequately supported by the default output format. */
1540 #if !HASH_ALGO_CKSUM
1541 error (0, 0, _("--tag does not support --text mode"));
1542 #else
1543 error (0, 0, _("--text mode is only supported with --untagged"));
1544 #endif
1545 usage (EXIT_FAILURE);
1548 if (digest_delim != '\n' && do_check)
1550 error (0, 0, _("the --zero option is not supported when "
1551 "verifying checksums"));
1552 usage (EXIT_FAILURE);
1554 #if !HASH_ALGO_CKSUM
1555 if (prefix_tag && do_check)
1557 error (0, 0, _("the --tag option is meaningless when "
1558 "verifying checksums"));
1559 usage (EXIT_FAILURE);
1561 #endif
1563 if (0 <= binary && do_check)
1565 error (0, 0, _("the --binary and --text options are meaningless when "
1566 "verifying checksums"));
1567 usage (EXIT_FAILURE);
1570 if (ignore_missing && !do_check)
1572 error (0, 0,
1573 _("the --ignore-missing option is meaningful only when "
1574 "verifying checksums"));
1575 usage (EXIT_FAILURE);
1578 if (status_only && !do_check)
1580 error (0, 0,
1581 _("the --status option is meaningful only when verifying checksums"));
1582 usage (EXIT_FAILURE);
1585 if (warn && !do_check)
1587 error (0, 0,
1588 _("the --warn option is meaningful only when verifying checksums"));
1589 usage (EXIT_FAILURE);
1592 if (quiet && !do_check)
1594 error (0, 0,
1595 _("the --quiet option is meaningful only when verifying checksums"));
1596 usage (EXIT_FAILURE);
1599 if (strict & !do_check)
1601 error (0, 0,
1602 _("the --strict option is meaningful only when verifying checksums"));
1603 usage (EXIT_FAILURE);
1606 if (!O_BINARY && binary < 0)
1607 binary = 0;
1609 char **operand_lim = argv + argc;
1610 if (optind == argc)
1611 *operand_lim++ = bad_cast ("-");
1612 else if (1 < argc - optind && raw_digest)
1613 error (EXIT_FAILURE, 0,
1614 _("the --raw option is not supported with multiple files"));
1616 for (char **operandp = argv + optind; operandp < operand_lim; operandp++)
1618 char *file = *operandp;
1619 if (do_check)
1620 ok &= digest_check (file);
1621 else
1623 int binary_file = binary;
1624 bool missing;
1625 uintmax_t length;
1627 if (! digest_file (file, &binary_file, bin_buffer, &missing, &length))
1628 ok = false;
1629 else
1631 DIGEST_OUT (file, binary_file, bin_buffer, raw_digest, prefix_tag,
1632 digest_delim, optind != argc, length);
1637 if (have_read_stdin && fclose (stdin) == EOF)
1638 error (EXIT_FAILURE, errno, _("standard input"));
1640 return ok ? EXIT_SUCCESS : EXIT_FAILURE;