Last active
November 21, 2022 01:55
-
-
Save killerbees19/3b8ea25c5ca4b473624de6c8a567ebe5 to your computer and use it in GitHub Desktop.
Recursive MD5/SHA1/SHA256/SHA512 checksum validator for TrueNAS CORE (or any other *BSD operating system)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# cs@fnx.li (2022-05-31) | |
### | |
# License: GNU General Public License v3.0 | |
# Source: https://gist.github.com/3b8ea25c5ca4b473624de6c8a567ebe5 | |
### | |
set -o pipefail | |
function usage() | |
{ | |
cat << EOF >&2 | |
Usage: $0 ALGO FILE|DIR ... | |
Checks lines of FILEs and/or searches checksum files in DIRs. | |
It is a nice recursive checksum implementation for TrueNAS CORE. | |
Should be compatible with any *BSD system. (Linux unsupported!) | |
Supported ALGOrithms: | |
md5 sha1 sha256 sha512 | |
Supported checksum filenames in DIRs: | |
*.ALGO *.ALGOsum *.ALGOsums ALGOsum ALGOsums | |
Supported checksum format: | |
CHECKSUM FILENAME | |
2 spaces between CHECKSUM and FILENAME! | |
Checksum must be a hex-string. (0-9 & A-F) | |
Output messages: | |
STDOUT (1) - Processed filenames and directories. | |
STDERR (2) - Command errors and failed checksums. | |
Use output redirection to suppress something: | |
$(basename "$0") >/dev/null # hide progress | |
$(basename "$0") 2>/dev/null # hide errors | |
$(basename "$0") &>/dev/null # no output | |
Return codes: | |
0 - OK (checksums matched) | |
> 0 - ERROR (see STDERR output) | |
-- $(head -n 2 "$0" | tail -n 1 | cut -b 3-) | |
EOF | |
exit 2 | |
} | |
function check() | |
{ | |
method=${1,,} | |
case "$method" | |
in | |
md5) | |
l=32 | |
;; | |
sha1) | |
l=40 | |
;; | |
sha256) | |
l=64 | |
;; | |
sha512) | |
l=128 | |
;; | |
*) | |
echo "Invalid algorithm: $method" >&2 | |
return 1 | |
;; | |
esac | |
state=0 | |
path=$(readlink -f "$2") | |
while IFS= read -r line | |
do | |
sum=${line:0:l} | |
file=${line:l+2} | |
# shellcheck disable=SC2015 | |
[[ -n "$file" && "$sum" =~ ^[0-9A-Fa-f]+$ ]] \ | |
&& echo "Checking file: [$2] $file" \ | |
&& "$method" -c "$sum" "$file" &>/dev/null \ | |
|| \ | |
{ | |
state=1 | |
echo "Failed: [$path] $line" | |
} >&2 | |
done < "$2" | |
return $state | |
} | |
function status() | |
{ | |
[[ "$status" -ne 0 && "$HC_INTERNAL" -ne 1337 ]] && echo -e "\nFAILED!" >&2 | |
[[ "$status" -ne 0 || "$finished" -eq 1 ]] && exit "$status" | |
exit 1 | |
} | |
if [[ $# -lt 2 ]] | |
then | |
usage | |
fi | |
algo=${1,,} | |
shift | |
case "$algo" | |
in | |
md5|sha1|sha256|sha512) | |
;; | |
*) | |
usage | |
;; | |
esac | |
status=0 | |
finished=0 | |
trap status EXIT INT TERM | |
for realinput in "$@" | |
do | |
input=$(readlink -f "$realinput") | |
if [[ -n "$input" && -e "$realinput" ]] | |
then | |
if [[ -f "$input" ]] | |
then | |
echo "Checking file: [$input]" | |
check "$algo" "$input" && continue | |
elif [[ -d "$input" ]] | |
then | |
echo "Checking directory: $input" | |
# shellcheck disable=SC2016 | |
find "$input" \ | |
-type f \ | |
\( \ | |
-iname "*.$algo" -o \ | |
-iname "*.${algo}sum" -o \ | |
-iname "*.${algo}sums" -o \ | |
-iname "${algo}sum" -o \ | |
-iname "${algo}sums" \ | |
\) \ | |
-print0 \ | |
| xargs -0 -n1 bash -c 'cd "$(dirname "$0")" && HC_INTERNAL=1337 '"$(printf '%q %q' "$0" "$algo")"' "$0" || exit 1' \ | |
&& continue | |
fi | |
fi | |
{ | |
status=1 | |
[[ -n "$input" ]] \ | |
&& echo "Failed: [$input]" \ | |
|| echo "Failed: [$realinput]" | |
} >&2 | |
done | |
finished=1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment