This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade to Digest-SHA-5.44.
[perl5.git] / ext / Digest / SHA / bin / shasum
1 #!perl -w
2
3         # shasum: filter for computing SHA digests (analogous to sha1sum)
4         #
5         # Copyright (C) 2003-2006 Mark Shelor, All Rights Reserved
6         #
7         # Version: 5.44
8         # Sat Oct 14 00:42:44 MST 2006
9
10 =head1 NAME
11
12 shasum - Print or Check SHA Checksums
13
14 =head1 SYNOPSIS
15
16  Usage: shasum [OPTION] [FILE]...
17     or: shasum [OPTION] --check [FILE]
18  Print or check SHA checksums.
19  With no FILE, or when FILE is -, read standard input.
20
21   -a, --algorithm    1 (default), 224, 256, 384, 512
22   -b, --binary       read files in binary mode (default on DOS/Windows)
23   -c, --check        check SHA sums against given list
24   -p, --portable     read files in portable mode
25                          produces same digest on Windows/Unix/Mac
26   -t, --text         read files in text mode (default)
27
28  The following two options are useful only when verifying checksums:
29
30   -s, --status       don't output anything, status code shows success
31   -w, --warn         warn about improperly formatted SHA checksum lines
32
33   -h, --help         display this help and exit
34   -v, --version      output version information and exit
35
36  The sums are computed as described in FIPS PUB 180-2.  When checking,
37  the input should be a former output of this program.  The default mode
38  is to print a line with checksum, a character indicating type (`*'
39  for binary, `?' for portable, ` ' for text), and name for each FILE.
40
41 =head1 AUTHOR
42
43 Copyright (c) 2003-2006 Mark Shelor <mshelor@cpan.org>.
44
45 =head1 SEE ALSO
46
47 shasum is implemented using the Perl module L<Digest::SHA> or
48 L<Digest::SHA::PurePerl>.
49
50 =cut
51
52 use strict;
53 use Getopt::Long;
54
55 my $VERSION = "5.44";
56
57
58         # Try to use Digest::SHA, since it's faster.  If not installed,
59         # use Digest::SHA::PurePerl instead.
60
61 my $MOD_PREFER = "Digest::SHA";
62 my $MOD_SECOND = "Digest::SHA::PurePerl";
63
64 my $module = $MOD_PREFER;
65 eval "require $module";                 ## no critic
66 if ($@) {
67         $module = $MOD_SECOND;
68         eval "require $module";         ## no critic
69         die "Unable to find $MOD_PREFER or $MOD_SECOND\n" if $@;
70 }
71
72
73         # Usage statement adapted from Ulrich Drepper's md5sum.
74         # Include an "-a" option for algorithm selection,
75         # and a "-p" option for portable digest computation.
76
77 sub usage {
78         my($err, $msg) = @_;
79
80         $msg = "" unless defined $msg;
81         if ($err) {
82                 warn($msg . "Type shasum -h for help\n");
83                 exit($err);
84         }
85         print <<'END_OF_USAGE';
86 Usage: shasum [OPTION] [FILE]...
87    or: shasum [OPTION] --check [FILE]
88 Print or check SHA checksums.
89 With no FILE, or when FILE is -, read standard input.
90
91   -a, --algorithm    1 (default), 224, 256, 384, 512
92   -b, --binary       read files in binary mode (default on DOS/Windows)
93   -c, --check        check SHA sums against given list
94   -p, --portable     read files in portable mode
95                          produces same digest on Windows/Unix/Mac
96   -t, --text         read files in text mode (default)
97
98 The following two options are useful only when verifying checksums:
99   -s, --status       don't output anything, status code shows success
100   -w, --warn         warn about improperly formatted SHA checksum lines
101
102   -h, --help         display this help and exit
103   -v, --version      output version information and exit
104
105 The sums are computed as described in FIPS PUB 180-2.  When checking, the
106 input should be a former output of this program.  The default mode is to
107 print a line with checksum, a character indicating type (`*' for binary,
108 `?' for portable, ` ' for text), and name for each FILE.
109
110 Report bugs to <mshelor@cpan.org>.
111 END_OF_USAGE
112         exit($err);
113 }
114
115
116         # Collect options from command line
117
118 my ($alg, $binary, $check, $text, $status, $warn, $help, $version);
119 my ($portable);
120
121 Getopt::Long::Configure ("bundling");
122 GetOptions(
123         'b|binary' => \$binary, 'c|check' => \$check,
124         't|text' => \$text, 'a|algorithm=i' => \$alg,
125         's|status' => \$status, 'w|warn' => \$warn,
126         'h|help' => \$help, 'v|version' => \$version,
127         'p|portable' => \$portable
128 ) or usage(1, "");
129
130
131         # Deal with help requests and incorrect uses
132
133 usage(0)
134         if $help;
135 usage(1, "shasum: Ambiguous file mode\n")
136         if scalar(grep { defined $_ } ($binary, $portable, $text)) > 1;
137 usage(1, "shasum: --warn option used only when verifying checksums\n")
138         if $warn && !$check;
139 usage(1, "shasum: --status option used only when verifying checksums\n")
140         if $status && !$check;
141
142
143         # Default to SHA-1 unless overriden by command line option
144
145 $alg = 1 unless $alg;
146 grep { $_ == $alg } (1, 224, 256, 384, 512)
147         or usage(1, "shasum: Unrecognized algorithm\n");
148
149
150         # Display version information if requested
151
152 if ($version) {
153         print "$VERSION\n";
154         exit(0);
155 }
156
157
158         # Try to figure out if the OS is DOS-like.  If it is,
159         # default to binary mode when reading files, unless
160         # explicitly overriden by command line "--text" or
161         # "--portable" options.
162
163 my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/);
164 if ($isDOSish) { $binary = 1 unless $text || $portable }
165
166 my $modesym = $binary ? '*' : ($portable ? '?' : ' ');
167
168
169         # Read from STDIN (-) if no files listed on command line
170
171 @ARGV = ("-") unless @ARGV;
172
173
174         # sumfile($file): computes SHA digest of $file
175
176 sub sumfile {
177         my $file = shift;
178
179         my $mode = $portable ? 'p' : ($binary ? 'b' : '');
180         my $digest = eval { $module->new($alg)->addfile($file, $mode) };
181         if ($@) {
182                 warn "shasum: $file: $!\n";
183                 return;
184         }
185
186         $digest->hexdigest;
187 }
188
189
190         # %len2alg: maps hex digest length to SHA algorithm
191
192 my %len2alg = (40 => 1, 56 => 224, 64 => 256, 96 => 384, 128 => 512);
193
194
195         # Verify checksums if requested
196
197 if ($check) {
198         my $checkfile = shift(@ARGV);
199         my ($err, $read_errs, $match_errs) = (0, 0, 0);
200         my ($num_files, $num_checksums) = (0, 0);
201         my ($fh, $sum, $fname, $rsp);
202
203         die "shasum: $checkfile: $!\n"
204                 unless open($fh, "<$checkfile");        ## no critic
205         while (<$fh>) {
206                 s/\s+$//;
207                 ($sum, $modesym, $fname) = /^(\S+) (.)(.*)$/;
208                 ($binary, $portable, $text) =
209                         map { $_ eq $modesym } ('*', '?', ' ');
210                 unless ($alg = $len2alg{length($sum)}) {
211                         warn("shasum: $checkfile: $.: improperly " .
212                                 "formatted SHA checksum line\n") if $warn;
213                         next;
214                 }
215                 $rsp = "$fname: "; $num_files++;
216                 unless (my $digest = sumfile($fname)) {
217                         $rsp .= "FAILED open or read\n";
218                         $err = 1; $read_errs++;
219                 }
220                 else {
221                         $num_checksums++;
222                         if (lc($sum) eq $digest) { $rsp .= "OK\n" }
223                         else { $rsp .= "FAILED\n"; $err = 1; $match_errs++ }
224                 }
225                 print $rsp unless $status;
226         }
227         close($fh);
228         unless ($status) {
229                 warn("shasum: WARNING: $read_errs of $num_files listed " .
230                         "files could not be read\n") if $read_errs;
231                 warn("shasum: WARNING: $match_errs of $num_checksums " .
232                         "computed checksums did NOT match\n") if $match_errs;
233         }
234         exit($err);
235 }
236
237
238         # Compute and display SHA checksums of requested files
239
240 for my $file (@ARGV) {
241         if (my $digest = sumfile($file)) {
242                 print "$digest $modesym", "$file\n";
243         }
244 }