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