Commit | Line | Data |
6bc89f92 |
1 | #!perl -w |
2 | |
3 | # shasum: filter for computing SHA digests (analogous to md5sum) |
4 | # |
77d2a621 |
5 | # Copyright (C) 2003-2006 Mark Shelor, All Rights Reserved |
6bc89f92 |
6 | # |
77d2a621 |
7 | # Version: 5.34 |
8 | # Thu Feb 2 18:55:40 MST 2006 |
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 |
24 | -t, --text read files in text mode (default) |
25 | |
26 | The following two options are useful only when verifying checksums: |
27 | |
28 | --status don't output anything, status code shows success |
29 | -w, --warn warn about improperly formatted SHA checksum lines |
30 | |
31 | --help display this help and exit |
32 | --version output version information and exit |
33 | |
34 | The sums are computed as described in FIPS PUB 180-2. When checking, |
35 | the input should be a former output of this program. The default |
36 | mode is to print a line with checksum, a character indicating type |
37 | (`*' for binary, ` ' for text), and name for each FILE. |
38 | |
39 | =head1 AUTHOR |
40 | |
77d2a621 |
41 | Copyright (c) 2003-2006 Mark Shelor <mshelor@cpan.org>. |
6bc89f92 |
42 | |
43 | =head1 SEE ALSO |
44 | |
45 | Shasum is implemented using the Perl module L<Digest::SHA> or |
46 | L<Digest::SHA::PurePerl>. |
47 | |
48 | =cut |
49 | |
50 | use strict; |
51 | use Getopt::Long; |
52 | |
77d2a621 |
53 | my $VERSION = "5.34"; |
6bc89f92 |
54 | |
55 | |
56 | # Try to use Digest::SHA, since it's faster. If not installed, |
57 | # use Digest::SHA::PurePerl instead. |
58 | |
59 | my $MOD_PREFER = "Digest::SHA"; |
60 | my $MOD_SECOND = "Digest::SHA::PurePerl"; |
61 | |
62 | my $module = $MOD_PREFER; |
63 | eval "require $module"; |
64 | if ($@) { |
65 | $module = $MOD_SECOND; |
66 | eval "require $module"; |
67 | die "Unable to find $MOD_PREFER or $MOD_SECOND\n" if $@; |
68 | } |
69 | |
70 | |
71 | # Usage statement adapted from Ulrich Drepper's md5sum. |
72 | # Include an "-a" option for algorithm selection. |
73 | |
74 | sub usage { |
75 | my($err) = @_; |
76 | |
77 | my $stream = $err ? *STDERR : *STDOUT; |
78 | print $stream <<'END_OF_USAGE'; |
79 | Usage: shasum [OPTION] [FILE]... |
80 | or: shasum [OPTION] --check [FILE] |
81 | Print or check SHA checksums. |
82 | With no FILE, or when FILE is -, read standard input. |
83 | |
84 | -a, --algorithm 1 (default), 224, 256, 384, 512 |
85 | -b, --binary read files in binary mode (default on DOS/Windows) |
86 | -c, --check check SHA sums against given list |
87 | -t, --text read files in text mode (default) |
88 | |
89 | The following two options are useful only when verifying checksums: |
90 | --status don't output anything, status code shows success |
91 | -w, --warn warn about improperly formatted SHA checksum lines |
92 | |
93 | --help display this help and exit |
94 | --version output version information and exit |
95 | |
96 | The sums are computed as described in FIPS PUB 180-2. When checking, |
97 | the input should be a former output of this program. The default |
98 | mode is to print a line with checksum, a character indicating type |
99 | (`*' for binary, ` ' for text), and name for each FILE. |
100 | |
101 | Report bugs to <mshelor@cpan.org>. |
102 | END_OF_USAGE |
103 | exit($err); |
104 | } |
105 | |
106 | |
107 | # Collect options from command line |
108 | |
109 | my ($alg, $binary, $check, $text, $status, $warn, $help, $version); |
110 | |
111 | GetOptions( |
112 | 'binary' => \$binary, 'check' => \$check, |
113 | 'text' => \$text, 'algorithm=i' => \$alg, |
114 | 'status' => \$status, 'warn' => \$warn, |
115 | 'help' => \$help, 'version' => \$version |
116 | ) or usage(1); |
117 | |
118 | |
119 | # Deal with help requests and incorrect uses |
120 | |
121 | usage(0) if $help; |
122 | usage(1) if $binary and $text; |
123 | usage(1) if $warn and not $check; |
124 | usage(1) if $status and not $check; |
125 | |
126 | |
127 | # Default to SHA-1 unless overriden by command line option |
128 | |
129 | $alg = 1 unless $alg; |
130 | grep { $_ == $alg } (1, 224, 256, 384, 512) or usage(1); |
131 | |
132 | |
133 | # Display version information if requested |
134 | |
135 | if ($version) { |
136 | print "$VERSION\n"; |
137 | exit(0); |
138 | } |
139 | |
140 | |
141 | # Try to figure out if the OS is DOS-like. If it is, |
142 | # default to binary mode when reading files, unless |
143 | # explicitly overriden by command line "text" option. |
144 | |
145 | my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/); |
146 | if ($isDOSish) { $binary = 1 unless $text } |
147 | |
148 | |
149 | # Read from STDIN (-) if no files listed on command line |
150 | |
151 | @ARGV = ("-") unless @ARGV; |
152 | |
153 | |
154 | # sumfile($file): computes SHA digest of $file |
155 | |
156 | sub sumfile { |
157 | my($file) = @_; |
158 | my($fh, $digest); |
159 | |
160 | unless (open($fh, "<$file")) { |
161 | print STDERR "shasum: $file: No such file or directory\n"; |
162 | return; |
163 | } |
164 | binmode($fh) if $binary; |
165 | $digest = $module->new($alg)->addfile($fh)->hexdigest; |
166 | close($fh); |
167 | return($digest); |
168 | } |
169 | |
170 | |
171 | # %len2alg: maps hex digest length to SHA algorithm |
172 | |
173 | my %len2alg = (40 => 1, 56 => 224, 64 => 256, 96 => 384, 128 => 512); |
174 | |
175 | |
176 | # Verify checksums if requested |
177 | |
178 | if ($check) { |
179 | my $checkfile = shift(@ARGV); |
180 | my $err = 0; |
181 | my ($fh, $sum, $fname, $rsp); |
182 | |
183 | die "shasum: $checkfile: No such file or directory\n" |
184 | unless open($fh, "<$checkfile"); |
185 | while (<$fh>) { |
186 | s/\s+$//; |
187 | ($sum, $binary, $fname) = /^(\S+)\s+(\*?)(.*)$/; |
188 | unless ($alg = $len2alg{length($sum)}) { |
189 | print STDERR "shasum: $checkfile: $.: improperly ", |
190 | "formatted SHA checksum line\n" if $warn; |
191 | next; |
192 | } |
193 | $rsp = "$fname: "; |
194 | if (lc($sum) eq sumfile($fname)) { $rsp .= "OK\n" } |
195 | else { $rsp .= "FAILED\n"; $err = 1 } |
196 | print $rsp unless $status; |
197 | } |
198 | close($fh); |
199 | exit($err); |
200 | } |
201 | |
202 | |
203 | # Compute and display SHA checksums of requested files |
204 | |
205 | for (@ARGV) { |
206 | if (-d $_) { |
207 | print STDERR "shasum: $_: Is a directory\n"; |
208 | next; |
209 | } |
210 | next unless my $digest = sumfile($_); |
211 | print "$digest ", $binary ? "\*" : " ", "$_\n"; |
212 | } |