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