Skip to content

Instantly share code, notes, and snippets.

@killerbees19
Last active November 21, 2022 01:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save killerbees19/3b8ea25c5ca4b473624de6c8a567ebe5 to your computer and use it in GitHub Desktop.
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)
#!/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