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