This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Update Digest-SHA to CPAN version 5.97
[perl5.git] / cpan / Digest-SHA / shasum
CommitLineData
207902b1 1#!perl
6bc89f92 2
0a178734
CBW
3 ## shasum: filter for computing SHA digests (ref. sha1sum/md5sum)
4 ##
f4f12f2f 5 ## Copyright (C) 2003-2017 Mark Shelor, All Rights Reserved
0a178734 6 ##
f4f12f2f
CBW
7 ## Version: 5.97
8 ## Wed Sep 6 02:23:02 MST 2017
65484cb9 9
207902b1
CBW
10 ## shasum SYNOPSIS adapted from GNU Coreutils sha1sum. Add
11 ## "-a" option for algorithm selection,
12 ## "-U" option for Universal Newlines support,
13 ## "-0" option for reading bit strings, and
14 ## "-p" option for portable digests (to be deprecated).
15
cee96d52 16BEGIN { pop @INC if $INC[-1] eq '.' }
e05a9d74 17
207902b1
CBW
18use strict;
19use warnings;
20use Fcntl;
21use Getopt::Long;
65484cb9
CBW
22
23my $POD = <<'END_OF_POD';
6bc89f92
SP
24
25=head1 NAME
26
27shasum - Print or Check SHA Checksums
28
29=head1 SYNOPSIS
30
65484cb9 31 Usage: shasum [OPTION]... [FILE]...
6bc89f92
SP
32 Print or check SHA checksums.
33 With no FILE, or when FILE is -, read standard input.
34
65484cb9
CBW
35 -a, --algorithm 1 (default), 224, 256, 384, 512, 512224, 512256
36 -b, --binary read in binary mode
37 -c, --check read SHA sums from the FILEs and check them
9dd45029 38 -t, --text read in text mode (default)
207902b1 39 -U, --UNIVERSAL read in Universal Newlines mode
cccd5831 40 produces same digest on Windows/Unix/Mac
e39652ea
CBW
41 -0, --01 read in BITS mode
42 ASCII '0' interpreted as 0-bit,
43 ASCII '1' interpreted as 1-bit,
44 all other characters ignored
207902b1 45 -p, --portable read in portable mode (to be deprecated)
6bc89f92 46
f4f12f2f 47 The following three options are useful only when verifying checksums:
65484cb9 48 -s, --status don't output anything, status code shows success
f4f12f2f 49 -q, --quiet don't print OK for each successfully verified file
65484cb9
CBW
50 -w, --warn warn about improperly formatted checksum lines
51
52 -h, --help display this help and exit
53 -v, --version output version information and exit
6bc89f92 54
65484cb9
CBW
55 When verifying SHA-512/224 or SHA-512/256 checksums, indicate the
56 algorithm explicitly using the -a option, e.g.
6bc89f92 57
65484cb9 58 shasum -a 512224 -c checksumfile
6bc89f92 59
626ec6d7
AC
60 The sums are computed as described in FIPS PUB 180-4. When checking,
61 the input should be a former output of this program. The default
62 mode is to print a line with checksum, a character indicating type
207902b1 63 (`*' for binary, ` ' for text, `U' for UNIVERSAL, `^' for BITS, `?'
f4f12f2f
CBW
64 for portable), and name for each FILE. The line starts with a `\'
65 character if the FILE name contains either newlines or backslashes,
66 which are then replaced by the two-character sequences `\n' and `\\'
67 respectively.
65484cb9
CBW
68
69 Report shasum bugs to mshelor@cpan.org
6bc89f92 70
747da336
RGS
71=head1 DESCRIPTION
72
65484cb9
CBW
73Running I<shasum> is often the quickest way to compute SHA message
74digests. The user simply feeds data to the script through files or
75standard input, and then collects the results from standard output.
747da336 76
e39652ea
CBW
77The following command shows how to compute digests for typical inputs
78such as the NIST test vector "abc":
747da336 79
dfe1edcb 80 perl -e "print qq(abc)" | shasum
747da336
RGS
81
82Or, if you want to use SHA-256 instead of the default SHA-1, simply say:
83
dfe1edcb 84 perl -e "print qq(abc)" | shasum -a 256
747da336 85
65484cb9
CBW
86Since I<shasum> mimics the behavior of the combined GNU I<sha1sum>,
87I<sha224sum>, I<sha256sum>, I<sha384sum>, and I<sha512sum> programs,
747da336
RGS
88you can install this script as a convenient drop-in replacement.
89
9dd45029
A
90Unlike the GNU programs, I<shasum> encompasses the full SHA standard by
91allowing partial-byte inputs. This is accomplished through the BITS
92option (I<-0>). The following example computes the SHA-224 digest of
93the 7-bit message I<0001100>:
94
95 perl -e "print qq(0001100)" | shasum -0 -a 224
96
6bc89f92
SP
97=head1 AUTHOR
98
f4f12f2f 99Copyright (c) 2003-2017 Mark Shelor <mshelor@cpan.org>.
6bc89f92
SP
100
101=head1 SEE ALSO
102
65484cb9 103I<shasum> is implemented using the Perl module L<Digest::SHA> or
6bc89f92
SP
104L<Digest::SHA::PurePerl>.
105
106=cut
107
65484cb9
CBW
108END_OF_POD
109
f4f12f2f 110my $VERSION = "5.97";
6bc89f92 111
6bc89f92 112sub usage {
128cbdba 113 my($err, $msg) = @_;
6bc89f92 114
128cbdba
SP
115 $msg = "" unless defined $msg;
116 if ($err) {
c7e5c266 117 warn($msg . "Type shasum -h for help\n");
128cbdba
SP
118 exit($err);
119 }
626ec6d7
AC
120 my($USAGE) = $POD =~ /SYNOPSIS(.+?)^=/sm;
121 $USAGE =~ s/^\s*//;
122 $USAGE =~ s/\s*$//;
65484cb9 123 $USAGE =~ s/^ //gm;
626ec6d7 124 print $USAGE, "\n";
6bc89f92
SP
125 exit($err);
126}
127
128
0a178734
CBW
129 ## Sync stdout and stderr by forcing a flush after every write
130
65484cb9
CBW
131select((select(STDOUT), $| = 1)[0]);
132select((select(STDERR), $| = 1)[0]);
0a178734
CBW
133
134
135 ## Collect options from command line
6bc89f92 136
f4f12f2f 137my ($alg, $binary, $check, $text, $status, $quiet, $warn, $help, $version);
207902b1 138my ($portable, $BITS, $reverse, $UNIVERSAL, $versions);
6bc89f92 139
747da336 140eval { Getopt::Long::Configure ("bundling") };
6bc89f92 141GetOptions(
128cbdba
SP
142 'b|binary' => \$binary, 'c|check' => \$check,
143 't|text' => \$text, 'a|algorithm=i' => \$alg,
144 's|status' => \$status, 'w|warn' => \$warn,
f4f12f2f 145 'q|quiet' => \$quiet,
128cbdba 146 'h|help' => \$help, 'v|version' => \$version,
e39652ea 147 'p|portable' => \$portable,
626ec6d7 148 '0|01' => \$BITS,
207902b1
CBW
149 'R|REVERSE' => \$reverse,
150 'U|UNIVERSAL' => \$UNIVERSAL,
626ec6d7 151 'V|VERSIONS' => \$versions,
128cbdba 152) or usage(1, "");
6bc89f92
SP
153
154
0a178734 155 ## Deal with help requests and incorrect uses
6bc89f92 156
128cbdba
SP
157usage(0)
158 if $help;
84c0b84e 159usage(1, "shasum: Ambiguous file mode\n")
207902b1
CBW
160 if scalar(grep {defined $_}
161 ($binary, $portable, $text, $BITS, $UNIVERSAL)) > 1;
c7e5c266 162usage(1, "shasum: --warn option used only when verifying checksums\n")
128cbdba 163 if $warn && !$check;
c7e5c266 164usage(1, "shasum: --status option used only when verifying checksums\n")
128cbdba 165 if $status && !$check;
f4f12f2f
CBW
166usage(1, "shasum: --quiet option used only when verifying checksums\n")
167 if $quiet && !$check;
6bc89f92
SP
168
169
626ec6d7
AC
170 ## Try to use Digest::SHA. If not installed, use the slower
171 ## but functionally equivalent Digest::SHA::PurePerl instead.
172
207902b1
CBW
173 ## If option -R is invoked, reverse the module preference,
174 ## i.e. try Digest::SHA::PurePerl first, then Digest::SHA.
626ec6d7 175
207902b1
CBW
176my @MODS = qw(Digest::SHA Digest::SHA::PurePerl);
177@MODS[0, 1] = @MODS[1, 0] if $reverse;
626ec6d7
AC
178
179my $module;
180for (@MODS) {
181 my $mod = $_;
182 if (eval "require $mod") {
183 $module = $mod;
184 last;
185 }
186}
187die "shasum: Unable to find " . join(" or ", @MODS) . "\n"
188 unless defined $module;
189
190
96d38a9d 191 ## Default to SHA-1 unless overridden by command line option
6bc89f92 192
dfe1edcb 193$alg = 1 unless defined $alg;
65484cb9 194grep { $_ == $alg } (1, 224, 256, 384, 512, 512224, 512256)
84c0b84e 195 or usage(1, "shasum: Unrecognized algorithm\n");
6bc89f92
SP
196
197
0a178734 198 ## Display version information if requested
6bc89f92
SP
199
200if ($version) {
201 print "$VERSION\n";
202 exit(0);
203}
204
626ec6d7
AC
205if ($versions) {
206 print "shasum $VERSION\n";
207 print "$module ", eval "\$${module}::VERSION", "\n";
208 print "perl ", defined $^V ? sprintf("%vd", $^V) : $], "\n";
209 exit(0);
210}
211
6bc89f92 212
0a178734
CBW
213 ## Try to figure out if the OS is DOS-like. If it is,
214 ## default to binary mode when reading files, unless
96d38a9d 215 ## explicitly overridden by command line "--text" or
207902b1 216 ## "--UNIVERSAL" or "--portable" options.
6bc89f92
SP
217
218my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/);
207902b1 219if ($isDOSish) { $binary = 1 unless $text || $UNIVERSAL || $portable }
128cbdba 220
207902b1
CBW
221my $modesym = $binary ? '*' : ($UNIVERSAL ? 'U' :
222 ($BITS ? '^' : ($portable ? '?' : ' ')));
6bc89f92
SP
223
224
0a178734 225 ## Read from STDIN (-) if no files listed on command line
6bc89f92
SP
226
227@ARGV = ("-") unless @ARGV;
228
229
0a178734 230 ## sumfile($file): computes SHA digest of $file
6bc89f92
SP
231
232sub sumfile {
dcbcf62d 233 my $file = shift;
6bc89f92 234
207902b1
CBW
235 my $mode = $binary ? 'b' : ($UNIVERSAL ? 'U' :
236 ($BITS ? '0' : ($portable ? 'p' : '')));
84c0b84e 237 my $digest = eval { $module->new($alg)->addfile($file, $mode) };
0a178734 238 if ($@) { warn "shasum: $file: $!\n"; return }
84c0b84e 239 $digest->hexdigest;
6bc89f92
SP
240}
241
242
0a178734 243 ## %len2alg: maps hex digest length to SHA algorithm
6bc89f92
SP
244
245my %len2alg = (40 => 1, 56 => 224, 64 => 256, 96 => 384, 128 => 512);
65484cb9
CBW
246$len2alg{56} = 512224 if $alg == 512224;
247$len2alg{64} = 512256 if $alg == 512256;
6bc89f92
SP
248
249
0a178734 250 ## unescape: convert backslashed filename to plain filename
6bc89f92 251
0a178734
CBW
252sub unescape {
253 $_ = shift;
254 s/\\\\/\0/g;
255 s/\\n/\n/g;
256 return if /\\/;
257 s/\0/\\/g;
258 return $_;
259}
6bc89f92 260
0a178734
CBW
261
262 ## verify: confirm the digest values in a checksum file
263
264sub verify {
265 my $checkfile = shift;
266 my ($err, $fmt_errs, $read_errs, $match_errs) = (0, 0, 0, 0);
65484cb9 267 my ($num_lines, $num_files) = (0, 0);
f4f12f2f 268 my ($bslash, $sum, $fname, $rsp, $digest, $isOK);
0a178734
CBW
269
270 local *FH;
65484cb9 271 $checkfile eq '-' and open(FH, '< -')
9cc8ef8a
CBW
272 and $checkfile = 'standard input'
273 or sysopen(FH, $checkfile, O_RDONLY)
274 or die "shasum: $checkfile: $!\n";
0a178734
CBW
275 while (<FH>) {
276 next if /^#/; s/\n$//; s/^[ \t]+//; $num_lines++;
277 $bslash = s/^\\//;
278 ($sum, $modesym, $fname) =
207902b1 279 /^([\da-fA-F]+)[ \t]([ *?^U])([^\0]*)/;
0a178734
CBW
280 $alg = defined $sum ? $len2alg{length($sum)} : undef;
281 $fname = unescape($fname) if defined $fname && $bslash;
282 if (grep { ! defined $_ } ($alg, $sum, $modesym, $fname)) {
283 $alg = 1 unless defined $alg;
dcbcf62d 284 warn("shasum: $checkfile: $.: improperly " .
0a178734
CBW
285 "formatted SHA$alg checksum line\n") if $warn;
286 $fmt_errs++;
6bc89f92
SP
287 next;
288 }
0a178734 289 $fname =~ s/\r$// unless -e $fname;
c7e5c266 290 $rsp = "$fname: "; $num_files++;
207902b1
CBW
291 ($binary, $text, $UNIVERSAL, $BITS, $portable) =
292 map { $_ eq $modesym } ('*', ' ', 'U', '^', 'p');
f4f12f2f 293 $isOK = 0;
747da336 294 unless ($digest = sumfile($fname)) {
dcbcf62d 295 $rsp .= "FAILED open or read\n";
c7e5c266 296 $err = 1; $read_errs++;
dcbcf62d
SP
297 }
298 else {
f4f12f2f 299 if (lc($sum) eq $digest) { $rsp .= "OK\n"; $isOK = 1 }
c7e5c266 300 else { $rsp .= "FAILED\n"; $err = 1; $match_errs++ }
dcbcf62d 301 }
f4f12f2f 302 print $rsp unless ($status || ($quiet && $isOK));
6bc89f92 303 }
0a178734
CBW
304 close(FH);
305 unless ($num_files) {
306 $alg = 1 unless defined $alg;
307 warn("shasum: $checkfile: no properly formatted " .
308 "SHA$alg checksum lines found\n");
309 $err = 1;
c7e5c266 310 }
0a178734
CBW
311 elsif (! $status) {
312 warn("shasum: WARNING: $fmt_errs line" . ($fmt_errs>1?
313 's are':' is') . " improperly formatted\n") if $fmt_errs;
314 warn("shasum: WARNING: $read_errs listed file" .
315 ($read_errs>1?'s':'') . " could not be read\n") if $read_errs;
316 warn("shasum: WARNING: $match_errs computed checksum" .
317 ($match_errs>1?'s':'') . " did NOT match\n") if $match_errs;
318 }
319 return($err == 0);
6bc89f92
SP
320}
321
322
0a178734 323 ## Verify or compute SHA checksums of requested files
6bc89f92 324
747da336
RGS
325my($file, $digest);
326
0a178734 327my $STATUS = 0;
747da336 328for $file (@ARGV) {
0a178734
CBW
329 if ($check) { $STATUS = 1 unless verify($file) }
330 elsif ($digest = sumfile($file)) {
331 if ($file =~ /[\n\\]/) {
332 $file =~ s/\\/\\\\/g; $file =~ s/\n/\\n/g;
333 $digest = "\\$digest";
334 }
84c0b84e 335 print "$digest $modesym", "$file\n";
6bc89f92 336 }
0a178734 337 else { $STATUS = 1 }
6bc89f92 338}
0a178734 339exit($STATUS)