* src/digest.c: Organize HASH_ALGO_CKSUM to be table driven, and amalgamate all digest algorithms. (main): Parse all options if HASH_ALGO_CKSUM, and disallow --tag, --zero, and --check with the traditional bsd, sysv, and crc checksums for now. * src/local.mk: Reorganize to include all digest modules in cksum. * tests/misc/cksum-a.sh: Add a new test. * tests/local.mk: Reference the new test. --- doc/coreutils.texi | 41 +++++-- src/digest.c | 267 ++++++++++++++++++++++++++++++++++++------ src/local.mk | 27 +++-- tests/local.mk | 1 + tests/misc/cksum-a.sh | 43 +++++++ 5 files changed, 320 insertions(+), 59 deletions(-) create mode 100755 tests/misc/cksum-a.sh
diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 5c12298cf..39eea77b0 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -3928,9 +3928,12 @@ next section) is preferable in new applications. @cindex cyclic redundancy check @cindex CRC checksum -@command{cksum} computes a cyclic redundancy check (CRC) checksum for each -given @var{file}, or standard input if none are given or for a -@var{file} of @samp{-}. Synopsis: +@command{cksum} by default computes a cyclic redundancy check (CRC) checksum +for each given @var{file}, or standard input if none are given or for a +@var{file} of @samp{-}. + +Also cksum supports the @option{-a,--algorithm} option to select the +digest algorithm to use. Synopsis: @example cksum [@var{option}]@dots{} [@var{file}]@dots{} @@ -3939,8 +3942,7 @@ cksum [@var{option}]@dots{} [@var{file}]@dots{} @command{cksum} prints the CRC checksum for each file along with the number of bytes in the file, and the file name unless no arguments were given. -@command{cksum} is typically used to ensure that files -transferred by unreliable means (e.g., netnews) have not been corrupted, +@command{cksum} is typically used to ensure that files have not been corrupted, by comparing the @command{cksum} output for the received files with the @command{cksum} output for the original files (typically given in the distribution). @@ -3949,10 +3951,33 @@ The CRC algorithm is specified by the POSIX standard. It is not compatible with the BSD or System V @command{sum} algorithms (see the previous section); it is more robust. -The only options are @option{--help} and @option{--version}. @xref{Common -options}. +The same usage and options as the @command{b2sum} +command are supported. @xref{b2sum invocation}. +In addition @command{cksum} supports the following options. -@exitstatus +@table @samp + +@item -a +@itemx --algorithm +@opindex -a +@opindex --algorithm +@cindex digest algorithm +Compute checksums using the specified digest algorithm. +Supported algorithms are: + +@example +@samp{sysv} (equivalent to sum -s) +@samp{bsd} (equivalent to sum -r) +@samp{crc} (equivalent to cksum) +@samp{md5} (equivalent to md5sum) +@samp{sha1} (equivalent to sha1sum) +@samp{sha224} (equivalent to sha224sum) +@samp{sha256} (equivalent to sha256sum) +@samp{sha384} (equivalent to sha384sum) +@samp{sha512} (equivalent to sha512sum) +@samp{blake2b} (equivalent to b2sum) +@end example +@end table @node b2sum invocation diff --git a/src/digest.c b/src/digest.c index 9381f6065..fd4a963a4 100644 --- a/src/digest.c +++ b/src/digest.c @@ -27,25 +27,25 @@ #include "xdectoint.h" #include "xstrtol.h" -#if HASH_ALGO_SUM +#if HASH_ALGO_SUM || HASH_ALGO_CKSUM # include "sum.h" #endif #if HASH_ALGO_CKSUM # include "cksum.h" #endif -#if HASH_ALGO_BLAKE2 +#if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM # include "blake2/b2sum.h" #endif -#if HASH_ALGO_MD5 +#if HASH_ALGO_MD5 || HASH_ALGO_CKSUM # include "md5.h" #endif -#if HASH_ALGO_SHA1 +#if HASH_ALGO_SHA1 || HASH_ALGO_CKSUM # include "sha1.h" #endif -#if HASH_ALGO_SHA256 || HASH_ALGO_SHA224 +#if HASH_ALGO_SHA256 || HASH_ALGO_SHA224 || HASH_ALGO_CKSUM # include "sha256.h" #endif -#if HASH_ALGO_SHA512 || HASH_ALGO_SHA384 +#if HASH_ALGO_SHA512 || HASH_ALGO_SHA384 || HASH_ALGO_CKSUM # include "sha512.h" #endif #include "die.h" @@ -63,12 +63,14 @@ # define DIGEST_BITS 16 # define DIGEST_ALIGN 4 #elif HASH_ALGO_CKSUM +# define MAX_DIGEST_BITS 512 +# define MAX_DIGEST_ALIGN 8 # define PROGRAM_NAME "cksum" -# define DIGEST_TYPE_STRING "CRC" -# define DIGEST_STREAM crc_sum_stream -# define DIGEST_OUT output_crc -# define DIGEST_BITS 32 -# define DIGEST_ALIGN 4 +# define DIGEST_TYPE_STRING algorithm_tags[cksum_algorithm] +# define DIGEST_STREAM cksumfns[cksum_algorithm] +# define DIGEST_OUT cksum_output_fns[cksum_algorithm] +# define DIGEST_BITS MAX_DIGEST_BITS +# define DIGEST_ALIGN MAX_DIGEST_ALIGN #elif HASH_ALGO_MD5 # define PROGRAM_NAME "md5sum" # define DIGEST_TYPE_STRING "MD5" @@ -79,7 +81,7 @@ #elif HASH_ALGO_BLAKE2 # define PROGRAM_NAME "b2sum" # define DIGEST_TYPE_STRING "BLAKE2" -# define DIGEST_STREAM blake2fns[b2_algorithm] +# define DIGEST_STREAM blake2b_stream # define DIGEST_BITS 512 # define DIGEST_REFERENCE "RFC 7693" # define DIGEST_ALIGN 8 @@ -146,7 +148,6 @@ #endif #define DIGEST_BIN_BYTES (DIGEST_BITS / 8) - /* 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 @@ -158,6 +159,12 @@ + 1 /* minimum filename length */ ) #endif +#if !HASH_ALGO_SUM +static void +output_file (char const *file, int binary_file, void const *digest, + bool tagged, bool args _GL_UNUSED, uintmax_t length _GL_UNUSED); +#endif + /* True if any of the files read were the standard input. */ static bool have_read_stdin; @@ -191,7 +198,7 @@ static int bsd_reversed = -1; /* line delimiter. */ static unsigned char delim = '\n'; -#if HASH_ALGO_BLAKE2 +#if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM static char const *const algorithm_in_string[] = { "blake2b", NULL @@ -200,19 +207,15 @@ static char const *const algorithm_out_string[] = { "BLAKE2b", NULL }; -enum Algorithm +enum blake2_Algorithm { BLAKE2b }; verify (ARRAY_CARDINALITY (algorithm_in_string) == 2); verify (ARRAY_CARDINALITY (algorithm_out_string) == 2); -static enum Algorithm b2_algorithm; +static enum blake2_Algorithm b2_algorithm; static uintmax_t b2_length; -static blake2fn blake2fns[]= -{ - blake2b_stream -}; static uintmax_t blake2_max_len[]= { BLAKE2B_OUTBYTES @@ -241,7 +244,112 @@ static digest_output_fn sum_output_fns[]= }; #endif +#if HASH_ALGO_CKSUM +static int +md5_sum_stream (FILE *stream, void *resstream, uintmax_t *length) +{ + return md5_stream (stream, resstream); +} +static int +sha1_sum_stream (FILE *stream, void *resstream, uintmax_t *length) +{ + return sha1_stream (stream, resstream); +} +static int +sha224_sum_stream (FILE *stream, void *resstream, uintmax_t *length) +{ + return sha224_stream (stream, resstream); +} +static int +sha256_sum_stream (FILE *stream, void *resstream, uintmax_t *length) +{ + return sha256_stream (stream, resstream); +} +static int +sha384_sum_stream (FILE *stream, void *resstream, uintmax_t *length) +{ + return sha384_stream (stream, resstream); +} +static int +sha512_sum_stream (FILE *stream, void *resstream, uintmax_t *length) +{ + return sha512_stream (stream, resstream); +} +static int +blake2b_sum_stream (FILE *stream, void *resstream, uintmax_t *length) +{ + return blake2b_stream (stream, resstream, *length); +} + +enum Algorithm +{ + bsd, + sysv, + crc, + md5, + sha1, + sha224, + sha256, + sha384, + sha512, + blake2b, +}; + +static char const *const algorithm_args[] = +{ + "bsd", "sysv", "crc", "md5", "sha1", "sha224", + "sha256", "sha384", "sha512", "blake2b", NULL +}; +static enum Algorithm const algorithm_types[] = +{ + bsd, sysv, crc, md5, sha1, sha224, + sha256, sha384, sha512, blake2b, +}; +ARGMATCH_VERIFY (algorithm_args, algorithm_types); + +static char const *const algorithm_tags[] = +{ + "BSD", "SYSV", "CRC", "MD5", "SHA1", "SHA224", + "SHA256", "SHA384", "SHA512", "BLAKE2b", NULL +}; +static int const algorithm_bits[] = +{ + 16, 16, 32, 128, 160, 224, + 256, 384, 512, 512, 0 +}; + +verify (ARRAY_CARDINALITY (algorithm_bits) + == ARRAY_CARDINALITY (algorithm_args)); + +static enum Algorithm cksum_algorithm = crc; +static sumfn cksumfns[]= +{ + bsd_sum_stream, + sysv_sum_stream, + crc_sum_stream, + md5_sum_stream, + sha1_sum_stream, + sha224_sum_stream, + sha256_sum_stream, + sha384_sum_stream, + sha512_sum_stream, + blake2b_sum_stream, +}; +static digest_output_fn cksum_output_fns[]= +{ + output_bsd, + output_sysv, + output_crc, + output_file, + output_file, + output_file, + output_file, + output_file, + output_file, + output_file, +}; bool debug; +#endif /* For long options that have no equivalent short option, use a non-character as a pseudo short option, starting with CHAR_MAX + 1. */ @@ -258,10 +366,10 @@ enum static struct option const long_options[] = { -#if HASH_ALGO_BLAKE2 +#if HASH_ALGO_BLAKE2 || HASH_ALSO_CKSUM { "length", required_argument, NULL, 'l'}, #endif -#if !HASH_AGLO_SUM && !HASH_ALGO_CKSUM +#if !HASH_AGLO_SUM { "binary", no_argument, NULL, 'b' }, { "check", no_argument, NULL, 'c' }, { "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION}, @@ -274,6 +382,7 @@ static struct option const long_options[] = { "zero", no_argument, NULL, 'z' }, #endif #if HASH_ALGO_CKSUM + {"algorithm", required_argument, NULL, 'a'}, {"debug", no_argument, NULL, DEBUG_PROGRAM_OPTION}, #endif #if HASH_ALGO_SUM @@ -293,11 +402,18 @@ usage (int status) { printf (_("\ Usage: %s [OPTION]... [FILE]...\n\ +"), program_name); +#if HASH_ALGO_CKSUM + fputs (_("\ +Print or check checksums\n\ +"), stdout); +#else + printf (_("\ Print or check %s (%d-bit) checksums.\n\ "), - program_name, DIGEST_TYPE_STRING, DIGEST_BITS); +#endif emit_stdin_note (); #if HASH_ALGO_SUM @@ -307,22 +423,27 @@ Print or check %s (%d-bit) checksums.\n\ -s, --sysv use System V sum algorithm, use 512 bytes blocks\n\ "), stdout); #endif -#if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM - if (O_BINARY) +#if HASH_ALGO_CKSUM fputs (_("\ \n\ + -a, --algorithm select the digest mode to operate in. See DIGEST below.\ +\n\ +"), stdout); +#endif +#if !HASH_ALGO_SUM + if (O_BINARY) + fputs (_("\ -b, --binary read in binary mode (default unless reading tty stdin)\n\ "), stdout); else fputs (_("\ -\n\ -b, --binary read in binary mode\n\ "), stdout); printf (_("\ -c, --check read %s sums from the FILEs and check them\n"), DIGEST_TYPE_STRING); -# if HASH_ALGO_BLAKE2 +# if HASH_ALGO_BLAKE2 || HASH_ALSO_CKSUM fputs (_("\ -l, --length digest length in bits; must not exceed the maximum for\n\ the blake2 algorithm and must be a multiple of 8\n\ @@ -361,17 +482,40 @@ The following five options are useful only when verifying checksums:\n\ #endif fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); +#if HASH_ALGO_CKSUM + fputs (_("\ +\n\ +DIGEST determines the digest algorithm and default output format:\n\ + 'sysv' (equivalent to sum -s)\n\ + 'bsd' (equivalent to sum -r)\n\ + 'crc' (equivalent to cksum)\n\ + 'md5' (equivalent to md5sum)\n\ + 'sha1' (equivalent to sha1sum)\n\ + 'sha224' (equivalent to sha224sum)\n\ + 'sha256' (equivalent to sha256sum)\n\ + 'sha384' (equivalent to sha384sum)\n\ + 'sha512' (equivalent to sha512sum)\n\ + 'blake2b' (equivalent to b2sum)\n\ +\n"), stdout); +#endif #if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM printf (_("\ \n\ -The sums are computed as described in %s. When checking, the input\n\ -should be a former output of this program. The default mode is to print a\n\ -line with checksum, a space, a character indicating input mode ('*' for binary,\ -\n' ' for text or where binary is insignificant), and name for each FILE.\n\ +The sums are computed as described in %s.\n"), DIGEST_REFERENCE); + fputs (_("\ +When checking, the input should be a former output of this program.\n\ +The default mode is to print a line with: checksum, a space,\n\ +a character indicating input mode ('*' for binary, ' ' for text\n\ +or where binary is insignificant), and name for each FILE.\n\ \n\ Note: There is no difference between binary mode and text mode on GNU systems.\ -\n"), - DIGEST_REFERENCE); +\n"), stdout); +#endif +#if HASH_ALGO_CKSUM + fputs (_("\ +When checking, the input should be a former output of this program,\n\ +or equivalent standalone program.\ +\n"), stdout); #endif emit_ancillary_info (PROGRAM_NAME); } @@ -707,7 +851,11 @@ digest_file (char const *filename, int *binary, unsigned char *bin_result, fadvise (fp, FADVISE_SEQUENTIAL); -#if HASH_ALGO_SUM || HASH_ALGO_CKSUM +#if HASH_ALGO_CKSUM + if (cksum_algorithm == blake2b) + *length = b2_length / 8; + err = DIGEST_STREAM (fp, bin_result, length); +#elif HASH_ALGO_SUM err = DIGEST_STREAM (fp, bin_result, length); #elif HASH_ALGO_BLAKE2 err = DIGEST_STREAM (fp, bin_result, b2_length / 8); @@ -729,7 +877,7 @@ digest_file (char const *filename, int *binary, unsigned char *bin_result, return true; } -#if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM +#if !HASH_ALGO_SUM static void output_file (char const *file, int binary_file, void const *digest, bool tagged, bool args _GL_UNUSED, uintmax_t length _GL_UNUSED) @@ -1021,7 +1169,8 @@ main (int argc, char **argv) #if HASH_ALGO_SUM const char* short_opts = "rs"; #elif HASH_ALGO_CKSUM - const char* short_opts = ""; + const char* short_opts = "a:l:bctwz"; + const char* b2_length_str = ""; #elif HASH_ALGO_BLAKE2 const char* short_opts = "l:bctwz"; const char* b2_length_str = ""; @@ -1033,11 +1182,16 @@ main (int argc, char **argv) switch (opt) { #if HASH_ALGO_CKSUM + case 'a': + cksum_algorithm = XARGMATCH ("--algorithm", optarg, + algorithm_args, algorithm_types); + break; + case DEBUG_PROGRAM_OPTION: debug = true; break; #endif -#if HASH_ALGO_BLAKE2 +#if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM case 'l': b2_length = xdectoumax (optarg, 0, UINTMAX_MAX, "", _("invalid length"), 0); @@ -1049,7 +1203,7 @@ main (int argc, char **argv) } break; #endif -#if !HASH_ALGO_SUM && !HASH_ALGO_CKSUM +#if !HASH_ALGO_SUM case 'b': binary = 1; break; @@ -1104,7 +1258,7 @@ main (int argc, char **argv) } min_digest_line_length = MIN_DIGEST_LINE_LENGTH; -#if HASH_ALGO_BLAKE2 +#if HASH_ALGO_BLAKE2 || HASH_ALGO_CKSUM if (b2_length > blake2_max_len[b2_algorithm] * 8) { error (0, 0, _("invalid length: %s"), quote (b2_length_str)); @@ -1113,13 +1267,48 @@ main (int argc, char **argv) quote (algorithm_in_string[b2_algorithm]), blake2_max_len[b2_algorithm] * 8); } +# if HASH_ALGO_CKSUM + if (b2_length && cksum_algorithm != blake2b) + die (EXIT_FAILURE, 0, + _("--length is only supported with --algorithm=blake2b")); +# endif if (b2_length == 0 && ! do_check) b2_length = blake2_max_len[b2_algorithm] * 8; +# if HASH_ALGO_BLAKE2 digest_hex_bytes = b2_length / 4; +# else + if (cksum_algorithm == blake2b) + digest_hex_bytes = b2_length / 4; + else + digest_hex_bytes = algorithm_bits[cksum_algorithm] / 4; +# endif #else digest_hex_bytes = DIGEST_HEX_BYTES; #endif +#if HASH_ALGO_CKSUM + /* TODO: Remove these restrictions. */ + switch (cksum_algorithm) + { + case bsd: + case sysv: + case crc: + if (delim != '\n') + die (EXIT_FAILURE, 0, + _("--zero is not supported with --algorithm={bsd,sysv,crc}")); + if (prefix_tag) + die (EXIT_FAILURE, 0, + _("--tag is not supported with --algorithm={bsd,sysv,crc}")); + if (do_check) + die (EXIT_FAILURE, 0, + _("--check is not supported with --algorithm={bsd,sysv,crc}")); + break; + default: + break; + } + +#endif + if (prefix_tag && !binary) { /* This could be supported in a backwards compatible way diff --git a/src/local.mk b/src/local.mk index 54303d305..0c8b65d39 100644 --- a/src/local.mk +++ b/src/local.mk @@ -304,6 +304,7 @@ src_sha224sum_LDADD += $(LIB_CRYPTO) src_sha256sum_LDADD += $(LIB_CRYPTO) src_sha384sum_LDADD += $(LIB_CRYPTO) src_sha512sum_LDADD += $(LIB_CRYPTO) +src_cksum_LDADD += $(LIB_CRYPTO) # for canon_host src_pinky_LDADD += $(GETADDRINFO_LIB) @@ -355,18 +356,6 @@ src___SOURCES = src/lbracket.c nodist_src_coreutils_SOURCES = src/coreutils.h src_coreutils_SOURCES = src/coreutils.c -src_sum_SOURCES = src/sum.c src/sum.h src/digest.c -src_sum_CPPFLAGS = -DHASH_ALGO_SUM=1 $(AM_CPPFLAGS) - -src_cksum_SOURCES = src/cksum.c src/cksum.h src/crctab.c src/digest.c -src_cksum_CPPFLAGS = -DHASH_ALGO_CKSUM=1 $(AM_CPPFLAGS) -if USE_PCLMUL_CRC32 -noinst_LIBRARIES += src/libcksum_pclmul.a -src_libcksum_pclmul_a_SOURCES = src/cksum_pclmul.c src/cksum.h -cksum_pclmul_ldadd = src/libcksum_pclmul.a -src_cksum_LDADD += $(cksum_pclmul_ldadd) -src_libcksum_pclmul_a_CFLAGS = -mavx -mpclmul $(AM_CFLAGS) -endif src_cp_SOURCES = src/cp.c $(copy_sources) $(selinux_sources) src_dir_SOURCES = src/ls.c src/ls-dir.c src_env_SOURCES = src/env.c src/operand2sig.c @@ -401,6 +390,9 @@ src_arch_SOURCES = src/uname.c src/uname-arch.c src_cut_SOURCES = src/cut.c src/set-fields.c src_numfmt_SOURCES = src/numfmt.c src/set-fields.c +src_sum_SOURCES = src/sum.c src/sum.h src/digest.c +src_sum_CPPFLAGS = -DHASH_ALGO_SUM=1 $(AM_CPPFLAGS) + src_md5sum_SOURCES = src/digest.c src_md5sum_CPPFLAGS = -DHASH_ALGO_MD5=1 $(AM_CPPFLAGS) src_sha1sum_SOURCES = src/digest.c @@ -419,6 +411,17 @@ src_b2sum_SOURCES = src/digest.c \ src/blake2/blake2b-ref.c \ src/blake2/b2sum.c src/blake2/b2sum.h +src_cksum_SOURCES = $(src_b2sum_SOURCES) src/sum.c src/sum.h \ + src/cksum.c src/cksum.h src/crctab.c +src_cksum_CPPFLAGS = -DHASH_ALGO_CKSUM=1 -DHAVE_CONFIG_H $(AM_CPPFLAGS) +if USE_PCLMUL_CRC32 +noinst_LIBRARIES += src/libcksum_pclmul.a +src_libcksum_pclmul_a_SOURCES = src/cksum_pclmul.c src/cksum.h +cksum_pclmul_ldadd = src/libcksum_pclmul.a +src_cksum_LDADD += $(cksum_pclmul_ldadd) +src_libcksum_pclmul_a_CFLAGS = -mavx -mpclmul $(AM_CFLAGS) +endif + src_base64_SOURCES = src/basenc.c src_base64_CPPFLAGS = -DBASE_TYPE=64 $(AM_CPPFLAGS) src_base32_SOURCES = src/basenc.c diff --git a/tests/local.mk b/tests/local.mk index 4a08147df..3ddd6f1bb 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -289,6 +289,7 @@ all_tests = \ tests/misc/close-stdout.sh \ tests/misc/chroot-fail.sh \ tests/misc/cksum.sh \ + tests/misc/cksum-a.sh \ tests/misc/comm.pl \ tests/misc/csplit.sh \ tests/misc/csplit-1000.sh \ diff --git a/tests/misc/cksum-a.sh b/tests/misc/cksum-a.sh new file mode 100755 index 000000000..c402f26e2 --- /dev/null +++ b/tests/misc/cksum-a.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Validate cksum --algorithm operation + +# Copyright (C) 2021 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/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ cksum + +printf " +bsd sum -r +sysv sum -s +crc cksum +md5 md5um +sha1 sha1sum +sha224 sha224sum +sha256 sha256sum +sha384 sha384sum +sha512 sha512sum +blake2b b2sum +" | while read algo prog; do + $prog < /dev/null >> out || continue + cksum --algorithm=$algo < /dev/null >> out-a || fail=1 +done +compare out out-a || fail=1 + +returns_ 1 cksum -a bsd --tag </dev/null +returns_ 1 cksum -a bsd --zero </dev/null +returns_ 1 cksum -a bsd --check </dev/null + +Exit $fail -- 2.26.2