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>. */
22 #include <sys/types.h>
28 #include "xdectoint.h"
31 #ifndef HASH_ALGO_CKSUM
32 # define HASH_ALGO_CKSUM 0
35 #if HASH_ALGO_SUM || HASH_ALGO_CKSUM
42 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
43 # include "blake2/b2sum.h"
45 #if HASH_ALGO_MD5 || HASH_ALGO_CKSUM
48 #if HASH_ALGO_SHA1 || HASH_ALGO_CKSUM
51 #if HASH_ALGO_SHA256 || HASH_ALGO_SHA224 || HASH_ALGO_CKSUM
54 #if HASH_ALGO_SHA512 || HASH_ALGO_SHA384 || HASH_ALGO_CKSUM
62 #include "xbinary-io.h"
64 /* The official name of this program (e.g., no 'g' prefix). */
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
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
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
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
131 # error "Can't decide which hash algorithm to compile."
133 #if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM
134 # define DIGEST_OUT output_file
139 proper_name ("Kayvan Aghaiepour"), \
140 proper_name ("David MacKenzie")
141 #elif HASH_ALGO_CKSUM
143 proper_name_lite ("Padraig Brady", "P\303\241draig Brady"), \
144 proper_name ("Q. Frank Xia")
145 #elif HASH_ALGO_BLAKE2
147 proper_name_lite ("Padraig Brady", "P\303\241draig Brady"), \
148 proper_name ("Samuel Neves")
151 proper_name ("Ulrich Drepper"), \
152 proper_name ("Scott Miller"), \
153 proper_name ("David Madore")
155 #if !HASH_ALGO_BLAKE2 && !HASH_ALGO_CKSUM
156 # define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
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. */
165 # define MIN_DIGEST_LINE_LENGTH \
166 (DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
168 + 1 /* minimum filename length */ )
173 output_file (char const *file
, int binary_file
, void const *digest
,
174 bool raw
, bool tagged
, unsigned char delim
, bool args
,
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';
212 /* If true, print base64-encoded digests, not hex. */
213 static bool base64_digest
= false;
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);
233 static enum Algorithm sum_algorithm
;
234 static sumfn sumfns
[]=
239 static digest_output_fn sum_output_fns
[]=
248 md5_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
250 return md5_stream (stream
, resstream
);
253 sha1_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
255 return sha1_stream (stream
, resstream
);
258 sha224_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
260 return sha224_stream (stream
, resstream
);
263 sha256_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
265 return sha256_stream (stream
, resstream
);
268 sha384_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
270 return sha384_stream (stream
, resstream
);
273 sha512_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
275 return sha512_stream (stream
, resstream
);
278 blake2b_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
280 return blake2b_stream (stream
, resstream
, *length
);
283 sm3_sum_stream (FILE *stream
, void *resstream
, uintmax_t *length
)
285 return sm3_stream (stream
, resstream
);
303 static char const *const algorithm_args
[] =
305 "bsd", "sysv", "crc", "md5", "sha1", "sha224",
306 "sha256", "sha384", "sha512", "blake2b", "sm3", nullptr
308 static enum Algorithm
const algorithm_types
[] =
310 bsd
, sysv
, crc
, md5
, sha1
, sha224
,
311 sha256
, sha384
, sha512
, blake2b
, sm3
,
313 ARGMATCH_VERIFY (algorithm_args
, algorithm_types
);
315 static char const *const algorithm_tags
[] =
317 "BSD", "SYSV", "CRC", "MD5", "SHA1", "SHA224",
318 "SHA256", "SHA384", "SHA512", "BLAKE2b", "SM3", nullptr
320 static int const algorithm_bits
[] =
322 16, 16, 32, 128, 160, 224,
323 256, 384, 512, 512, 256, 0
326 static_assert (ARRAY_CARDINALITY (algorithm_bits
)
327 == ARRAY_CARDINALITY (algorithm_args
));
329 static bool algorithm_specified
= false;
330 static enum Algorithm cksum_algorithm
= crc
;
331 static sumfn cksumfns
[]=
345 static digest_output_fn cksum_output_fns
[]=
362 /* For long options that have no equivalent short option, use a
363 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
367 IGNORE_MISSING_OPTION
= CHAR_MAX
+ 1,
373 DEBUG_PROGRAM_OPTION
,
378 static struct option
const long_options
[] =
380 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
381 { "length", required_argument
, nullptr, 'l'},
385 { "check", no_argument
, nullptr, 'c' },
386 { "ignore-missing", no_argument
, nullptr, IGNORE_MISSING_OPTION
},
387 { "quiet", no_argument
, nullptr, QUIET_OPTION
},
388 { "status", no_argument
, nullptr, STATUS_OPTION
},
389 { "warn", no_argument
, nullptr, 'w' },
390 { "strict", no_argument
, nullptr, STRICT_OPTION
},
391 { "tag", no_argument
, nullptr, TAG_OPTION
},
392 { "zero", no_argument
, nullptr, 'z' },
395 { "algorithm", required_argument
, nullptr, 'a'},
396 { "base64", no_argument
, nullptr, BASE64_OPTION
},
397 { "debug", no_argument
, nullptr, DEBUG_PROGRAM_OPTION
},
398 { "raw", no_argument
, nullptr, RAW_OPTION
},
399 { "untagged", no_argument
, nullptr, UNTAG_OPTION
},
401 { "binary", no_argument
, nullptr, 'b' },
402 { "text", no_argument
, nullptr, 't' },
405 {"sysv", no_argument
, nullptr, 's'},
408 { GETOPT_HELP_OPTION_DECL
},
409 { GETOPT_VERSION_OPTION_DECL
},
410 { nullptr, 0, nullptr, 0 }
416 if (status
!= EXIT_SUCCESS
)
421 Usage: %s [OPTION]... [FILE]...\n\
425 Print or verify checksums.\n\
426 By default use the 32 bit CRC algorithm.\n\
430 Print or check %s (%d-bit) checksums.\n\
440 -r use BSD sum algorithm (the default), use 1K blocks\n\
441 -s, --sysv use System V sum algorithm, use 512 bytes blocks\n\
444 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
445 emit_mandatory_arg_note ();
449 -a, --algorithm=TYPE select the digest type to use. See DIGEST below.\
453 --base64 emit base64-encoded digests, not hexadecimal\
458 # if !HASH_ALGO_CKSUM
461 -b, --binary read in binary mode (default unless reading tty stdin)\
466 -b, --binary read in binary mode\n\
470 -c, --check read checksums from the FILEs and check them\n\
472 # if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
474 -l, --length=BITS digest length in bits; must not exceed the max for\n\
475 the blake2 algorithm and must be a multiple of 8\n\
480 --raw emit a raw binary digest, not hexadecimal\
484 --tag create a BSD-style checksum (the default)\n\
487 --untagged create a reversed style checksum, without digest type\n\
491 --tag create a BSD-style checksum\n\
494 # if !HASH_ALGO_CKSUM
497 -t, --text read in text mode (default if reading tty stdin)\n\
501 -t, --text read in text mode (default)\n\
505 -z, --zero end each output line with NUL, not newline,\n\
506 and disable file name escaping\n\
510 The following five options are useful only when verifying checksums:\n\
511 --ignore-missing don't fail or report status for missing files\n\
512 --quiet don't print OK for each successfully verified file\n\
513 --status don't output anything, status code shows success\n\
514 --strict exit non-zero for improperly formatted checksum lines\n\
515 -w, --warn warn about improperly formatted checksum lines\n\
521 --debug indicate which implementation used\n\
524 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
525 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
529 DIGEST determines the digest algorithm and default output format:\n\
530 sysv (equivalent to sum -s)\n\
531 bsd (equivalent to sum -r)\n\
532 crc (equivalent to cksum)\n\
533 md5 (equivalent to md5sum)\n\
534 sha1 (equivalent to sha1sum)\n\
535 sha224 (equivalent to sha224sum)\n\
536 sha256 (equivalent to sha256sum)\n\
537 sha384 (equivalent to sha384sum)\n\
538 sha512 (equivalent to sha512sum)\n\
539 blake2b (equivalent to b2sum)\n\
540 sm3 (only available through cksum)\n\
543 #if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM
546 The sums are computed as described in %s.\n"), DIGEST_REFERENCE
);
548 When checking, the input should be a former output of this program.\n\
549 The default mode is to print a line with: checksum, a space,\n\
550 a character indicating input mode ('*' for binary, ' ' for text\n\
551 or where binary is insignificant), and name for each FILE.\n\
553 There is no difference between binary mode and text mode on GNU systems.\
558 When checking, the input should be a former output of this program,\n\
559 or equivalent standalone program.\
562 emit_ancillary_info (PROGRAM_NAME
);
568 /* Given a string S, return TRUE if it contains problematic characters
569 that need escaping. Note we escape '\' itself to provide some forward
570 compat to introduce escaping of other characters. */
574 problematic_chars (char const *s
)
576 size_t length
= strcspn (s
, "\\\n\r");
577 return s
[length
] != '\0';
580 #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
582 /* Given a file name, S of length S_LEN, that is not NUL-terminated,
583 modify it in place, performing the equivalent of this sed substitution:
584 's/\\n/\n/g;s/\\r/\r/g;s/\\\\/\\/g' i.e., replacing each "\\n" string
585 with a newline, each "\\r" string with a carriage return,
586 and each "\\\\" with a single backslash, NUL-terminate it and return S.
587 If S is not a valid escaped file name, i.e., if it ends with an odd number
588 of backslashes or if it contains a backslash followed by anything other
589 than "n" or another backslash, return nullptr. */
592 filename_unescape (char *s
, size_t s_len
)
596 for (size_t i
= 0; i
< s_len
; i
++)
603 /* File name ends with an unescaped backslash: invalid. */
619 /* Only '\', 'n' or 'r' may follow a backslash. */
625 /* The file name may not contain a NUL. */
639 /* Return true if S is a LEN-byte NUL-terminated string of hex or base64
640 digits and has the expected length. Otherwise, return false. */
643 valid_digits (unsigned char const *s
, size_t len
)
646 if (len
== BASE64_LENGTH (digest_length
/ 8))
649 for (i
= 0; i
< len
- digest_length
% 3; i
++)
655 for ( ; i
< len
; i
++)
664 if (len
== digest_hex_bytes
)
666 for (idx_t i
= 0; i
< digest_hex_bytes
; i
++)
668 if (!c_isxdigit (*s
))
679 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
680 'sha1' command into two parts: a hexadecimal digest, and the file
681 name. S is modified. Set *D_LEN to the length of the digest string.
682 Return true if successful. */
685 bsd_split_3 (char *s
, size_t s_len
,
686 unsigned char **digest
, size_t *d_len
,
687 char **file_name
, bool escaped_filename
)
692 /* Find end of filename. */
693 size_t i
= s_len
- 1;
694 while (i
&& s
[i
] != ')')
702 if (escaped_filename
&& filename_unescape (s
, i
) == nullptr)
707 while (ISWHITE (s
[i
]))
715 while (ISWHITE (s
[i
]))
718 *digest
= (unsigned char *) &s
[i
];
721 return valid_digits (*digest
, *d_len
);
725 /* Return the corresponding Algorithm for the string S,
726 or -1 for no match. */
729 algorithm_from_tag (char *s
)
731 /* Limit check size to this length for perf reasons. */
732 static size_t max_tag_len
;
735 char const * const * tag
= algorithm_tags
;
738 size_t tag_len
= strlen (*tag
++);
739 max_tag_len
= MAX (tag_len
, max_tag_len
);
745 /* Find end of tag */
746 while (i
<= max_tag_len
&& s
[i
] && ! ISWHITE (s
[i
])
747 && s
[i
] != '-' && s
[i
] != '(')
753 /* Terminate tag, and lookup. */
756 ptrdiff_t algo
= argmatch_exact (s
, algorithm_tags
);
763 /* Split the string S (of length S_LEN) into three parts:
764 a hexadecimal digest, binary flag, and the file name.
765 S is modified. Set *D_LEN to the length of the digest string.
766 Return true if successful. */
769 split_3 (char *s
, size_t s_len
,
770 unsigned char **digest
, size_t *d_len
, int *binary
, char **file_name
)
772 bool escaped_filename
= false;
773 size_t algo_name_len
;
776 while (ISWHITE (s
[i
]))
782 escaped_filename
= true;
785 /* Check for BSD-style checksum line. */
788 if (! algorithm_specified
)
790 ptrdiff_t algo_tag
= algorithm_from_tag (s
+ i
);
794 return false; /* We don't support checking these older formats. */
795 cksum_algorithm
= algo_tag
;
798 return false; /* We only support tagged format without -a. */
802 algo_name_len
= strlen (DIGEST_TYPE_STRING
);
803 if (STREQ_LEN (s
+ i
, DIGEST_TYPE_STRING
, algo_name_len
))
806 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
807 /* Terminate and match algorithm name. */
808 char const *algo_name
= &s
[i
- algo_name_len
];
809 bool length_specified
= s
[i
] == '-';
810 bool openssl_format
= s
[i
] == '('; /* and no length_specified */
812 if (!STREQ (algo_name
, DIGEST_TYPE_STRING
))
817 # if HASH_ALGO_BLAKE2
818 digest_length
= BLAKE2B_MAX_LEN
* 8;
820 digest_length
= algorithm_bits
[cksum_algorithm
];
822 if (length_specified
)
826 if (! (xstrtoumax (s
+ i
, &siend
, 0, &length
, nullptr) == LONGINT_OK
827 && 0 < length
&& length
<= digest_length
832 digest_length
= length
;
834 digest_hex_bytes
= digest_length
/ 4;
842 return bsd_split_3 (s
+ i
, s_len
- i
,
843 digest
, d_len
, file_name
, escaped_filename
);
848 /* Ignore this line if it is too short.
849 Each line must have at least 'min_digest_line_length - 1' (or one more, if
850 the first is a backslash) more characters to contain correct message digest
852 if (s_len
- i
< min_digest_line_length
+ (s
[i
] == '\\'))
855 *digest
= (unsigned char *) &s
[i
];
857 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
858 /* Auto determine length. */
860 if (cksum_algorithm
== blake2b
) {
862 unsigned char const *hp
= *digest
;
863 digest_hex_bytes
= 0;
864 while (c_isxdigit (*hp
++))
866 if (digest_hex_bytes
< 2 || digest_hex_bytes
% 2
867 || BLAKE2B_MAX_LEN
* 2 < digest_hex_bytes
)
869 digest_length
= digest_hex_bytes
* 4;
875 /* This field must be the hexadecimal or base64 representation
876 of the message digest. */
877 while (s
[i
] && !ISWHITE (s
[i
]))
880 /* The digest must be followed by at least one whitespace character. */
884 *d_len
= &s
[i
] - (char *) *digest
;
887 if (! valid_digits (*digest
, *d_len
))
890 /* If "bsd reversed" format detected. */
891 if ((s_len
- i
== 1) || (s
[i
] != ' ' && s
[i
] != '*'))
893 /* Don't allow mixing bsd and standard formats,
894 to minimize security issues with attackers
895 renaming files with leading spaces.
896 This assumes that with bsd format checksums
897 that the first file name does not have
898 a leading ' ' or '*'. */
899 if (bsd_reversed
== 0)
903 else if (bsd_reversed
!= 1)
906 *binary
= (s
[i
++] == '*');
909 /* All characters between the type indicator and end of line are
910 significant -- that includes leading and trailing white space. */
913 if (escaped_filename
)
914 return filename_unescape (&s
[i
], s_len
- i
) != nullptr;
919 /* If ESCAPE is true, then translate each:
920 NEWLINE byte to the string, "\\n",
921 CARRIAGE RETURN byte to the string, "\\r",
922 and each backslash to "\\\\". */
924 print_filename (char const *file
, bool escape
)
928 fputs (file
, stdout
);
937 fputs ("\\n", stdout
);
941 fputs ("\\r", stdout
);
945 fputs ("\\\\", stdout
);
956 /* An interface to the function, DIGEST_STREAM.
957 Operate on FILENAME (it may be "-").
959 *BINARY indicates whether the file is binary. BINARY < 0 means it
960 depends on whether binary mode makes any difference and the file is
961 a terminal; in that case, clear *BINARY if the file was treated as
962 text because it was a terminal.
964 Put the checksum in *BIN_RESULT, which must be properly aligned.
965 Put true in *MISSING if the file can't be opened due to ENOENT.
966 Return true if successful. */
969 digest_file (char const *filename
, int *binary
, unsigned char *bin_result
,
970 bool *missing
, MAYBE_UNUSED
uintmax_t *length
)
974 bool is_stdin
= STREQ (filename
, "-");
980 have_read_stdin
= true;
982 if (O_BINARY
&& *binary
)
985 *binary
= ! isatty (STDIN_FILENO
);
987 xset_binary_mode (STDIN_FILENO
, O_BINARY
);
992 fp
= fopen (filename
, (O_BINARY
&& *binary
? "rb" : "r"));
995 if (ignore_missing
&& errno
== ENOENT
)
1000 error (0, errno
, "%s", quotef (filename
));
1005 fadvise (fp
, FADVISE_SEQUENTIAL
);
1008 if (cksum_algorithm
== blake2b
)
1009 *length
= digest_length
/ 8;
1010 err
= DIGEST_STREAM (fp
, bin_result
, length
);
1012 err
= DIGEST_STREAM (fp
, bin_result
, length
);
1013 #elif HASH_ALGO_BLAKE2
1014 err
= DIGEST_STREAM (fp
, bin_result
, digest_length
/ 8);
1016 err
= DIGEST_STREAM (fp
, bin_result
);
1018 err
= err
? errno
: 0;
1021 else if (fclose (fp
) != 0 && !err
)
1026 error (0, err
, "%s", quotef (filename
));
1035 output_file (char const *file
, int binary_file
, void const *digest
,
1036 bool raw
, bool tagged
, unsigned char delim
, MAYBE_UNUSED
bool args
,
1037 MAYBE_UNUSED
uintmax_t length
)
1039 # if HASH_ALGO_CKSUM
1042 fwrite (digest
, 1, digest_length
/ 8, stdout
);
1047 unsigned char const *bin_buffer
= digest
;
1049 /* Output a leading backslash if the file name contains problematic chars. */
1050 bool needs_escape
= delim
== '\n' && problematic_chars (file
);
1057 fputs (DIGEST_TYPE_STRING
, stdout
);
1058 # if HASH_ALGO_BLAKE2
1059 if (digest_length
< BLAKE2B_MAX_LEN
* 8)
1060 printf ("-%ju", digest_length
);
1061 # elif HASH_ALGO_CKSUM
1062 if (cksum_algorithm
== blake2b
)
1064 if (digest_length
< BLAKE2B_MAX_LEN
* 8)
1065 printf ("-%ju", digest_length
);
1068 fputs (" (", stdout
);
1069 print_filename (file
, needs_escape
);
1070 fputs (") = ", stdout
);
1073 # if HASH_ALGO_CKSUM
1076 char b64
[BASE64_LENGTH (DIGEST_BIN_BYTES
) + 1];
1077 base64_encode ((char const *) bin_buffer
, digest_length
/ 8,
1079 fputs (b64
, stdout
);
1084 for (size_t i
= 0; i
< (digest_hex_bytes
/ 2); ++i
)
1085 printf ("%02x", bin_buffer
[i
]);
1091 putchar (binary_file
? '*' : ' ');
1092 print_filename (file
, needs_escape
);
1100 /* Return true if B64_DIGEST is the same as the base64 digest of the
1101 DIGEST_LENGTH/8 bytes at BIN_BUFFER. */
1103 b64_equal (unsigned char const *b64_digest
, unsigned char const *bin_buffer
)
1105 size_t b64_n_bytes
= BASE64_LENGTH (digest_length
/ 8);
1106 char b64
[BASE64_LENGTH (DIGEST_BIN_BYTES
) + 1];
1107 base64_encode ((char const *) bin_buffer
, digest_length
/ 8, b64
, sizeof b64
);
1108 return memcmp (b64_digest
, b64
, b64_n_bytes
+ 1) == 0;
1112 /* Return true if HEX_DIGEST is the same as the hex-encoded digest of the
1113 DIGEST_LENGTH/8 bytes at BIN_BUFFER. */
1115 hex_equal (unsigned char const *hex_digest
, unsigned char const *bin_buffer
)
1117 static const char bin2hex
[] = { '0', '1', '2', '3',
1120 'c', 'd', 'e', 'f' };
1121 size_t digest_bin_bytes
= digest_hex_bytes
/ 2;
1123 /* Compare generated binary number with text representation
1124 in check file. Ignore case of hex digits. */
1126 for (cnt
= 0; cnt
< digest_bin_bytes
; ++cnt
)
1128 if (c_tolower (hex_digest
[2 * cnt
])
1129 != bin2hex
[bin_buffer
[cnt
] >> 4]
1130 || (c_tolower (hex_digest
[2 * cnt
+ 1])
1131 != (bin2hex
[bin_buffer
[cnt
] & 0xf])))
1134 return cnt
== digest_bin_bytes
;
1138 digest_check (char const *checkfile_name
)
1140 FILE *checkfile_stream
;
1141 uintmax_t n_misformatted_lines
= 0;
1142 uintmax_t n_mismatched_checksums
= 0;
1143 uintmax_t n_open_or_read_failures
= 0;
1144 bool properly_formatted_lines
= false;
1145 bool matched_checksums
= false;
1146 unsigned char bin_buffer_unaligned
[DIGEST_BIN_BYTES
+ DIGEST_ALIGN
];
1147 /* Make sure bin_buffer is properly aligned. */
1148 unsigned char *bin_buffer
= ptr_align (bin_buffer_unaligned
, DIGEST_ALIGN
);
1149 uintmax_t line_number
;
1151 size_t line_chars_allocated
;
1152 bool is_stdin
= STREQ (checkfile_name
, "-");
1156 have_read_stdin
= true;
1157 checkfile_name
= _("standard input");
1158 checkfile_stream
= stdin
;
1162 checkfile_stream
= fopen (checkfile_name
, "r");
1163 if (checkfile_stream
== nullptr)
1165 error (0, errno
, "%s", quotef (checkfile_name
));
1172 line_chars_allocated
= 0;
1177 unsigned char *digest
;
1178 ssize_t line_length
;
1181 if (line_number
== 0)
1182 error (EXIT_FAILURE
, 0, _("%s: too many checksum lines"),
1183 quotef (checkfile_name
));
1185 line_length
= getline (&line
, &line_chars_allocated
, checkfile_stream
);
1186 if (line_length
<= 0)
1189 /* Ignore comment lines, which begin with a '#' character. */
1193 /* Remove any trailing newline. */
1194 line_length
-= line
[line_length
- 1] == '\n';
1195 /* Remove any trailing carriage return. */
1196 line_length
-= line
[line_length
- (0 < line_length
)] == '\r';
1198 /* Ignore empty lines. */
1199 if (line_length
== 0)
1202 line
[line_length
] = '\0';
1205 if (! (split_3 (line
, line_length
, &digest
, &d_len
, &binary
, &filename
)
1206 && ! (is_stdin
&& STREQ (filename
, "-"))))
1208 ++n_misformatted_lines
;
1214 ": improperly formatted %s checksum line"),
1215 quotef (checkfile_name
), line_number
,
1216 DIGEST_TYPE_STRING
);
1223 bool needs_escape
= ! status_only
&& problematic_chars (filename
);
1225 properly_formatted_lines
= true;
1228 ok
= digest_file (filename
, &binary
, bin_buffer
, &missing
, &length
);
1232 ++n_open_or_read_failures
;
1237 print_filename (filename
, needs_escape
);
1238 printf (": %s\n", _("FAILED open or read"));
1241 else if (ignore_missing
&& missing
)
1243 /* Ignore missing files with --ignore-missing. */
1250 if (d_len
< digest_hex_bytes
)
1251 match
= b64_equal (digest
, bin_buffer
);
1254 if (d_len
== digest_hex_bytes
)
1255 match
= hex_equal (digest
, bin_buffer
);
1258 matched_checksums
= true;
1260 ++n_mismatched_checksums
;
1264 if (! match
|| ! quiet
)
1268 print_filename (filename
, needs_escape
);
1272 printf (": %s\n", _("FAILED"));
1274 printf (": %s\n", _("OK"));
1279 while (!feof (checkfile_stream
) && !ferror (checkfile_stream
));
1283 int err
= ferror (checkfile_stream
) ? 0 : -1;
1285 clearerr (checkfile_stream
);
1286 else if (fclose (checkfile_stream
) != 0 && err
< 0)
1291 error (0, err
, err
? "%s" : _("%s: read error"),
1292 quotef (checkfile_name
));
1296 if (! properly_formatted_lines
)
1298 /* Warn if no tests are found. */
1299 error (0, 0, _("%s: no properly formatted checksum lines found"),
1300 quotef (checkfile_name
));
1306 if (n_misformatted_lines
!= 0)
1309 ("WARNING: %ju line is improperly formatted",
1310 "WARNING: %ju lines are improperly formatted",
1311 select_plural (n_misformatted_lines
))),
1312 n_misformatted_lines
);
1314 if (n_open_or_read_failures
!= 0)
1317 ("WARNING: %ju listed file could not be read",
1318 "WARNING: %ju listed files could not be read",
1319 select_plural (n_open_or_read_failures
))),
1320 n_open_or_read_failures
);
1322 if (n_mismatched_checksums
!= 0)
1325 ("WARNING: %ju computed checksum did NOT match",
1326 "WARNING: %ju computed checksums did NOT match",
1327 select_plural (n_mismatched_checksums
))),
1328 n_mismatched_checksums
);
1330 if (ignore_missing
&& ! matched_checksums
)
1331 error (0, 0, _("%s: no file was verified"),
1332 quotef (checkfile_name
));
1336 return (properly_formatted_lines
1337 && matched_checksums
1338 && n_mismatched_checksums
== 0
1339 && n_open_or_read_failures
== 0
1340 && (!strict
|| n_misformatted_lines
== 0));
1344 main (int argc
, char **argv
)
1346 unsigned char bin_buffer_unaligned
[DIGEST_BIN_BYTES
+ DIGEST_ALIGN
];
1347 /* Make sure bin_buffer is properly aligned. */
1348 unsigned char *bin_buffer
= ptr_align (bin_buffer_unaligned
, DIGEST_ALIGN
);
1349 bool do_check
= false;
1353 int prefix_tag
= -1;
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);
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
= "";
1377 char const *short_opts
= "bctwz";
1380 while ((opt
= getopt_long (argc
, argv
, short_opts
, long_options
, nullptr))
1386 cksum_algorithm
= XARGMATCH_EXACT ("--algorithm", optarg
,
1387 algorithm_args
, algorithm_types
);
1388 algorithm_specified
= true;
1391 case DEBUG_PROGRAM_OPTION
:
1395 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
1397 digest_length
= xdectoumax (optarg
, 0, UINTMAX_MAX
, "",
1398 _("invalid length"), 0);
1399 digest_length_str
= optarg
;
1418 status_only
= false;
1422 case IGNORE_MISSING_OPTION
:
1423 ignore_missing
= true;
1426 status_only
= false;
1433 # if HASH_ALGO_CKSUM
1435 base64_digest
= true;
1441 if (prefix_tag
== 1)
1451 digest_delim
= '\0';
1455 case 'r': /* For SysV compatibility. */
1456 sum_algorithm
= bsd
;
1460 sum_algorithm
= sysv
;
1463 case_GETOPT_HELP_CHAR
;
1464 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
1466 usage (EXIT_FAILURE
);
1469 min_digest_line_length
= MIN_DIGEST_LINE_LENGTH
;
1470 #if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM
1471 # if HASH_ALGO_CKSUM
1472 if (digest_length
&& cksum_algorithm
!= blake2b
)
1473 error (EXIT_FAILURE
, 0,
1474 _("--length is only supported with --algorithm=blake2b"));
1476 if (digest_length
% 8 != 0)
1478 error (0, 0, _("invalid length: %s"), quote (digest_length_str
));
1479 error (EXIT_FAILURE
, 0, _("length is not a multiple of 8"));
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;
1494 digest_length
= algorithm_bits
[cksum_algorithm
];
1497 digest_hex_bytes
= digest_length
/ 4;
1499 digest_hex_bytes
= DIGEST_HEX_BYTES
;
1503 switch (cksum_algorithm
)
1508 if (do_check
&& algorithm_specified
)
1509 error (EXIT_FAILURE
, 0,
1510 _("--check is not supported with --algorithm={bsd,sysv,crc}"));
1516 if (base64_digest
&& raw_digest
)
1518 error (0, 0, _("--base64 and --raw are mutually exclusive"));
1519 usage (EXIT_FAILURE
);
1523 if (prefix_tag
== -1)
1524 prefix_tag
= HASH_ALGO_CKSUM
;
1526 if (prefix_tag
&& !binary
)
1528 /* This could be supported in a backwards compatible way
1529 by prefixing the output line with a space in text mode.
1530 However that's invasive enough that it was agreed to
1531 not support this mode with --tag, as --text use cases
1532 are adequately supported by the default output format. */
1533 #if !HASH_ALGO_CKSUM
1534 error (0, 0, _("--tag does not support --text mode"));
1536 error (0, 0, _("--text mode is only supported with --untagged"));
1538 usage (EXIT_FAILURE
);
1541 if (digest_delim
!= '\n' && do_check
)
1543 error (0, 0, _("the --zero option is not supported when "
1544 "verifying checksums"));
1545 usage (EXIT_FAILURE
);
1547 #if !HASH_ALGO_CKSUM
1548 if (prefix_tag
&& do_check
)
1550 error (0, 0, _("the --tag option is meaningless when "
1551 "verifying checksums"));
1552 usage (EXIT_FAILURE
);
1556 if (0 <= binary
&& do_check
)
1558 error (0, 0, _("the --binary and --text options are meaningless when "
1559 "verifying checksums"));
1560 usage (EXIT_FAILURE
);
1563 if (ignore_missing
&& !do_check
)
1566 _("the --ignore-missing option is meaningful only when "
1567 "verifying checksums"));
1568 usage (EXIT_FAILURE
);
1571 if (status_only
&& !do_check
)
1574 _("the --status option is meaningful only when verifying checksums"));
1575 usage (EXIT_FAILURE
);
1578 if (warn
&& !do_check
)
1581 _("the --warn option is meaningful only when verifying checksums"));
1582 usage (EXIT_FAILURE
);
1585 if (quiet
&& !do_check
)
1588 _("the --quiet option is meaningful only when verifying checksums"));
1589 usage (EXIT_FAILURE
);
1592 if (strict
& !do_check
)
1595 _("the --strict option is meaningful only when verifying checksums"));
1596 usage (EXIT_FAILURE
);
1599 if (!O_BINARY
&& binary
< 0)
1602 char **operand_lim
= argv
+ argc
;
1604 *operand_lim
++ = bad_cast ("-");
1605 else if (1 < argc
- optind
&& raw_digest
)
1606 error (EXIT_FAILURE
, 0,
1607 _("the --raw option is not supported with multiple files"));
1609 for (char **operandp
= argv
+ optind
; operandp
< operand_lim
; operandp
++)
1611 char *file
= *operandp
;
1613 ok
&= digest_check (file
);
1616 int binary_file
= binary
;
1620 if (! digest_file (file
, &binary_file
, bin_buffer
, &missing
, &length
))
1624 DIGEST_OUT (file
, binary_file
, bin_buffer
, raw_digest
, prefix_tag
,
1625 digest_delim
, optind
!= argc
, length
);
1630 if (have_read_stdin
&& fclose (stdin
) == EOF
)
1631 error (EXIT_FAILURE
, errno
, _("standard input"));
1633 return ok
? EXIT_SUCCESS
: EXIT_FAILURE
;