maint: add doc/coverage to .gitignore
[coreutils.git] / src / md5sum.c
blobc8002317856b747d086a8a73cc04dfb1d24259c8
1 /* Compute checksums of files or strings.
2 Copyright (C) 1995-2017 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_BLAKE2
31 # include "blake2/b2sum.h"
32 #endif
33 #if HASH_ALGO_MD5
34 # include "md5.h"
35 #endif
36 #if HASH_ALGO_SHA1
37 # include "sha1.h"
38 #endif
39 #if HASH_ALGO_SHA256 || HASH_ALGO_SHA224
40 # include "sha256.h"
41 #endif
42 #if HASH_ALGO_SHA512 || HASH_ALGO_SHA384
43 # include "sha512.h"
44 #endif
45 #include "die.h"
46 #include "error.h"
47 #include "fadvise.h"
48 #include "stdio--.h"
49 #include "xbinary-io.h"
51 /* The official name of this program (e.g., no 'g' prefix). */
52 #if HASH_ALGO_MD5
53 # define PROGRAM_NAME "md5sum"
54 # define DIGEST_TYPE_STRING "MD5"
55 # define DIGEST_STREAM md5_stream
56 # define DIGEST_BITS 128
57 # define DIGEST_REFERENCE "RFC 1321"
58 # define DIGEST_ALIGN 4
59 #elif HASH_ALGO_BLAKE2
60 # define PROGRAM_NAME "b2sum"
61 # define DIGEST_TYPE_STRING "BLAKE2"
62 # define DIGEST_STREAM blake2fns[b2_algorithm]
63 # define DIGEST_BITS 512
64 # define DIGEST_REFERENCE "RFC 7693"
65 # define DIGEST_ALIGN 8
66 #elif HASH_ALGO_SHA1
67 # define PROGRAM_NAME "sha1sum"
68 # define DIGEST_TYPE_STRING "SHA1"
69 # define DIGEST_STREAM sha1_stream
70 # define DIGEST_BITS 160
71 # define DIGEST_REFERENCE "FIPS-180-1"
72 # define DIGEST_ALIGN 4
73 #elif HASH_ALGO_SHA256
74 # define PROGRAM_NAME "sha256sum"
75 # define DIGEST_TYPE_STRING "SHA256"
76 # define DIGEST_STREAM sha256_stream
77 # define DIGEST_BITS 256
78 # define DIGEST_REFERENCE "FIPS-180-2"
79 # define DIGEST_ALIGN 4
80 #elif HASH_ALGO_SHA224
81 # define PROGRAM_NAME "sha224sum"
82 # define DIGEST_TYPE_STRING "SHA224"
83 # define DIGEST_STREAM sha224_stream
84 # define DIGEST_BITS 224
85 # define DIGEST_REFERENCE "RFC 3874"
86 # define DIGEST_ALIGN 4
87 #elif HASH_ALGO_SHA512
88 # define PROGRAM_NAME "sha512sum"
89 # define DIGEST_TYPE_STRING "SHA512"
90 # define DIGEST_STREAM sha512_stream
91 # define DIGEST_BITS 512
92 # define DIGEST_REFERENCE "FIPS-180-2"
93 # define DIGEST_ALIGN 8
94 #elif HASH_ALGO_SHA384
95 # define PROGRAM_NAME "sha384sum"
96 # define DIGEST_TYPE_STRING "SHA384"
97 # define DIGEST_STREAM sha384_stream
98 # define DIGEST_BITS 384
99 # define DIGEST_REFERENCE "FIPS-180-2"
100 # define DIGEST_ALIGN 8
101 #else
102 # error "Can't decide which hash algorithm to compile."
103 #endif
105 #if HASH_ALGO_BLAKE2
106 # define AUTHORS \
107 proper_name ("Padraig Brady"), \
108 proper_name ("Samuel Neves")
109 #else
110 # define AUTHORS \
111 proper_name ("Ulrich Drepper"), \
112 proper_name ("Scott Miller"), \
113 proper_name ("David Madore")
114 # define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
115 #endif
116 #define DIGEST_BIN_BYTES (DIGEST_BITS / 8)
119 /* The minimum length of a valid digest line. This length does
120 not include any newline character at the end of a line. */
121 #if HASH_ALGO_BLAKE2
122 # define MIN_DIGEST_LINE_LENGTH 3 /* With -l 8. */
123 #else
124 # define MIN_DIGEST_LINE_LENGTH \
125 (DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
126 + 1 /* blank */ \
127 + 1 /* minimum filename length */ )
128 #endif
130 /* True if any of the files read were the standard input. */
131 static bool have_read_stdin;
133 /* The minimum length of a valid checksum line for the selected algorithm. */
134 static size_t min_digest_line_length;
136 /* Set to the length of a digest hex string for the selected algorithm. */
137 static size_t digest_hex_bytes;
139 /* With --check, don't generate any output.
140 The exit code indicates success or failure. */
141 static bool status_only = false;
143 /* With --check, print a message to standard error warning about each
144 improperly formatted checksum line. */
145 static bool warn = false;
147 /* With --check, ignore missing files. */
148 static bool ignore_missing = false;
150 /* With --check, suppress the "OK" printed for each verified file. */
151 static bool quiet = false;
153 /* With --check, exit with a non-zero return code if any line is
154 improperly formatted. */
155 static bool strict = false;
157 /* Whether a BSD reversed format checksum is detected. */
158 static int bsd_reversed = -1;
160 #if HASH_ALGO_BLAKE2
161 static char const *const algorithm_in_string[] =
163 "blake2b", NULL
165 static char const *const algorithm_out_string[] =
167 "BLAKE2b", NULL
169 enum Algorithm
171 BLAKE2b
173 verify (ARRAY_CARDINALITY (algorithm_in_string) == 2);
174 verify (ARRAY_CARDINALITY (algorithm_out_string) == 2);
176 static enum Algorithm b2_algorithm;
177 static uintmax_t b2_length;
178 static blake2fn blake2fns[]=
180 blake2b_stream
182 static uintmax_t blake2_max_len[]=
184 BLAKE2B_OUTBYTES
186 #endif /* HASH_ALGO_BLAKE2 */
188 /* For long options that have no equivalent short option, use a
189 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
190 enum
192 IGNORE_MISSING_OPTION = CHAR_MAX + 1,
193 STATUS_OPTION,
194 QUIET_OPTION,
195 STRICT_OPTION,
196 TAG_OPTION
199 static struct option const long_options[] =
201 #if HASH_ALGO_BLAKE2
202 { "length", required_argument, NULL, 'l'},
203 #endif
204 { "binary", no_argument, NULL, 'b' },
205 { "check", no_argument, NULL, 'c' },
206 { "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION},
207 { "quiet", no_argument, NULL, QUIET_OPTION },
208 { "status", no_argument, NULL, STATUS_OPTION },
209 { "text", no_argument, NULL, 't' },
210 { "warn", no_argument, NULL, 'w' },
211 { "strict", no_argument, NULL, STRICT_OPTION },
212 { "tag", no_argument, NULL, TAG_OPTION },
213 { GETOPT_HELP_OPTION_DECL },
214 { GETOPT_VERSION_OPTION_DECL },
215 { NULL, 0, NULL, 0 }
218 void
219 usage (int status)
221 if (status != EXIT_SUCCESS)
222 emit_try_help ();
223 else
225 printf (_("\
226 Usage: %s [OPTION]... [FILE]...\n\
227 Print or check %s (%d-bit) checksums.\n\
229 program_name,
230 DIGEST_TYPE_STRING,
231 DIGEST_BITS);
233 emit_stdin_note ();
234 if (O_BINARY)
235 fputs (_("\
237 -b, --binary read in binary mode (default unless reading tty stdin)\n\
238 "), stdout);
239 else
240 fputs (_("\
242 -b, --binary read in binary mode\n\
243 "), stdout);
245 printf (_("\
246 -c, --check read %s sums from the FILEs and check them\n"),
247 DIGEST_TYPE_STRING);
248 #if HASH_ALGO_BLAKE2
249 fputs (_("\
250 -l, --length digest length in bits; must not exceed the maximum for\n\
251 the blake2 algorithm and must be a multiple of 8\n\
252 "), stdout);
253 #endif
254 fputs (_("\
255 --tag create a BSD-style checksum\n\
256 "), stdout);
257 if (O_BINARY)
258 fputs (_("\
259 -t, --text read in text mode (default if reading tty stdin)\n\
260 "), stdout);
261 else
262 fputs (_("\
263 -t, --text read in text mode (default)\n\
264 "), stdout);
265 fputs (_("\
267 The following five options are useful only when verifying checksums:\n\
268 --ignore-missing don't fail or report status for missing files\n\
269 --quiet don't print OK for each successfully verified file\n\
270 --status don't output anything, status code shows success\n\
271 --strict exit non-zero for improperly formatted checksum lines\n\
272 -w, --warn warn about improperly formatted checksum lines\n\
274 "), stdout);
275 fputs (HELP_OPTION_DESCRIPTION, stdout);
276 fputs (VERSION_OPTION_DESCRIPTION, stdout);
277 printf (_("\
279 The sums are computed as described in %s. When checking, the input\n\
280 should be a former output of this program. The default mode is to print a\n\
281 line with checksum, a space, a character indicating input mode ('*' for binary,\
282 \n' ' for text or where binary is insignificant), and name for each FILE.\n"),
283 DIGEST_REFERENCE);
284 emit_ancillary_info (PROGRAM_NAME);
287 exit (status);
290 #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
292 /* Given a file name, S of length S_LEN, that is not NUL-terminated,
293 modify it in place, performing the equivalent of this sed substitution:
294 's/\\n/\n/g;s/\\\\/\\/g' i.e., replacing each "\\n" string with a newline
295 and each "\\\\" with a single backslash, NUL-terminate it and return S.
296 If S is not a valid escaped file name, i.e., if it ends with an odd number
297 of backslashes or if it contains a backslash followed by anything other
298 than "n" or another backslash, return NULL. */
300 static char *
301 filename_unescape (char *s, size_t s_len)
303 char *dst = s;
305 for (size_t i = 0; i < s_len; i++)
307 switch (s[i])
309 case '\\':
310 if (i == s_len - 1)
312 /* File name ends with an unescaped backslash: invalid. */
313 return NULL;
315 ++i;
316 switch (s[i])
318 case 'n':
319 *dst++ = '\n';
320 break;
321 case '\\':
322 *dst++ = '\\';
323 break;
324 default:
325 /* Only '\' or 'n' may follow a backslash. */
326 return NULL;
328 break;
330 case '\0':
331 /* The file name may not contain a NUL. */
332 return NULL;
334 default:
335 *dst++ = s[i];
336 break;
339 if (dst < s + s_len)
340 *dst = '\0';
342 return s;
345 /* Return true if S is a NUL-terminated string of DIGEST_HEX_BYTES hex digits.
346 Otherwise, return false. */
347 static bool _GL_ATTRIBUTE_PURE
348 hex_digits (unsigned char const *s)
350 for (unsigned int i = 0; i < digest_hex_bytes; i++)
352 if (!isxdigit (*s))
353 return false;
354 ++s;
356 return *s == '\0';
359 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
360 'sha1' command into two parts: a hexadecimal digest, and the file
361 name. S is modified. Return true if successful. */
363 static bool
364 bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest,
365 char **file_name, bool escaped_filename)
367 size_t i;
369 if (s_len == 0)
370 return false;
372 /* Find end of filename. */
373 i = s_len - 1;
374 while (i && s[i] != ')')
375 i--;
377 if (s[i] != ')')
378 return false;
380 *file_name = s;
382 if (escaped_filename && filename_unescape (s, i) == NULL)
383 return false;
385 s[i++] = '\0';
387 while (ISWHITE (s[i]))
388 i++;
390 if (s[i] != '=')
391 return false;
393 i++;
395 while (ISWHITE (s[i]))
396 i++;
398 *hex_digest = (unsigned char *) &s[i];
400 return hex_digits (*hex_digest);
403 /* Split the string S (of length S_LEN) into three parts:
404 a hexadecimal digest, binary flag, and the file name.
405 S is modified. Return true if successful. */
407 static bool
408 split_3 (char *s, size_t s_len,
409 unsigned char **hex_digest, int *binary, char **file_name)
411 bool escaped_filename = false;
412 size_t algo_name_len;
414 size_t i = 0;
415 while (ISWHITE (s[i]))
416 ++i;
418 if (s[i] == '\\')
420 ++i;
421 escaped_filename = true;
424 /* Check for BSD-style checksum line. */
426 algo_name_len = strlen (DIGEST_TYPE_STRING);
427 if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
429 i += algo_name_len;
430 #if HASH_ALGO_BLAKE2
431 /* Terminate and match algorithm name. */
432 char const *algo_name = &s[i - algo_name_len];
433 /* Skip algorithm variants. */
434 while (s[i] && ! ISWHITE (s[i]) && s[i] != '-' && s[i] != '(')
435 ++i;
436 bool length_specified = s[i] == '-';
437 bool openssl_format = s[i] == '('; /* and no length_specified */
438 s[i++] = '\0';
439 ptrdiff_t algo = argmatch (algo_name, algorithm_out_string, NULL, 0);
440 if (algo < 0)
441 return false;
442 else
443 b2_algorithm = algo;
444 if (openssl_format)
445 s[--i] = '(';
447 if (length_specified)
449 unsigned long int tmp_ulong;
450 if (xstrtoul (s + i, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
451 && 0 < tmp_ulong && tmp_ulong <= blake2_max_len[b2_algorithm] * 8
452 && tmp_ulong % 8 == 0)
453 b2_length = tmp_ulong;
454 else
455 return false;
457 while (ISDIGIT (s[i]))
458 ++i;
460 else
461 b2_length = blake2_max_len[b2_algorithm] * 8;
463 digest_hex_bytes = b2_length / 4;
464 #endif
465 if (s[i] == ' ')
466 ++i;
467 if (s[i] == '(')
469 ++i;
470 *binary = 0;
471 return bsd_split_3 (s + i, s_len - i,
472 hex_digest, file_name, escaped_filename);
474 return false;
477 /* Ignore this line if it is too short.
478 Each line must have at least 'min_digest_line_length - 1' (or one more, if
479 the first is a backslash) more characters to contain correct message digest
480 information. */
481 if (s_len - i < min_digest_line_length + (s[i] == '\\'))
482 return false;
484 *hex_digest = (unsigned char *) &s[i];
486 #if HASH_ALGO_BLAKE2
487 /* Auto determine length. */
488 unsigned char const *hp = *hex_digest;
489 digest_hex_bytes = 0;
490 while (isxdigit (*hp++))
491 digest_hex_bytes++;
492 if (digest_hex_bytes < 2 || digest_hex_bytes % 2
493 || blake2_max_len[b2_algorithm] * 2 < digest_hex_bytes)
494 return false;
495 b2_length = digest_hex_bytes * 4;
496 #endif
498 /* The first field has to be the n-character hexadecimal
499 representation of the message digest. If it is not followed
500 immediately by a white space it's an error. */
501 i += digest_hex_bytes;
502 if (!ISWHITE (s[i]))
503 return false;
505 s[i++] = '\0';
507 if (! hex_digits (*hex_digest))
508 return false;
510 /* If "bsd reversed" format detected. */
511 if ((s_len - i == 1) || (s[i] != ' ' && s[i] != '*'))
513 /* Don't allow mixing bsd and standard formats,
514 to minimize security issues with attackers
515 renaming files with leading spaces.
516 This assumes that with bsd format checksums
517 that the first file name does not have
518 a leading ' ' or '*'. */
519 if (bsd_reversed == 0)
520 return false;
521 bsd_reversed = 1;
523 else if (bsd_reversed != 1)
525 bsd_reversed = 0;
526 *binary = (s[i++] == '*');
529 /* All characters between the type indicator and end of line are
530 significant -- that includes leading and trailing white space. */
531 *file_name = &s[i];
533 if (escaped_filename)
534 return filename_unescape (&s[i], s_len - i) != NULL;
536 return true;
539 /* If ESCAPE is true, then translate each NEWLINE byte to the string, "\\n",
540 and each backslash to "\\\\". */
541 static void
542 print_filename (char const *file, bool escape)
544 if (! escape)
546 fputs (file, stdout);
547 return;
550 while (*file)
552 switch (*file)
554 case '\n':
555 fputs ("\\n", stdout);
556 break;
558 case '\\':
559 fputs ("\\\\", stdout);
560 break;
562 default:
563 putchar (*file);
564 break;
566 file++;
570 /* An interface to the function, DIGEST_STREAM.
571 Operate on FILENAME (it may be "-").
573 *BINARY indicates whether the file is binary. BINARY < 0 means it
574 depends on whether binary mode makes any difference and the file is
575 a terminal; in that case, clear *BINARY if the file was treated as
576 text because it was a terminal.
578 Put the checksum in *BIN_RESULT, which must be properly aligned.
579 Put true in *MISSING if the file can't be opened due to ENOENT.
580 Return true if successful. */
582 static bool
583 digest_file (const char *filename, int *binary, unsigned char *bin_result,
584 bool *missing)
586 FILE *fp;
587 int err;
588 bool is_stdin = STREQ (filename, "-");
590 *missing = false;
592 if (is_stdin)
594 have_read_stdin = true;
595 fp = stdin;
596 if (O_BINARY && *binary)
598 if (*binary < 0)
599 *binary = ! isatty (STDIN_FILENO);
600 if (*binary)
601 xset_binary_mode (STDIN_FILENO, O_BINARY);
604 else
606 fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r"));
607 if (fp == NULL)
609 if (ignore_missing && errno == ENOENT)
611 *missing = true;
612 return true;
614 error (0, errno, "%s", quotef (filename));
615 return false;
619 fadvise (fp, FADVISE_SEQUENTIAL);
621 #if HASH_ALGO_BLAKE2
622 err = DIGEST_STREAM (fp, bin_result, b2_length / 8);
623 #else
624 err = DIGEST_STREAM (fp, bin_result);
625 #endif
626 if (err)
628 error (0, errno, "%s", quotef (filename));
629 if (fp != stdin)
630 fclose (fp);
631 return false;
634 if (!is_stdin && fclose (fp) != 0)
636 error (0, errno, "%s", quotef (filename));
637 return false;
640 return true;
643 static bool
644 digest_check (const char *checkfile_name)
646 FILE *checkfile_stream;
647 uintmax_t n_misformatted_lines = 0;
648 uintmax_t n_improperly_formatted_lines = 0;
649 uintmax_t n_mismatched_checksums = 0;
650 uintmax_t n_open_or_read_failures = 0;
651 bool properly_formatted_lines = false;
652 bool matched_checksums = false;
653 unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
654 /* Make sure bin_buffer is properly aligned. */
655 unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
656 uintmax_t line_number;
657 char *line;
658 size_t line_chars_allocated;
659 bool is_stdin = STREQ (checkfile_name, "-");
661 if (is_stdin)
663 have_read_stdin = true;
664 checkfile_name = _("standard input");
665 checkfile_stream = stdin;
667 else
669 checkfile_stream = fopen (checkfile_name, "r");
670 if (checkfile_stream == NULL)
672 error (0, errno, "%s", quotef (checkfile_name));
673 return false;
677 line_number = 0;
678 line = NULL;
679 line_chars_allocated = 0;
682 char *filename IF_LINT ( = NULL);
683 int binary;
684 unsigned char *hex_digest IF_LINT ( = NULL);
685 ssize_t line_length;
687 ++line_number;
688 if (line_number == 0)
689 die (EXIT_FAILURE, 0, _("%s: too many checksum lines"),
690 quotef (checkfile_name));
692 line_length = getline (&line, &line_chars_allocated, checkfile_stream);
693 if (line_length <= 0)
694 break;
696 /* Ignore comment lines, which begin with a '#' character. */
697 if (line[0] == '#')
698 continue;
700 /* Remove any trailing newline. */
701 if (line[line_length - 1] == '\n')
702 line[--line_length] = '\0';
704 if (! (split_3 (line, line_length, &hex_digest, &binary, &filename)
705 && ! (is_stdin && STREQ (filename, "-"))))
707 ++n_misformatted_lines;
709 if (warn)
711 error (0, 0,
712 _("%s: %" PRIuMAX
713 ": improperly formatted %s checksum line"),
714 quotef (checkfile_name), line_number,
715 DIGEST_TYPE_STRING);
718 ++n_improperly_formatted_lines;
720 else
722 static const char bin2hex[] = { '0', '1', '2', '3',
723 '4', '5', '6', '7',
724 '8', '9', 'a', 'b',
725 'c', 'd', 'e', 'f' };
726 bool ok;
727 bool missing;
728 /* Only escape in the edge case producing multiple lines,
729 to ease automatic processing of status output. */
730 bool needs_escape = ! status_only && strchr (filename, '\n');
732 properly_formatted_lines = true;
734 ok = digest_file (filename, &binary, bin_buffer, &missing);
736 if (!ok)
738 ++n_open_or_read_failures;
739 if (!status_only)
741 if (needs_escape)
742 putchar ('\\');
743 print_filename (filename, needs_escape);
744 printf (": %s\n", _("FAILED open or read"));
747 else if (ignore_missing && missing)
749 /* Ignore missing files with --ignore-missing. */
752 else
754 size_t digest_bin_bytes = digest_hex_bytes / 2;
755 size_t cnt;
757 /* Compare generated binary number with text representation
758 in check file. Ignore case of hex digits. */
759 for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
761 if (tolower (hex_digest[2 * cnt])
762 != bin2hex[bin_buffer[cnt] >> 4]
763 || (tolower (hex_digest[2 * cnt + 1])
764 != (bin2hex[bin_buffer[cnt] & 0xf])))
765 break;
767 if (cnt != digest_bin_bytes)
768 ++n_mismatched_checksums;
769 else
770 matched_checksums = true;
772 if (!status_only)
774 if (cnt != digest_bin_bytes || ! quiet)
776 if (needs_escape)
777 putchar ('\\');
778 print_filename (filename, needs_escape);
781 if (cnt != digest_bin_bytes)
782 printf (": %s\n", _("FAILED"));
783 else if (!quiet)
784 printf (": %s\n", _("OK"));
789 while (!feof (checkfile_stream) && !ferror (checkfile_stream));
791 free (line);
793 if (ferror (checkfile_stream))
795 error (0, 0, _("%s: read error"), quotef (checkfile_name));
796 return false;
799 if (!is_stdin && fclose (checkfile_stream) != 0)
801 error (0, errno, "%s", quotef (checkfile_name));
802 return false;
805 if (! properly_formatted_lines)
807 /* Warn if no tests are found. */
808 error (0, 0, _("%s: no properly formatted %s checksum lines found"),
809 quotef (checkfile_name), DIGEST_TYPE_STRING);
811 else
813 if (!status_only)
815 if (n_misformatted_lines != 0)
816 error (0, 0,
817 (ngettext
818 ("WARNING: %" PRIuMAX " line is improperly formatted",
819 "WARNING: %" PRIuMAX " lines are improperly formatted",
820 select_plural (n_misformatted_lines))),
821 n_misformatted_lines);
823 if (n_open_or_read_failures != 0)
824 error (0, 0,
825 (ngettext
826 ("WARNING: %" PRIuMAX " listed file could not be read",
827 "WARNING: %" PRIuMAX " listed files could not be read",
828 select_plural (n_open_or_read_failures))),
829 n_open_or_read_failures);
831 if (n_mismatched_checksums != 0)
832 error (0, 0,
833 (ngettext
834 ("WARNING: %" PRIuMAX " computed checksum did NOT match",
835 "WARNING: %" PRIuMAX " computed checksums did NOT match",
836 select_plural (n_mismatched_checksums))),
837 n_mismatched_checksums);
839 if (ignore_missing && ! matched_checksums)
840 error (0, 0, _("%s: no file was verified"),
841 quotef (checkfile_name));
845 return (properly_formatted_lines
846 && matched_checksums
847 && n_mismatched_checksums == 0
848 && n_open_or_read_failures == 0
849 && (!strict || n_improperly_formatted_lines == 0));
853 main (int argc, char **argv)
855 unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
856 /* Make sure bin_buffer is properly aligned. */
857 unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
858 bool do_check = false;
859 int opt;
860 bool ok = true;
861 int binary = -1;
862 bool prefix_tag = false;
864 /* Setting values of global variables. */
865 initialize_main (&argc, &argv);
866 set_program_name (argv[0]);
867 setlocale (LC_ALL, "");
868 bindtextdomain (PACKAGE, LOCALEDIR);
869 textdomain (PACKAGE);
871 atexit (close_stdout);
873 /* Line buffer stdout to ensure lines are written atomically and immediately
874 so that processes running in parallel do not intersperse their output. */
875 setvbuf (stdout, NULL, _IOLBF, 0);
877 #if HASH_ALGO_BLAKE2
878 const char* short_opts = "l:bctw";
879 const char* b2_length_str = "";
880 #else
881 const char* short_opts = "bctw";
882 #endif
884 while ((opt = getopt_long (argc, argv, short_opts, long_options, NULL)) != -1)
885 switch (opt)
887 #if HASH_ALGO_BLAKE2
888 case 'l':
889 b2_length = xdectoumax (optarg, 0, UINTMAX_MAX, "",
890 _("invalid length"), 0);
891 b2_length_str = optarg;
892 if (b2_length % 8 != 0)
894 error (0, 0, _("invalid length: %s"), quote (b2_length_str));
895 die (EXIT_FAILURE, 0, _("length is not a multiple of 8"));
897 break;
898 #endif
899 case 'b':
900 binary = 1;
901 break;
902 case 'c':
903 do_check = true;
904 break;
905 case STATUS_OPTION:
906 status_only = true;
907 warn = false;
908 quiet = false;
909 break;
910 case 't':
911 binary = 0;
912 break;
913 case 'w':
914 status_only = false;
915 warn = true;
916 quiet = false;
917 break;
918 case IGNORE_MISSING_OPTION:
919 ignore_missing = true;
920 break;
921 case QUIET_OPTION:
922 status_only = false;
923 warn = false;
924 quiet = true;
925 break;
926 case STRICT_OPTION:
927 strict = true;
928 break;
929 case TAG_OPTION:
930 prefix_tag = true;
931 binary = 1;
932 break;
933 case_GETOPT_HELP_CHAR;
934 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
935 default:
936 usage (EXIT_FAILURE);
939 min_digest_line_length = MIN_DIGEST_LINE_LENGTH;
940 #if HASH_ALGO_BLAKE2
941 if (b2_length > blake2_max_len[b2_algorithm] * 8)
943 error (0, 0, _("invalid length: %s"), quote (b2_length_str));
944 die (EXIT_FAILURE, 0,
945 _("maximum digest length for %s is %"PRIuMAX" bits"),
946 quote (algorithm_in_string[b2_algorithm]),
947 blake2_max_len[b2_algorithm] * 8);
949 if (b2_length == 0 && ! do_check)
950 b2_length = blake2_max_len[b2_algorithm] * 8;
951 digest_hex_bytes = b2_length / 4;
952 #else
953 digest_hex_bytes = DIGEST_HEX_BYTES;
954 #endif
956 if (prefix_tag && !binary)
958 /* This could be supported in a backwards compatible way
959 by prefixing the output line with a space in text mode.
960 However that's invasive enough that it was agreed to
961 not support this mode with --tag, as --text use cases
962 are adequately supported by the default output format. */
963 error (0, 0, _("--tag does not support --text mode"));
964 usage (EXIT_FAILURE);
967 if (prefix_tag && do_check)
969 error (0, 0, _("the --tag option is meaningless when "
970 "verifying checksums"));
971 usage (EXIT_FAILURE);
974 if (0 <= binary && do_check)
976 error (0, 0, _("the --binary and --text options are meaningless when "
977 "verifying checksums"));
978 usage (EXIT_FAILURE);
981 if (ignore_missing && !do_check)
983 error (0, 0,
984 _("the --ignore-missing option is meaningful only when "
985 "verifying checksums"));
986 usage (EXIT_FAILURE);
989 if (status_only && !do_check)
991 error (0, 0,
992 _("the --status option is meaningful only when verifying checksums"));
993 usage (EXIT_FAILURE);
996 if (warn && !do_check)
998 error (0, 0,
999 _("the --warn option is meaningful only when verifying checksums"));
1000 usage (EXIT_FAILURE);
1003 if (quiet && !do_check)
1005 error (0, 0,
1006 _("the --quiet option is meaningful only when verifying checksums"));
1007 usage (EXIT_FAILURE);
1010 if (strict & !do_check)
1012 error (0, 0,
1013 _("the --strict option is meaningful only when verifying checksums"));
1014 usage (EXIT_FAILURE);
1017 if (!O_BINARY && binary < 0)
1018 binary = 0;
1020 char **operand_lim = argv + argc;
1021 if (optind == argc)
1022 *operand_lim++ = bad_cast ("-");
1024 for (char **operandp = argv + optind; operandp < operand_lim; operandp++)
1026 char *file = *operandp;
1028 if (do_check)
1029 ok &= digest_check (file);
1030 else
1032 int file_is_binary = binary;
1033 bool missing;
1035 if (! digest_file (file, &file_is_binary, bin_buffer, &missing))
1036 ok = false;
1037 else
1039 /* We don't really need to escape, and hence detect, the '\\'
1040 char, and not doing so should be both forwards and backwards
1041 compatible, since only escaped lines would have a '\\' char at
1042 the start. However just in case users are directly comparing
1043 against old (hashed) outputs, in the presence of files
1044 containing '\\' characters, we decided to not simplify the
1045 output in this case. */
1046 bool needs_escape = strchr (file, '\\') || strchr (file, '\n');
1048 if (prefix_tag)
1050 if (needs_escape)
1051 putchar ('\\');
1053 #if HASH_ALGO_BLAKE2
1054 fputs (algorithm_out_string[b2_algorithm], stdout);
1055 if (b2_length < blake2_max_len[b2_algorithm] * 8)
1056 printf ("-%"PRIuMAX, b2_length);
1057 #else
1058 fputs (DIGEST_TYPE_STRING, stdout);
1059 #endif
1060 fputs (" (", stdout);
1061 print_filename (file, needs_escape);
1062 fputs (") = ", stdout);
1065 /* Output a leading backslash if the file name contains
1066 a newline or backslash. */
1067 if (!prefix_tag && needs_escape)
1068 putchar ('\\');
1070 for (size_t i = 0; i < (digest_hex_bytes / 2); ++i)
1071 printf ("%02x", bin_buffer[i]);
1073 if (!prefix_tag)
1075 putchar (' ');
1077 putchar (file_is_binary ? '*' : ' ');
1079 print_filename (file, needs_escape);
1082 putchar ('\n');
1087 if (have_read_stdin && fclose (stdin) == EOF)
1088 die (EXIT_FAILURE, errno, _("standard input"));
1090 return ok ? EXIT_SUCCESS : EXIT_FAILURE;