b2sum: a new checksum utility with md5sum like interface
[coreutils.git] / src / md5sum.c
blob8e21609677182f3e31ff0296bc1206f56f362e8b
1 /* Compute checksums of files or strings.
2 Copyright (C) 1995-2016 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 <http://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 "xfreopen.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 static enum Algorithm const algorithm[] =
175 BLAKE2b
177 ARGMATCH_VERIFY (algorithm_in_string, algorithm);
178 ARGMATCH_VERIFY (algorithm_out_string, algorithm);
180 static enum Algorithm b2_algorithm;
181 static uintmax_t b2_length;
182 static blake2fn blake2fns[]=
184 blake2b_stream
186 static uintmax_t blake2_max_len[]=
188 BLAKE2B_OUTBYTES
190 #endif /* HASH_ALGO_BLAKE2 */
192 /* For long options that have no equivalent short option, use a
193 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
194 enum
196 IGNORE_MISSING_OPTION = CHAR_MAX + 1,
197 STATUS_OPTION,
198 QUIET_OPTION,
199 STRICT_OPTION,
200 TAG_OPTION
203 static struct option const long_options[] =
205 #if HASH_ALGO_BLAKE2
206 { "length", required_argument, NULL, 'l'},
207 #endif
208 { "binary", no_argument, NULL, 'b' },
209 { "check", no_argument, NULL, 'c' },
210 { "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION},
211 { "quiet", no_argument, NULL, QUIET_OPTION },
212 { "status", no_argument, NULL, STATUS_OPTION },
213 { "text", no_argument, NULL, 't' },
214 { "warn", no_argument, NULL, 'w' },
215 { "strict", no_argument, NULL, STRICT_OPTION },
216 { "tag", no_argument, NULL, TAG_OPTION },
217 { GETOPT_HELP_OPTION_DECL },
218 { GETOPT_VERSION_OPTION_DECL },
219 { NULL, 0, NULL, 0 }
222 void
223 usage (int status)
225 if (status != EXIT_SUCCESS)
226 emit_try_help ();
227 else
229 printf (_("\
230 Usage: %s [OPTION]... [FILE]...\n\
231 Print or check %s (%d-bit) checksums.\n\
233 program_name,
234 DIGEST_TYPE_STRING,
235 DIGEST_BITS);
237 emit_stdin_note ();
238 if (O_BINARY)
239 fputs (_("\
241 -b, --binary read in binary mode (default unless reading tty stdin)\n\
242 "), stdout);
243 else
244 fputs (_("\
246 -b, --binary read in binary mode\n\
247 "), stdout);
249 printf (_("\
250 -c, --check read %s sums from the FILEs and check them\n"),
251 DIGEST_TYPE_STRING);
252 #if HASH_ALGO_BLAKE2
253 fputs (_("\
254 -l, --length digest length in bits; must not exceed the maximum for\n\
255 the blake2 algorithm and must be a multiple of 8\n\
256 "), stdout);
257 #endif
258 fputs (_("\
259 --tag create a BSD-style checksum\n\
260 "), stdout);
261 if (O_BINARY)
262 fputs (_("\
263 -t, --text read in text mode (default if reading tty stdin)\n\
264 "), stdout);
265 else
266 fputs (_("\
267 -t, --text read in text mode (default)\n\
268 "), stdout);
269 fputs (_("\
271 The following five options are useful only when verifying checksums:\n\
272 --ignore-missing don't fail or report status for missing files\n\
273 --quiet don't print OK for each successfully verified file\n\
274 --status don't output anything, status code shows success\n\
275 --strict exit non-zero for improperly formatted checksum lines\n\
276 -w, --warn warn about improperly formatted checksum lines\n\
278 "), stdout);
279 fputs (HELP_OPTION_DESCRIPTION, stdout);
280 fputs (VERSION_OPTION_DESCRIPTION, stdout);
281 printf (_("\
283 The sums are computed as described in %s. When checking, the input\n\
284 should be a former output of this program. The default mode is to print a\n\
285 line with checksum, a space, a character indicating input mode ('*' for binary,\
286 \n' ' for text or where binary is insignificant), and name for each FILE.\n"),
287 DIGEST_REFERENCE);
288 emit_ancillary_info (PROGRAM_NAME);
291 exit (status);
294 #define ISWHITE(c) ((c) == ' ' || (c) == '\t')
296 /* Given a file name, S of length S_LEN, that is not NUL-terminated,
297 modify it in place, performing the equivalent of this sed substitution:
298 's/\\n/\n/g;s/\\\\/\\/g' i.e., replacing each "\\n" string with a newline
299 and each "\\\\" with a single backslash, NUL-terminate it and return S.
300 If S is not a valid escaped file name, i.e., if it ends with an odd number
301 of backslashes or if it contains a backslash followed by anything other
302 than "n" or another backslash, return NULL. */
304 static char *
305 filename_unescape (char *s, size_t s_len)
307 char *dst = s;
309 for (size_t i = 0; i < s_len; i++)
311 switch (s[i])
313 case '\\':
314 if (i == s_len - 1)
316 /* File name ends with an unescaped backslash: invalid. */
317 return NULL;
319 ++i;
320 switch (s[i])
322 case 'n':
323 *dst++ = '\n';
324 break;
325 case '\\':
326 *dst++ = '\\';
327 break;
328 default:
329 /* Only '\' or 'n' may follow a backslash. */
330 return NULL;
332 break;
334 case '\0':
335 /* The file name may not contain a NUL. */
336 return NULL;
338 default:
339 *dst++ = s[i];
340 break;
343 if (dst < s + s_len)
344 *dst = '\0';
346 return s;
349 /* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
350 'sha1' command into two parts: a hexadecimal digest, and the file
351 name. S is modified. Return true if successful. */
353 static bool
354 bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest,
355 char **file_name, bool escaped_filename)
357 size_t i;
359 if (s_len == 0)
360 return false;
362 /* Find end of filename. */
363 i = s_len - 1;
364 while (i && s[i] != ')')
365 i--;
367 if (s[i] != ')')
368 return false;
370 *file_name = s;
372 if (escaped_filename && filename_unescape (s, i) == NULL)
373 return false;
375 s[i++] = '\0';
377 while (ISWHITE (s[i]))
378 i++;
380 if (s[i] != '=')
381 return false;
383 i++;
385 while (ISWHITE (s[i]))
386 i++;
388 *hex_digest = (unsigned char *) &s[i];
389 return true;
392 /* Split the string S (of length S_LEN) into three parts:
393 a hexadecimal digest, binary flag, and the file name.
394 S is modified. Return true if successful. */
396 static bool
397 split_3 (char *s, size_t s_len,
398 unsigned char **hex_digest, int *binary, char **file_name)
400 bool escaped_filename = false;
401 size_t algo_name_len;
403 size_t i = 0;
404 while (ISWHITE (s[i]))
405 ++i;
407 if (s[i] == '\\')
409 ++i;
410 escaped_filename = true;
413 /* Check for BSD-style checksum line. */
415 algo_name_len = strlen (DIGEST_TYPE_STRING);
416 if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
418 i += algo_name_len;
419 #if HASH_ALGO_BLAKE2
420 /* Terminate and match algorithm name. */
421 char const *algo_name = &s[i - algo_name_len];
422 while (! ISWHITE (s[i]) && s[i] != '-' && s[i] != '(')
423 ++i;
424 bool length_specified = s[i] == '-';
425 bool openssl_format = s[i] == '('; /* and no length_specified */
426 s[i++] = '\0';
427 ptrdiff_t algo = argmatch (algo_name, algorithm_out_string, NULL, 0);
428 if (algo < 0)
429 return false;
430 else
431 b2_algorithm = algo;
432 if (openssl_format)
433 s[--i] = '(';
435 if (length_specified)
437 unsigned long int tmp_ulong;
438 if (xstrtoul (s + i, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
439 && 0 < tmp_ulong && tmp_ulong <= blake2_max_len[b2_algorithm] * 8
440 && tmp_ulong % 8 == 0)
441 b2_length = tmp_ulong;
442 else
443 return false;
445 while (ISDIGIT (s[i]))
446 ++i;
448 else
449 b2_length = blake2_max_len[b2_algorithm] * 8;
451 digest_hex_bytes = b2_length / 4;
452 #endif
453 if (s[i] == ' ')
454 ++i;
455 if (s[i] == '(')
457 ++i;
458 *binary = 0;
459 return bsd_split_3 (s + i, s_len - i,
460 hex_digest, file_name, escaped_filename);
462 return false;
465 /* Ignore this line if it is too short.
466 Each line must have at least 'min_digest_line_length - 1' (or one more, if
467 the first is a backslash) more characters to contain correct message digest
468 information. */
469 if (s_len - i < min_digest_line_length + (s[i] == '\\'))
470 return false;
472 *hex_digest = (unsigned char *) &s[i];
474 #if HASH_ALGO_BLAKE2
475 /* Auto determine length. */
476 unsigned char const *hp = *hex_digest;
477 digest_hex_bytes = 0;
478 while (isxdigit (*hp++))
479 digest_hex_bytes++;
480 if (digest_hex_bytes < 2 || digest_hex_bytes % 2
481 || blake2_max_len[b2_algorithm] * 2 < digest_hex_bytes)
482 return false;
483 b2_length = digest_hex_bytes * 4;
484 #endif
486 /* The first field has to be the n-character hexadecimal
487 representation of the message digest. If it is not followed
488 immediately by a white space it's an error. */
489 i += digest_hex_bytes;
490 if (!ISWHITE (s[i]))
491 return false;
493 s[i++] = '\0';
495 /* If "bsd reversed" format detected. */
496 if ((s_len - i == 1) || (s[i] != ' ' && s[i] != '*'))
498 /* Don't allow mixing bsd and standard formats,
499 to minimize security issues with attackers
500 renaming files with leading spaces.
501 This assumes that with bsd format checksums
502 that the first file name does not have
503 a leading ' ' or '*'. */
504 if (bsd_reversed == 0)
505 return false;
506 bsd_reversed = 1;
508 else if (bsd_reversed != 1)
510 bsd_reversed = 0;
511 *binary = (s[i++] == '*');
514 /* All characters between the type indicator and end of line are
515 significant -- that includes leading and trailing white space. */
516 *file_name = &s[i];
518 if (escaped_filename)
519 return filename_unescape (&s[i], s_len - i) != NULL;
521 return true;
524 /* Return true if S is a NUL-terminated string of DIGEST_HEX_BYTES hex digits.
525 Otherwise, return false. */
526 static bool _GL_ATTRIBUTE_PURE
527 hex_digits (unsigned char const *s)
529 unsigned int i;
530 for (i = 0; i < digest_hex_bytes; i++)
532 if (!isxdigit (*s))
533 return false;
534 ++s;
536 return *s == '\0';
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 xfreopen (NULL, "rb", stdin);
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, "-"))
706 && hex_digits (hex_digest)))
708 ++n_misformatted_lines;
710 if (warn)
712 error (0, 0,
713 _("%s: %" PRIuMAX
714 ": improperly formatted %s checksum line"),
715 quotef (checkfile_name), line_number,
716 DIGEST_TYPE_STRING);
719 ++n_improperly_formatted_lines;
721 else
723 static const char bin2hex[] = { '0', '1', '2', '3',
724 '4', '5', '6', '7',
725 '8', '9', 'a', 'b',
726 'c', 'd', 'e', 'f' };
727 bool ok;
728 bool missing;
729 /* Only escape in the edge case producing multiple lines,
730 to ease automatic processing of status output. */
731 bool needs_escape = ! status_only && strchr (filename, '\n');
733 properly_formatted_lines = true;
735 ok = digest_file (filename, &binary, bin_buffer, &missing);
737 if (!ok)
739 ++n_open_or_read_failures;
740 if (!status_only)
742 if (needs_escape)
743 putchar ('\\');
744 print_filename (filename, needs_escape);
745 printf (": %s\n", _("FAILED open or read"));
748 else if (ignore_missing && missing)
750 /* Ignore missing files with --ignore-missing. */
753 else
755 size_t digest_bin_bytes = digest_hex_bytes / 2;
756 size_t cnt;
758 /* Compare generated binary number with text representation
759 in check file. Ignore case of hex digits. */
760 for (cnt = 0; cnt < digest_bin_bytes; ++cnt)
762 if (tolower (hex_digest[2 * cnt])
763 != bin2hex[bin_buffer[cnt] >> 4]
764 || (tolower (hex_digest[2 * cnt + 1])
765 != (bin2hex[bin_buffer[cnt] & 0xf])))
766 break;
768 if (cnt != digest_bin_bytes)
769 ++n_mismatched_checksums;
770 else
771 matched_checksums = true;
773 if (!status_only)
775 if (cnt != digest_bin_bytes || ! quiet)
777 if (needs_escape)
778 putchar ('\\');
779 print_filename (filename, needs_escape);
782 if (cnt != digest_bin_bytes)
783 printf (": %s\n", _("FAILED"));
784 else if (!quiet)
785 printf (": %s\n", _("OK"));
790 while (!feof (checkfile_stream) && !ferror (checkfile_stream));
792 free (line);
794 if (ferror (checkfile_stream))
796 error (0, 0, _("%s: read error"), quotef (checkfile_name));
797 return false;
800 if (!is_stdin && fclose (checkfile_stream) != 0)
802 error (0, errno, "%s", quotef (checkfile_name));
803 return false;
806 if (! properly_formatted_lines)
808 /* Warn if no tests are found. */
809 error (0, 0, _("%s: no properly formatted %s checksum lines found"),
810 quotef (checkfile_name), DIGEST_TYPE_STRING);
812 else
814 if (!status_only)
816 if (n_misformatted_lines != 0)
817 error (0, 0,
818 (ngettext
819 ("WARNING: %" PRIuMAX " line is improperly formatted",
820 "WARNING: %" PRIuMAX " lines are improperly formatted",
821 select_plural (n_misformatted_lines))),
822 n_misformatted_lines);
824 if (n_open_or_read_failures != 0)
825 error (0, 0,
826 (ngettext
827 ("WARNING: %" PRIuMAX " listed file could not be read",
828 "WARNING: %" PRIuMAX " listed files could not be read",
829 select_plural (n_open_or_read_failures))),
830 n_open_or_read_failures);
832 if (n_mismatched_checksums != 0)
833 error (0, 0,
834 (ngettext
835 ("WARNING: %" PRIuMAX " computed checksum did NOT match",
836 "WARNING: %" PRIuMAX " computed checksums did NOT match",
837 select_plural (n_mismatched_checksums))),
838 n_mismatched_checksums);
840 if (ignore_missing && ! matched_checksums)
841 error (0, 0, _("%s: no file was verified"),
842 quotef (checkfile_name));
846 return (properly_formatted_lines
847 && matched_checksums
848 && n_mismatched_checksums == 0
849 && n_open_or_read_failures == 0
850 && (!strict || n_improperly_formatted_lines == 0));
854 main (int argc, char **argv)
856 unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN];
857 /* Make sure bin_buffer is properly aligned. */
858 unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN);
859 bool do_check = false;
860 int opt;
861 bool ok = true;
862 int binary = -1;
863 bool prefix_tag = false;
865 /* Setting values of global variables. */
866 initialize_main (&argc, &argv);
867 set_program_name (argv[0]);
868 setlocale (LC_ALL, "");
869 bindtextdomain (PACKAGE, LOCALEDIR);
870 textdomain (PACKAGE);
872 atexit (close_stdout);
874 /* Line buffer stdout to ensure lines are written atomically and immediately
875 so that processes running in parallel do not intersperse their output. */
876 setvbuf (stdout, NULL, _IOLBF, 0);
878 #if HASH_ALGO_BLAKE2
879 const char* short_opts = "l:bctw";
880 const char* b2_length_str = "";
881 #else
882 const char* short_opts = "bctw";
883 #endif
885 while ((opt = getopt_long (argc, argv, short_opts, long_options, NULL)) != -1)
886 switch (opt)
888 #if HASH_ALGO_BLAKE2
889 case 'l':
890 b2_length = xdectoumax (optarg, 0, UINTMAX_MAX, "",
891 _("invalid length"), 0);
892 b2_length_str = optarg;
893 if (b2_length % 8 != 0)
895 error (0, 0, _("invalid length: %s"), quote (b2_length_str));
896 die (EXIT_FAILURE, 0, _("length is not a multiple of 8"));
898 break;
899 #endif
900 case 'b':
901 binary = 1;
902 break;
903 case 'c':
904 do_check = true;
905 break;
906 case STATUS_OPTION:
907 status_only = true;
908 warn = false;
909 quiet = false;
910 break;
911 case 't':
912 binary = 0;
913 break;
914 case 'w':
915 status_only = false;
916 warn = true;
917 quiet = false;
918 break;
919 case IGNORE_MISSING_OPTION:
920 ignore_missing = true;
921 break;
922 case QUIET_OPTION:
923 status_only = false;
924 warn = false;
925 quiet = true;
926 break;
927 case STRICT_OPTION:
928 strict = true;
929 break;
930 case TAG_OPTION:
931 prefix_tag = true;
932 binary = 1;
933 break;
934 case_GETOPT_HELP_CHAR;
935 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
936 default:
937 usage (EXIT_FAILURE);
940 min_digest_line_length = MIN_DIGEST_LINE_LENGTH;
941 #if HASH_ALGO_BLAKE2
942 if (b2_length > blake2_max_len[b2_algorithm] * 8)
944 error (0, 0, _("invalid length: %s"), quote (b2_length_str));
945 die (EXIT_FAILURE, 0,
946 _("maximum digest length for %s is %"PRIuMAX" bits"),
947 quote (algorithm_in_string[b2_algorithm]),
948 blake2_max_len[b2_algorithm] * 8);
950 if (b2_length == 0 && ! do_check)
951 b2_length = blake2_max_len[b2_algorithm] * 8;
952 digest_hex_bytes = b2_length / 4;
953 #else
954 digest_hex_bytes = DIGEST_HEX_BYTES;
955 #endif
957 if (prefix_tag && !binary)
959 /* This could be supported in a backwards compatible way
960 by prefixing the output line with a space in text mode.
961 However that's invasive enough that it was agreed to
962 not support this mode with --tag, as --text use cases
963 are adequately supported by the default output format. */
964 error (0, 0, _("--tag does not support --text mode"));
965 usage (EXIT_FAILURE);
968 if (prefix_tag && do_check)
970 error (0, 0, _("the --tag option is meaningless when "
971 "verifying checksums"));
972 usage (EXIT_FAILURE);
975 if (0 <= binary && do_check)
977 error (0, 0, _("the --binary and --text options are meaningless when "
978 "verifying checksums"));
979 usage (EXIT_FAILURE);
982 if (ignore_missing && !do_check)
984 error (0, 0,
985 _("the --ignore-missing option is meaningful only when "
986 "verifying checksums"));
987 usage (EXIT_FAILURE);
990 if (status_only && !do_check)
992 error (0, 0,
993 _("the --status option is meaningful only when verifying checksums"));
994 usage (EXIT_FAILURE);
997 if (warn && !do_check)
999 error (0, 0,
1000 _("the --warn option is meaningful only when verifying checksums"));
1001 usage (EXIT_FAILURE);
1004 if (quiet && !do_check)
1006 error (0, 0,
1007 _("the --quiet option is meaningful only when verifying checksums"));
1008 usage (EXIT_FAILURE);
1011 if (strict & !do_check)
1013 error (0, 0,
1014 _("the --strict option is meaningful only when verifying checksums"));
1015 usage (EXIT_FAILURE);
1018 if (!O_BINARY && binary < 0)
1019 binary = 0;
1021 char **operand_lim = argv + argc;
1022 if (optind == argc)
1023 *operand_lim++ = bad_cast ("-");
1025 for (char **operandp = argv + optind; operandp < operand_lim; operandp++)
1027 char *file = *operandp;
1029 if (do_check)
1030 ok &= digest_check (file);
1031 else
1033 int file_is_binary = binary;
1034 bool missing;
1036 if (! digest_file (file, &file_is_binary, bin_buffer, &missing))
1037 ok = false;
1038 else
1040 /* We don't really need to escape, and hence detect, the '\\'
1041 char, and not doing so should be both forwards and backwards
1042 compatible, since only escaped lines would have a '\\' char at
1043 the start. However just in case users are directly comparing
1044 against old (hashed) outputs, in the presence of files
1045 containing '\\' characters, we decided to not simplify the
1046 output in this case. */
1047 bool needs_escape = strchr (file, '\\') || strchr (file, '\n');
1049 if (prefix_tag)
1051 if (needs_escape)
1052 putchar ('\\');
1054 #if HASH_ALGO_BLAKE2
1055 fputs (algorithm_out_string[b2_algorithm], stdout);
1056 if (b2_length < blake2_max_len[b2_algorithm] * 8)
1057 printf ("-%"PRIuMAX, b2_length);
1058 #else
1059 fputs (DIGEST_TYPE_STRING, stdout);
1060 #endif
1061 fputs (" (", stdout);
1062 print_filename (file, needs_escape);
1063 fputs (") = ", stdout);
1066 size_t i;
1068 /* Output a leading backslash if the file name contains
1069 a newline or backslash. */
1070 if (!prefix_tag && needs_escape)
1071 putchar ('\\');
1073 for (i = 0; i < (digest_hex_bytes / 2); ++i)
1074 printf ("%02x", bin_buffer[i]);
1076 if (!prefix_tag)
1078 putchar (' ');
1080 putchar (file_is_binary ? '*' : ' ');
1082 print_filename (file, needs_escape);
1085 putchar ('\n');
1090 if (have_read_stdin && fclose (stdin) == EOF)
1091 die (EXIT_FAILURE, errno, _("standard input"));
1093 return ok ? EXIT_SUCCESS : EXIT_FAILURE;