Commit | Line | Data |
6bc89f92 |
1 | #!perl -w |
2 | |
84c0b84e |
3 | # shasum: filter for computing SHA digests (analogous to sha1sum) |
6bc89f92 |
4 | # |
747da336 |
5 | # Copyright (C) 2003-2007 Mark Shelor, All Rights Reserved |
6bc89f92 |
6 | # |
747da336 |
7 | # Version: 5.45 |
8 | # Tue Jun 26 02:36:00 MST 2007 |
6bc89f92 |
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 |
128cbdba |
24 | -p, --portable read files in portable mode |
cccd5831 |
25 | produces same digest on Windows/Unix/Mac |
6bc89f92 |
26 | -t, --text read files in text mode (default) |
27 | |
28 | The following two options are useful only when verifying checksums: |
29 | |
128cbdba |
30 | -s, --status don't output anything, status code shows success |
6bc89f92 |
31 | -w, --warn warn about improperly formatted SHA checksum lines |
32 | |
128cbdba |
33 | -h, --help display this help and exit |
34 | -v, --version output version information and exit |
6bc89f92 |
35 | |
128cbdba |
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. |
6bc89f92 |
40 | |
747da336 |
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 qw(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 qw(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 | |
6bc89f92 |
62 | =head1 AUTHOR |
63 | |
747da336 |
64 | Copyright (c) 2003-2007 Mark Shelor <mshelor@cpan.org>. |
6bc89f92 |
65 | |
66 | =head1 SEE ALSO |
67 | |
128cbdba |
68 | shasum is implemented using the Perl module L<Digest::SHA> or |
6bc89f92 |
69 | L<Digest::SHA::PurePerl>. |
70 | |
71 | =cut |
72 | |
73 | use strict; |
747da336 |
74 | use FileHandle; |
6bc89f92 |
75 | use Getopt::Long; |
76 | |
747da336 |
77 | my $VERSION = "5.45"; |
6bc89f92 |
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; |
747da336 |
87 | eval "require $module"; |
6bc89f92 |
88 | if ($@) { |
89 | $module = $MOD_SECOND; |
747da336 |
90 | eval "require $module"; |
6bc89f92 |
91 | die "Unable to find $MOD_PREFER or $MOD_SECOND\n" if $@; |
92 | } |
93 | |
94 | |
95 | # Usage statement adapted from Ulrich Drepper's md5sum. |
128cbdba |
96 | # Include an "-a" option for algorithm selection, |
97 | # and a "-p" option for portable digest computation. |
6bc89f92 |
98 | |
99 | sub usage { |
128cbdba |
100 | my($err, $msg) = @_; |
6bc89f92 |
101 | |
128cbdba |
102 | $msg = "" unless defined $msg; |
103 | if ($err) { |
c7e5c266 |
104 | warn($msg . "Type shasum -h for help\n"); |
128cbdba |
105 | exit($err); |
106 | } |
c7e5c266 |
107 | print <<'END_OF_USAGE'; |
6bc89f92 |
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 |
128cbdba |
116 | -p, --portable read files in portable mode |
cccd5831 |
117 | produces same digest on Windows/Unix/Mac |
6bc89f92 |
118 | -t, --text read files in text mode (default) |
119 | |
120 | The following two options are useful only when verifying checksums: |
128cbdba |
121 | -s, --status don't output anything, status code shows success |
6bc89f92 |
122 | -w, --warn warn about improperly formatted SHA checksum lines |
123 | |
128cbdba |
124 | -h, --help display this help and exit |
125 | -v, --version output version information and exit |
6bc89f92 |
126 | |
128cbdba |
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. |
6bc89f92 |
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); |
128cbdba |
141 | my ($portable); |
6bc89f92 |
142 | |
747da336 |
143 | eval { Getopt::Long::Configure ("bundling") }; |
6bc89f92 |
144 | GetOptions( |
128cbdba |
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, ""); |
6bc89f92 |
151 | |
152 | |
153 | # Deal with help requests and incorrect uses |
154 | |
128cbdba |
155 | usage(0) |
156 | if $help; |
84c0b84e |
157 | usage(1, "shasum: Ambiguous file mode\n") |
128cbdba |
158 | if scalar(grep { defined $_ } ($binary, $portable, $text)) > 1; |
c7e5c266 |
159 | usage(1, "shasum: --warn option used only when verifying checksums\n") |
128cbdba |
160 | if $warn && !$check; |
c7e5c266 |
161 | usage(1, "shasum: --status option used only when verifying checksums\n") |
128cbdba |
162 | if $status && !$check; |
6bc89f92 |
163 | |
164 | |
165 | # Default to SHA-1 unless overriden by command line option |
166 | |
167 | $alg = 1 unless $alg; |
128cbdba |
168 | grep { $_ == $alg } (1, 224, 256, 384, 512) |
84c0b84e |
169 | or usage(1, "shasum: Unrecognized algorithm\n"); |
6bc89f92 |
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 |
c7e5c266 |
182 | # explicitly overriden by command line "--text" or |
183 | # "--portable" options. |
6bc89f92 |
184 | |
185 | my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/); |
128cbdba |
186 | if ($isDOSish) { $binary = 1 unless $text || $portable } |
187 | |
c7e5c266 |
188 | my $modesym = $binary ? '*' : ($portable ? '?' : ' '); |
6bc89f92 |
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 { |
dcbcf62d |
199 | my $file = shift; |
6bc89f92 |
200 | |
84c0b84e |
201 | my $mode = $portable ? 'p' : ($binary ? 'b' : ''); |
202 | my $digest = eval { $module->new($alg)->addfile($file, $mode) }; |
203 | if ($@) { |
204 | warn "shasum: $file: $!\n"; |
c7e5c266 |
205 | return; |
206 | } |
c7e5c266 |
207 | |
84c0b84e |
208 | $digest->hexdigest; |
6bc89f92 |
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); |
c7e5c266 |
221 | my ($err, $read_errs, $match_errs) = (0, 0, 0); |
222 | my ($num_files, $num_checksums) = (0, 0); |
747da336 |
223 | my ($fh, $sum, $fname, $rsp, $digest); |
6bc89f92 |
224 | |
84c0b84e |
225 | die "shasum: $checkfile: $!\n" |
747da336 |
226 | unless $fh = FileHandle->new($checkfile, "r"); |
6bc89f92 |
227 | while (<$fh>) { |
228 | s/\s+$//; |
c7e5c266 |
229 | ($sum, $modesym, $fname) = /^(\S+) (.)(.*)$/; |
128cbdba |
230 | ($binary, $portable, $text) = |
c7e5c266 |
231 | map { $_ eq $modesym } ('*', '?', ' '); |
6bc89f92 |
232 | unless ($alg = $len2alg{length($sum)}) { |
dcbcf62d |
233 | warn("shasum: $checkfile: $.: improperly " . |
234 | "formatted SHA checksum line\n") if $warn; |
6bc89f92 |
235 | next; |
236 | } |
c7e5c266 |
237 | $rsp = "$fname: "; $num_files++; |
747da336 |
238 | unless ($digest = sumfile($fname)) { |
dcbcf62d |
239 | $rsp .= "FAILED open or read\n"; |
c7e5c266 |
240 | $err = 1; $read_errs++; |
dcbcf62d |
241 | } |
242 | else { |
c7e5c266 |
243 | $num_checksums++; |
dcbcf62d |
244 | if (lc($sum) eq $digest) { $rsp .= "OK\n" } |
c7e5c266 |
245 | else { $rsp .= "FAILED\n"; $err = 1; $match_errs++ } |
dcbcf62d |
246 | } |
6bc89f92 |
247 | print $rsp unless $status; |
248 | } |
747da336 |
249 | $fh->close; |
c7e5c266 |
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 | } |
6bc89f92 |
256 | exit($err); |
257 | } |
258 | |
259 | |
260 | # Compute and display SHA checksums of requested files |
261 | |
747da336 |
262 | my($file, $digest); |
263 | |
264 | for $file (@ARGV) { |
265 | if ($digest = sumfile($file)) { |
84c0b84e |
266 | print "$digest $modesym", "$file\n"; |
6bc89f92 |
267 | } |
6bc89f92 |
268 | } |