/* Compute checksums of files or strings. This is the md5sum utility
Copyright (C) 1995-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */
#include <config.h> Provides system specific information
#include <getopt.h> ...!includes auto-comment...
#include <sys/types.h> Provides system data types
#include "system.h" ...!includes auto-comment...
#include "argmatch.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "xdectoint.h" ...!includes auto-comment...
#include "xstrtol.h" ...!includes auto-comment...
#if HASH_ALGO_BLAKE2 Line 30
# include "blake2/b2sum.h" Line 31
#endif Line 32
#if HASH_ALGO_MD5 Line 33
# include "md5.h" ...!includes auto-comment...
#endif Line 35
#if HASH_ALGO_SHA1 Line 36
# include "sha1.h" Line 37
#endif Line 38
#if HASH_ALGO_SHA256 || HASH_ALGO_SHA224 Line 39
# include "sha256.h" Line 40
#endif Line 41
#if HASH_ALGO_SHA512 || HASH_ALGO_SHA384 Line 42
# include "sha512.h" Line 43
#endif Line 44
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "fadvise.h" ...!includes auto-comment...
#include "stdio--.h" ...!includes auto-comment...
#include "xbinary-io.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#if HASH_ALGO_MD5 Line 52
# define PROGRAM_NAME "md5sum" Line 53
# define DIGEST_TYPE_STRING "MD5" Line 54
# define DIGEST_STREAM md5_stream Line 55
# define DIGEST_BITS 128 Line 56
# define DIGEST_REFERENCE "RFC 1321" Line 57
# define DIGEST_ALIGN 4 Line 58
#elif HASH_ALGO_BLAKE2 Line 59
# define PROGRAM_NAME "b2sum" Line 60
# define DIGEST_TYPE_STRING "BLAKE2" Line 61
# define DIGEST_STREAM blake2fns[b2_algorithm] Line 62
# define DIGEST_BITS 512 Line 63
# define DIGEST_REFERENCE "RFC 7693" Line 64
# define DIGEST_ALIGN 8 Line 65
#elif HASH_ALGO_SHA1 Line 66
# define PROGRAM_NAME "sha1sum" Line 67
# define DIGEST_TYPE_STRING "SHA1" Line 68
# define DIGEST_STREAM sha1_stream Line 69
# define DIGEST_BITS 160 Line 70
# define DIGEST_REFERENCE "FIPS-180-1" Line 71
# define DIGEST_ALIGN 4 Line 72
#elif HASH_ALGO_SHA256 Line 73
# define PROGRAM_NAME "sha256sum" Line 74
# define DIGEST_TYPE_STRING "SHA256" Line 75
# define DIGEST_STREAM sha256_stream Line 76
# define DIGEST_BITS 256 Line 77
# define DIGEST_REFERENCE "FIPS-180-2" Line 78
# define DIGEST_ALIGN 4 Line 79
#elif HASH_ALGO_SHA224 Line 80
# define PROGRAM_NAME "sha224sum" Line 81
# define DIGEST_TYPE_STRING "SHA224" Line 82
# define DIGEST_STREAM sha224_stream Line 83
# define DIGEST_BITS 224 Line 84
# define DIGEST_REFERENCE "RFC 3874" Line 85
# define DIGEST_ALIGN 4 Line 86
#elif HASH_ALGO_SHA512 Line 87
# define PROGRAM_NAME "sha512sum" Line 88
# define DIGEST_TYPE_STRING "SHA512" Line 89
# define DIGEST_STREAM sha512_stream Line 90
# define DIGEST_BITS 512 Line 91
# define DIGEST_REFERENCE "FIPS-180-2" Line 92
# define DIGEST_ALIGN 8 Line 93
#elif HASH_ALGO_SHA384 Line 94
# define PROGRAM_NAME "sha384sum" Line 95
# define DIGEST_TYPE_STRING "SHA384" Line 96
# define DIGEST_STREAM sha384_stream Line 97
# define DIGEST_BITS 384 Line 98
# define DIGEST_REFERENCE "FIPS-180-2" Line 99
# define DIGEST_ALIGN 8 Line 100
#else Line 101
# error "Can't decide which hash algorithm to compile." Line 102
#endif Line 103
#if HASH_ALGO_BLAKE2 Line 105
# define AUTHORS \ Line 106
proper_name ("Padraig Brady"), \ Line 107
proper_name ("Samuel Neves") Line 108
#else Line 109
# define AUTHORS \ Line 110
proper_name ("Ulrich Drepper"), \ Line 111
proper_name ("Scott Miller"), \ Line 112
proper_name ("David Madore") Line 113
# define DIGEST_HEX_BYTES (DIGEST_BITS / 4) Line 114
#endif Line 115
#define DIGEST_BIN_BYTES (DIGEST_BITS / 8) Line 116
/* The minimum length of a valid digest line. This length does
not include any newline character at the end of a line. */
#if HASH_ALGO_BLAKE2 Line 121
# define MIN_DIGEST_LINE_LENGTH 3 /* With -l 8. */ Line 122
#else Line 123
# define MIN_DIGEST_LINE_LENGTH \ Line 124
(DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \ Line 125
+ 1 /* blank */ \ Line 126
+ 1 /* minimum filename length */ ) Line 127
#endif Line 128
/* True if any of the files read were the standard input. */
static bool have_read_stdin; Line 131
/* The minimum length of a valid checksum line for the selected algorithm. */
static size_t min_digest_line_length; Line 134
/* Set to the length of a digest hex string for the selected algorithm. */
static size_t digest_hex_bytes; Line 137
/* With --check, don't generate any output.
The exit code indicates success or failure. */
static bool status_only = false; Line 141
/* With --check, print a message to standard error warning about each
improperly formatted checksum line. */
static bool warn = false; Line 145
/* With --check, ignore missing files. */
static bool ignore_missing = false; Line 148
/* With --check, suppress the "OK" printed for each verified file. */
static bool quiet = false; Line 151
/* With --check, exit with a non-zero return code if any line is
improperly formatted. */
static bool strict = false; Line 155
/* Whether a BSD reversed format checksum is detected. */
static int bsd_reversed = -1; Line 158
/* line delimiter. */
static unsigned char delim = '\n'; Line 161
#if HASH_ALGO_BLAKE2 Line 163
static char const *const algorithm_in_string[] = Line 164
{
"blake2b", NULL Line 166
}; Block 1
static char const *const algorithm_out_string[] = Line 168
{
"BLAKE2b", NULL Line 170
}; Block 2
enum Algorithm Line 172
{
BLAKE2b Line 174
}; Block 3
verify (ARRAY_CARDINALITY (algorithm_in_string) == 2); Line 176
verify (ARRAY_CARDINALITY (algorithm_out_string) == 2); Line 177
static enum Algorithm b2_algorithm; Line 179
static uintmax_t b2_length; Line 180
static blake2fn blake2fns[]= Line 181
{
blake2b_stream Line 183
}; Block 4
static uintmax_t blake2_max_len[]= Line 185
{
BLAKE2B_OUTBYTES Line 187
}; Block 5
#endif /* HASH_ALGO_BLAKE2 */ Line 189
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum Line 193
{
IGNORE_MISSING_OPTION = CHAR_MAX + 1, Line 195
STATUS_OPTION, Line 196
QUIET_OPTION, Line 197
STRICT_OPTION, Line 198
TAG_OPTION Line 199
}; Block 6
static struct option const long_options[] = Line 202
{
#if HASH_ALGO_BLAKE2 Line 204
{ "length", required_argument, NULL, 'l'}, Line 205
#endif Line 206
{ "binary", no_argument, NULL, 'b' }, Line 207
{ "check", no_argument, NULL, 'c' }, Line 208
{ "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION}, Line 209
{ "quiet", no_argument, NULL, QUIET_OPTION }, Line 210
{ "status", no_argument, NULL, STATUS_OPTION }, Line 211
{ "text", no_argument, NULL, 't' }, Line 212
{ "warn", no_argument, NULL, 'w' }, Line 213
{ "strict", no_argument, NULL, STRICT_OPTION }, Line 214
{ "tag", no_argument, NULL, TAG_OPTION }, Line 215
{ "zero", no_argument, NULL, 'z' }, Line 216
{ GETOPT_HELP_OPTION_DECL }, Line 217
{ GETOPT_VERSION_OPTION_DECL }, Line 218
{ NULL, 0, NULL, 0 } Line 219
}; Block 7
void Line 222
usage (int status) Line 223
{
if (status != EXIT_SUCCESS) Line 225
emit_try_help (); ...!common auto-comment...
else Line 227
{
printf (_("\ Line 229
Usage: %s [OPTION]... [FILE]...\n\ Line 230
Print or check %s (%d-bit) checksums.\n\ Line 231
"), Line 232
program_name, Line 233
DIGEST_TYPE_STRING, Line 234
DIGEST_BITS); Line 235
emit_stdin_note (); ...!common auto-comment...
if (O_BINARY) Line 238
fputs (_("\ Line 239
\n\
-b, --binary read in binary mode (default unless reading tty stdin)\n\Line 241
"), stdout); Line 242
else Line 243
fputs (_("\ Line 244
\n\
-b, --binary read in binary mode\n\ Line 246
"), stdout); Line 247
printf (_("\ Line 249
-c, --check read %s sums from the FILEs and check them\n"), Line 250
DIGEST_TYPE_STRING); Line 251
#if HASH_ALGO_BLAKE2 Line 252
fputs (_("\ Line 253
-l, --length digest length in bits; must not exceed the maximum for\n\Line 254
the blake2 algorithm and must be a multiple of 8\n\ Line 255
"), stdout); Line 256
#endif Line 257
fputs (_("\ Line 258
--tag create a BSD-style checksum\n\ Line 259
"), stdout); Line 260
if (O_BINARY) Line 261
fputs (_("\ Line 262
-t, --text read in text mode (default if reading tty stdin)\n\ Line 263
"), stdout); Line 264
else Line 265
fputs (_("\ Line 266
-t, --text read in text mode (default)\n\ Line 267
"), stdout); Line 268
fputs (_("\ Line 269
-z, --zero end each output line with NUL, not newline,\n\ Line 270
and disable file name escaping\n\ Line 271
"), stdout); Line 272
fputs (_("\ Line 273
\n\
The following five options are useful only when verifying checksums:\n\ Line 275
--ignore-missing don't fail or report status for missing files\n\ Line 276
--quiet don't print OK for each successfully verified file\n\ Line 277
--status don't output anything, status code shows success\n\ Line 278
--strict exit non-zero for improperly formatted checksum lines\n\ Line 279
-w, --warn warn about improperly formatted checksum lines\n\ Line 280
\n\
"), stdout); Line 282
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 283
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 284
printf (_("\ Line 285
\n\
The sums are computed as described in %s. When checking, the input\n\ Line 287
should be a former output of this program. The default mode is to print a\n\ Line 288
line with checksum, a space, a character indicating input mode ('*' for binary,\Line 289
\n' ' for text or where binary is insignificant), and name for each FILE.\n"), Line 290
DIGEST_REFERENCE); Line 291
emit_ancillary_info (PROGRAM_NAME); Line 292
}
exit (status); Line 295
} Block 8
#define ISWHITE(c) ((c) == ' ' || (c) == '\t') Line 298
/* Given a file name, S of length S_LEN, that is not NUL-terminated,
modify it in place, performing the equivalent of this sed substitution:
's/\\n/\n/g;s/\\\\/\\/g' i.e., replacing each "\\n" string with a newline
and each "\\\\" with a single backslash, NUL-terminate it and return S.
If S is not a valid escaped file name, i.e., if it ends with an odd number
of backslashes or if it contains a backslash followed by anything other
than "n" or another backslash, return NULL. */
static char * Line 308
filename_unescape (char *s, size_t s_len) Line 309
{
char *dst = s; Line 311
for (size_t i = 0; i < s_len; i++) Line 313
{
switch (s[i]) Line 315
{
case '\\': Line 317
if (i == s_len - 1) Line 318
{
/* File name ends with an unescaped backslash: invalid. */
return NULL; Line 321
}
++i; Line 323
switch (s[i]) Line 324
{
case 'n': Line 326
*dst++ = '\n'; Line 327
break; Line 328
case '\\': Line 329
*dst++ = '\\'; Line 330
break; Line 331
default: Line 332
/* Only '\' or 'n' may follow a backslash. */
return NULL; Line 334
}
break; Line 336
case '\0': Line 338
/* The file name may not contain a NUL. */
return NULL; Line 340
default: Line 342
*dst++ = s[i]; Line 343
break; Line 344
}
}
if (dst < s + s_len) Line 347
*dst = '\0'; Line 348
return s; Line 350
} Block 9
/* Return true if S is a NUL-terminated string of DIGEST_HEX_BYTES hex digits.
Otherwise, return false. */
static bool _GL_ATTRIBUTE_PURE Line 355
hex_digits (unsigned char const *s) Line 356
{
for (unsigned int i = 0; i < digest_hex_bytes; i++) Line 358
{
if (!isxdigit (*s)) Line 360
return false; Line 361
++s; Line 362
}
return *s == '\0'; Line 364
} Block 10
/* Split the checksum string S (of length S_LEN) from a BSD 'md5' or
'sha1' command into two parts: a hexadecimal digest, and the file
name. S is modified. Return true if successful. */
static bool Line 371
bsd_split_3 (char *s, size_t s_len, unsigned char **hex_digest, Line 372
char **file_name, bool escaped_filename) Line 373
{
size_t i; Line 375
if (s_len == 0) Line 377
return false; Line 378
/* Find end of filename. */
i = s_len - 1; Line 381
while (i && s[i] != ')') Line 382
i--; Line 383
if (s[i] != ')') Line 385
return false; Line 386
*file_name = s; Line 388
if (escaped_filename && filename_unescape (s, i) == NULL) Line 390
return false; Line 391
s[i++] = '\0'; Line 393
while (ISWHITE (s[i])) Line 395
i++; Line 396
if (s[i] != '=') Line 398
return false; Line 399
i++; Line 401
while (ISWHITE (s[i])) Line 403
i++; Line 404
*hex_digest = (unsigned char *) &s[i]; Line 406
return hex_digits (*hex_digest); Line 408
} Block 11
/* Split the string S (of length S_LEN) into three parts:
a hexadecimal digest, binary flag, and the file name.
S is modified. Return true if successful. */
static bool Line 415
split_3 (char *s, size_t s_len, Line 416
unsigned char **hex_digest, int *binary, char **file_name) Line 417
{
bool escaped_filename = false; Line 419
size_t algo_name_len; Line 420
size_t i = 0; Line 422
while (ISWHITE (s[i])) Line 423
++i; Line 424
if (s[i] == '\\') Line 426
{
++i; Line 428
escaped_filename = true; Line 429
}
/* Check for BSD-style checksum line. */
algo_name_len = strlen (DIGEST_TYPE_STRING); Line 434
if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len)) Line 435
{
i += algo_name_len; Line 437
#if HASH_ALGO_BLAKE2 Line 438
/* Terminate and match algorithm name. */
char const *algo_name = &s[i - algo_name_len]; Line 440
/* Skip algorithm variants. */
while (s[i] && ! ISWHITE (s[i]) && s[i] != '-' && s[i] != '(') Line 442
++i; Line 443
bool length_specified = s[i] == '-'; Line 444
bool openssl_format = s[i] == '('; /* and no length_specified */ Line 445
s[i++] = '\0'; Line 446
ptrdiff_t algo = argmatch (algo_name, algorithm_out_string, NULL, 0); Line 447
if (algo < 0) Line 448
return false; Line 449
else Line 450
b2_algorithm = algo; Line 451
if (openssl_format) Line 452
s[--i] = '('; Line 453
if (length_specified) Line 455
{
unsigned long int tmp_ulong; Line 457
if (xstrtoul (s + i, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK Line 458
&& 0 < tmp_ulong && tmp_ulong <= blake2_max_len[b2_algorithm] * 8 Line 459
&& tmp_ulong % 8 == 0) Line 460
b2_length = tmp_ulong; Line 461
else Line 462
return false; Line 463
while (ISDIGIT (s[i])) Line 465
++i; Line 466
}
else Line 468
b2_length = blake2_max_len[b2_algorithm] * 8; Line 469
digest_hex_bytes = b2_length / 4; Line 471
#endif Line 472
if (s[i] == ' ') Line 473
++i; Line 474
if (s[i] == '(') Line 475
{
++i; Line 477
*binary = 0; Line 478
return bsd_split_3 (s + i, s_len - i, Line 479
hex_digest, file_name, escaped_filename); Line 480
}
return false; Line 482
}
/* Ignore this line if it is too short.
Each line must have at least 'min_digest_line_length - 1' (or one more, if
the first is a backslash) more characters to contain correct message digest
information. */
if (s_len - i < min_digest_line_length + (s[i] == '\\')) Line 489
return false; Line 490
*hex_digest = (unsigned char *) &s[i]; Line 492
#if HASH_ALGO_BLAKE2 Line 494
/* Auto determine length. */
unsigned char const *hp = *hex_digest; Line 496
digest_hex_bytes = 0; Line 497
while (isxdigit (*hp++)) Line 498
digest_hex_bytes++; Line 499
if (digest_hex_bytes < 2 || digest_hex_bytes % 2 Line 500
|| blake2_max_len[b2_algorithm] * 2 < digest_hex_bytes) Line 501
return false; Line 502
b2_length = digest_hex_bytes * 4; Line 503
#endif Line 504
/* The first field has to be the n-character hexadecimal
representation of the message digest. If it is not followed
immediately by a white space it's an error. */
i += digest_hex_bytes; Line 509
if (!ISWHITE (s[i])) Line 510
return false; Line 511
s[i++] = '\0'; Line 513
if (! hex_digits (*hex_digest)) Line 515
return false; Line 516
/* If "bsd reversed" format detected. */
if ((s_len - i == 1) || (s[i] != ' ' && s[i] != '*')) Line 519
{
/* Don't allow mixing bsd and standard formats,
to minimize security issues with attackers
renaming files with leading spaces.
This assumes that with bsd format checksums
that the first file name does not have
a leading ' ' or '*'. */
if (bsd_reversed == 0) Line 527
return false; Line 528
bsd_reversed = 1; Line 529
}
else if (bsd_reversed != 1) Line 531
{
bsd_reversed = 0; Line 533
*binary = (s[i++] == '*'); Line 534
}
/* All characters between the type indicator and end of line are
significant -- that includes leading and trailing white space. */
*file_name = &s[i]; Line 539
if (escaped_filename) Line 541
return filename_unescape (&s[i], s_len - i) != NULL; Line 542
return true; Line 544
} Block 12
/* If ESCAPE is true, then translate each NEWLINE byte to the string, "\\n",
and each backslash to "\\\\". */
static void Line 549
print_filename (char const *file, bool escape) Line 550
{
if (! escape) Line 552
{
fputs (file, stdout); Line 554
return; Line 555
}
while (*file) Line 558
{
switch (*file) Line 560
{
case '\n': Line 562
fputs ("\\n", stdout); Line 563
break; Line 564
case '\\': Line 566
fputs ("\\\\", stdout); Line 567
break; Line 568
default: Line 570
putchar (*file); Line 571
break; Line 572
}
file++; Line 574
}
} Block 13
/* An interface to the function, DIGEST_STREAM.
Operate on FILENAME (it may be "-").
*BINARY indicates whether the file is binary. BINARY < 0 means it
depends on whether binary mode makes any difference and the file is
a terminal; in that case, clear *BINARY if the file was treated as
text because it was a terminal.
Put the checksum in *BIN_RESULT, which must be properly aligned.
Put true in *MISSING if the file can't be opened due to ENOENT.
Return true if successful. */
static bool Line 590
digest_file (const char *filename, int *binary, unsigned char *bin_result, Line 591
bool *missing) Line 592
{
FILE *fp; Line 594
int err; Line 595
bool is_stdin = STREQ (filename, "-"); Line 596
*missing = false; Line 598
if (is_stdin) Line 600
{
have_read_stdin = true; Line 602
fp = stdin; Line 603
if (O_BINARY && *binary) Line 604
{
if (*binary < 0) Line 606
*binary = ! isatty (STDIN_FILENO); Line 607
if (*binary) Line 608
xset_binary_mode (STDIN_FILENO, O_BINARY); Line 609
}
}
else Line 612
{
fp = fopen (filename, (O_BINARY && *binary ? "rb" : "r")); Line 614...!syscalls auto-comment...
if (fp == NULL) Line 615
{
if (ignore_missing && errno == ENOENT) Line 617
{
*missing = true; Line 619
return true; Line 620
}
error (0, errno, "%s", quotef (filename)); Line 622
return false; Line 623
}
}
fadvise (fp, FADVISE_SEQUENTIAL); Line 627...!syscalls auto-comment...
#if HASH_ALGO_BLAKE2 Line 629
err = DIGEST_STREAM (fp, bin_result, b2_length / 8); Line 630
#else Line 631
err = DIGEST_STREAM (fp, bin_result); Line 632
#endif Line 633
if (err) Line 634
{
error (0, errno, "%s", quotef (filename)); Line 636
if (fp != stdin) Line 637
fclose (fp); Line 638...!syscalls auto-comment...
return false; Line 639
}
if (!is_stdin && fclose (fp) != 0) Line 642...!syscalls auto-comment...
{
error (0, errno, "%s", quotef (filename)); Line 644
return false; Line 645
}
return true; Line 648
} Block 14
static bool Line 651
digest_check (const char *checkfile_name) Line 652
{
FILE *checkfile_stream; Line 654
uintmax_t n_misformatted_lines = 0; Line 655
uintmax_t n_improperly_formatted_lines = 0; Line 656
uintmax_t n_mismatched_checksums = 0; Line 657
uintmax_t n_open_or_read_failures = 0; Line 658
bool properly_formatted_lines = false; Line 659
bool matched_checksums = false; Line 660
unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN]; Line 661
/* Make sure bin_buffer is properly aligned. */
unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN); Line 663
uintmax_t line_number; Line 664
char *line; Line 665
size_t line_chars_allocated; Line 666
bool is_stdin = STREQ (checkfile_name, "-"); Line 667
if (is_stdin) Line 669
{
have_read_stdin = true; Line 671
checkfile_name = _("standard input"); Line 672
checkfile_stream = stdin; Line 673
}
else Line 675
{
checkfile_stream = fopen (checkfile_name, "r"); Line 677...!syscalls auto-comment...
if (checkfile_stream == NULL) Line 678
{
error (0, errno, "%s", quotef (checkfile_name)); Line 680
return false; Line 681
}
}
line_number = 0; Line 685
line = NULL; Line 686
line_chars_allocated = 0; Line 687
do
{
char *filename IF_LINT ( = NULL); Line 690
int binary; Line 691
unsigned char *hex_digest IF_LINT ( = NULL); Line 692
ssize_t line_length; Line 693
++line_number; Line 695
if (line_number == 0) Line 696
die (EXIT_FAILURE, 0, _("%s: too many checksum lines"), Line 697
quotef (checkfile_name)); Line 698
line_length = getline (&line, &line_chars_allocated, checkfile_stream); Line 700
if (line_length <= 0) Line 701
break; Line 702
/* Ignore comment lines, which begin with a '#' character. */
if (line[0] == '#') Line 705
continue; Line 706
/* Remove any trailing newline. */
if (line[line_length - 1] == '\n') Line 709
line[--line_length] = '\0'; Line 710
if (! (split_3 (line, line_length, &hex_digest, &binary, &filename) Line 712
&& ! (is_stdin && STREQ (filename, "-")))) Line 713
{
++n_misformatted_lines; Line 715
if (warn) Line 717
{
error (0, 0, Line 719
_("%s: %" PRIuMAX Line 720
": improperly formatted %s checksum line"), Line 721
quotef (checkfile_name), line_number, Line 722
DIGEST_TYPE_STRING); Line 723
}
++n_improperly_formatted_lines; Line 726
}
else Line 728
{
static const char bin2hex[] = { '0', '1', '2', '3', Line 730
'4', '5', '6', '7', Line 731
'8', '9', 'a', 'b', Line 732
'c', 'd', 'e', 'f' }; Line 733
bool ok; Line 734
bool missing; Line 735
/* Only escape in the edge case producing multiple lines,
to ease automatic processing of status output. */
bool needs_escape = ! status_only && strchr (filename, '\n'); Line 738
properly_formatted_lines = true; Line 740
ok = digest_file (filename, &binary, bin_buffer, &missing); Line 742
if (!ok) Line 744
{
++n_open_or_read_failures; Line 746
if (!status_only) Line 747
{
if (needs_escape) Line 749
putchar ('\\'); Line 750
print_filename (filename, needs_escape); Line 751
printf (": %s\n", _("FAILED open or read")); Line 752
}
}
else if (ignore_missing && missing) Line 755
{
/* Ignore missing files with --ignore-missing. */
;
}
else Line 760
{
size_t digest_bin_bytes = digest_hex_bytes / 2; Line 762
size_t cnt; Line 763
/* Compare generated binary number with text representation
in check file. Ignore case of hex digits. */
for (cnt = 0; cnt < digest_bin_bytes; ++cnt) Line 767
{
if (tolower (hex_digest[2 * cnt]) Line 769
!= bin2hex[bin_buffer[cnt] >> 4] Line 770
|| (tolower (hex_digest[2 * cnt + 1]) Line 771
!= (bin2hex[bin_buffer[cnt] & 0xf]))) Line 772
break; Line 773
}
if (cnt != digest_bin_bytes) Line 775
++n_mismatched_checksums; Line 776
else Line 777
matched_checksums = true; Line 778
if (!status_only) Line 780
{
if (cnt != digest_bin_bytes || ! quiet) Line 782
{
if (needs_escape) Line 784
putchar ('\\'); Line 785
print_filename (filename, needs_escape); Line 786
}
if (cnt != digest_bin_bytes) Line 789
printf (": %s\n", _("FAILED")); Line 790
else if (!quiet) Line 791
printf (": %s\n", _("OK")); Line 792
}
}
}
}
while (!feof (checkfile_stream) && !ferror (checkfile_stream)); Line 797
free (line); Line 799
if (ferror (checkfile_stream)) Line 801
{
error (0, 0, _("%s: read error"), quotef (checkfile_name)); Line 803
return false; Line 804
}
if (!is_stdin && fclose (checkfile_stream) != 0) Line 807...!syscalls auto-comment...
{
error (0, errno, "%s", quotef (checkfile_name)); Line 809
return false; Line 810
}
if (! properly_formatted_lines) Line 813
{
/* Warn if no tests are found. */
error (0, 0, _("%s: no properly formatted %s checksum lines found"), Line 816
quotef (checkfile_name), DIGEST_TYPE_STRING); Line 817
}
else Line 819
{
if (!status_only) Line 821
{
if (n_misformatted_lines != 0) Line 823
error (0, 0, Line 824
(ngettext Line 825
("WARNING: %" PRIuMAX " line is improperly formatted", Line 826
"WARNING: %" PRIuMAX " lines are improperly formatted", Line 827
select_plural (n_misformatted_lines))), Line 828
n_misformatted_lines); Line 829
if (n_open_or_read_failures != 0) Line 831
error (0, 0, Line 832
(ngettext Line 833
("WARNING: %" PRIuMAX " listed file could not be read", Line 834
"WARNING: %" PRIuMAX " listed files could not be read", Line 835
select_plural (n_open_or_read_failures))), Line 836
n_open_or_read_failures); Line 837
if (n_mismatched_checksums != 0) Line 839
error (0, 0, Line 840
(ngettext Line 841
("WARNING: %" PRIuMAX " computed checksum did NOT match", Line 842
"WARNING: %" PRIuMAX " computed checksums did NOT match", Line 843
select_plural (n_mismatched_checksums))), Line 844
n_mismatched_checksums); Line 845
if (ignore_missing && ! matched_checksums) Line 847
error (0, 0, _("%s: no file was verified"), Line 848
quotef (checkfile_name)); Line 849
}
}
return (properly_formatted_lines Line 853
&& matched_checksums Line 854
&& n_mismatched_checksums == 0 Line 855
&& n_open_or_read_failures == 0 Line 856
&& (!strict || n_improperly_formatted_lines == 0)); Line 857
} Block 15
int
main (int argc, char **argv) Line 861
{
unsigned char bin_buffer_unaligned[DIGEST_BIN_BYTES + DIGEST_ALIGN]; Line 863
/* Make sure bin_buffer is properly aligned. */
unsigned char *bin_buffer = ptr_align (bin_buffer_unaligned, DIGEST_ALIGN); Line 865
bool do_check = false; Line 866
int opt; Line 867
bool ok = true; Line 868
int binary = -1; Line 869
bool prefix_tag = false; Line 870
/* Setting values of global variables. */
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
/* Line buffer stdout to ensure lines are written atomically and immediately
so that processes running in parallel do not intersperse their output. */
setvbuf (stdout, NULL, _IOLBF, 0); Line 883
#if HASH_ALGO_BLAKE2 Line 885
const char* short_opts = "l:bctwz"; Line 886
const char* b2_length_str = ""; Line 887
#else Line 888
const char* short_opts = "bctwz"; Line 889
#endif Line 890
while ((opt = getopt_long (argc, argv, short_opts, long_options, NULL)) != -1)Line 892
switch (opt) Line 893
{
#if HASH_ALGO_BLAKE2 Line 895
case 'l': Line 896
b2_length = xdectoumax (optarg, 0, UINTMAX_MAX, "", Line 897
_("invalid length"), 0); Line 898
b2_length_str = optarg; Line 899
if (b2_length % 8 != 0) Line 900
{
error (0, 0, _("invalid length: %s"), quote (b2_length_str)); Line 902
die (EXIT_FAILURE, 0, _("length is not a multiple of 8")); Line 903
}
break; Line 905
#endif Line 906
case 'b': Line 907
binary = 1; Line 908
break; Line 909
case 'c': Line 910
do_check = true; Line 911
break; Line 912
case STATUS_OPTION: Line 913
status_only = true; Line 914
warn = false; Line 915
quiet = false; Line 916
break; Line 917
case 't': Line 918
binary = 0; Line 919
break; Line 920
case 'w': Line 921
status_only = false; Line 922
warn = true; Line 923
quiet = false; Line 924
break; Line 925
case IGNORE_MISSING_OPTION: Line 926
ignore_missing = true; Line 927
break; Line 928
case QUIET_OPTION: Line 929
status_only = false; Line 930
warn = false; Line 931
quiet = true; Line 932
break; Line 933
case STRICT_OPTION: Line 934
strict = true; Line 935
break; Line 936
case TAG_OPTION: Line 937
prefix_tag = true; Line 938
binary = 1; Line 939
break; Line 940
case 'z': Line 941
delim = '\0'; Line 942
break; Line 943
case_GETOPT_HELP_CHAR; Line 944
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 945
default: Line 946
usage (EXIT_FAILURE); Line 947
}
min_digest_line_length = MIN_DIGEST_LINE_LENGTH; Line 950
#if HASH_ALGO_BLAKE2 Line 951
if (b2_length > blake2_max_len[b2_algorithm] * 8) Line 952
{
error (0, 0, _("invalid length: %s"), quote (b2_length_str)); Line 954
die (EXIT_FAILURE, 0, Line 955
_("maximum digest length for %s is %"PRIuMAX" bits"), Line 956
quote (algorithm_in_string[b2_algorithm]), Line 957
blake2_max_len[b2_algorithm] * 8); Line 958
}
if (b2_length == 0 && ! do_check) Line 960
b2_length = blake2_max_len[b2_algorithm] * 8; Line 961
digest_hex_bytes = b2_length / 4; Line 962
#else Line 963
digest_hex_bytes = DIGEST_HEX_BYTES; Line 964
#endif Line 965
if (prefix_tag && !binary) Line 967
{
/* This could be supported in a backwards compatible way
by prefixing the output line with a space in text mode.
However that's invasive enough that it was agreed to
not support this mode with --tag, as --text use cases
are adequately supported by the default output format. */
error (0, 0, _("--tag does not support --text mode")); Line 974
usage (EXIT_FAILURE); Line 975
}
if (delim != '\n' && do_check) Line 978
{
error (0, 0, _("the --zero option is not supported when " Line 980
"verifying checksums")); Line 981
usage (EXIT_FAILURE); Line 982
}
if (prefix_tag && do_check) Line 985
{
error (0, 0, _("the --tag option is meaningless when " Line 987
"verifying checksums")); Line 988
usage (EXIT_FAILURE); Line 989
}
if (0 <= binary && do_check) Line 992
{
error (0, 0, _("the --binary and --text options are meaningless when " Line 994
"verifying checksums")); Line 995
usage (EXIT_FAILURE); Line 996
}
if (ignore_missing && !do_check) Line 999
{
error (0, 0, Line 1001
_("the --ignore-missing option is meaningful only when " Line 1002
"verifying checksums")); Line 1003
usage (EXIT_FAILURE); Line 1004
}
if (status_only && !do_check) Line 1007
{
error (0, 0, Line 1009
_("the --status option is meaningful only when verifying checksums")); Line 1010
usage (EXIT_FAILURE); Line 1011
}
if (warn && !do_check) Line 1014
{
error (0, 0, Line 1016
_("the --warn option is meaningful only when verifying checksums")); Line 1017
usage (EXIT_FAILURE); Line 1018
}
if (quiet && !do_check) Line 1021
{
error (0, 0, Line 1023
_("the --quiet option is meaningful only when verifying checksums")); Line 1024
usage (EXIT_FAILURE); Line 1025
}
if (strict & !do_check) Line 1028
{
error (0, 0, Line 1030
_("the --strict option is meaningful only when verifying checksums")); Line 1031
usage (EXIT_FAILURE); Line 1032
}
if (!O_BINARY && binary < 0) Line 1035
binary = 0; Line 1036
char **operand_lim = argv + argc; Line 1038
if (optind == argc) Line 1039
*operand_lim++ = bad_cast ("-"); Line 1040
for (char **operandp = argv + optind; operandp < operand_lim; operandp++) Line 1042
{
char *file = *operandp; Line 1044
if (do_check) Line 1046
ok &= digest_check (file); Line 1047
else Line 1048
{
int file_is_binary = binary; Line 1050
bool missing; Line 1051
if (! digest_file (file, &file_is_binary, bin_buffer, &missing)) Line 1053
ok = false; Line 1054
else Line 1055
{
/* We don't really need to escape, and hence detect, the '\\'
char, and not doing so should be both forwards and backwards
compatible, since only escaped lines would have a '\\' char at
the start. However just in case users are directly comparing
against old (hashed) outputs, in the presence of files
containing '\\' characters, we decided to not simplify the
output in this case. */
bool needs_escape = (strchr (file, '\\') || strchr (file, '\n')) Line 1064
&& delim == '\n'; Line 1065
if (prefix_tag) Line 1067
{
if (needs_escape) Line 1069
putchar ('\\'); Line 1070
#if HASH_ALGO_BLAKE2 Line 1072
fputs (algorithm_out_string[b2_algorithm], stdout); Line 1073
if (b2_length < blake2_max_len[b2_algorithm] * 8) Line 1074
printf ("-%"PRIuMAX, b2_length); Line 1075
#else Line 1076
fputs (DIGEST_TYPE_STRING, stdout); Line 1077
#endif Line 1078
fputs (" (", stdout); Line 1079
print_filename (file, needs_escape); Line 1080
fputs (") = ", stdout); Line 1081
}
/* Output a leading backslash if the file name contains
a newline or backslash. */
if (!prefix_tag && needs_escape) Line 1086
putchar ('\\'); Line 1087
for (size_t i = 0; i < (digest_hex_bytes / 2); ++i) Line 1089
printf ("%02x", bin_buffer[i]); Line 1090
if (!prefix_tag) Line 1092
{
putchar (' '); Line 1094
putchar (file_is_binary ? '*' : ' '); Line 1096
print_filename (file, needs_escape); Line 1098
}
putchar (delim); Line 1101
}
}
}
if (have_read_stdin && fclose (stdin) == EOF) Line 1106...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("standard input")); Line 1107
return ok ? EXIT_SUCCESS : EXIT_FAILURE; Line 1109
} Block 16