9cb421c16f
The hash files do not use trailing backslash \ to continue lines, so we don't want them to be interpreted thusly, so we use 'read -r' (SC2162). The h_file is used twice in the same loop, once for reading from it, and once just to print it, so there is no conflict (SC2094). Integrer variables need not be quoted (SC2086). In any case, should there be an actual issue and they be set empty, that would cause a runtime issue, wether they be quoted or not. Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
116 lines
3.4 KiB
Bash
Executable File
116 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
# Helper to check a file matches its known hash
|
|
# Call it with:
|
|
# $1: the full path to the temporary file that was downloaded, and
|
|
# that is to be checked
|
|
# $2: the final basename of the file, to which it will be ultimately
|
|
# saved as, to be able to match it to the corresponding hashes
|
|
# in the .hash file
|
|
# $*: the paths of the files containing all the expected hashes
|
|
#
|
|
# Exit codes:
|
|
# 0: the hash file exists and the file to check matches all its hashes,
|
|
# or the hash file does not exist
|
|
# 1: unknown command-line option
|
|
# 2: the hash file exists and the file to check does not match at least
|
|
# one of its hashes
|
|
# 3: the hash file exists and there was no hash to check the file against
|
|
# 4: the hash file exists and at least one hash type is unknown
|
|
|
|
while getopts :q OPT; do
|
|
case "${OPT}" in
|
|
q) exec >/dev/null;;
|
|
\?) exit 1;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
|
|
file="${1}"
|
|
base="${2}"
|
|
shift 2
|
|
declare -a h_files=( "${@}" )
|
|
|
|
# Check one hash for a file
|
|
# $1: algo hash
|
|
# $2: known hash
|
|
# $3: file (full path)
|
|
# $4: hash file (full path)
|
|
check_one_hash() {
|
|
_h="${1}"
|
|
_known="${2}"
|
|
_file="${3}"
|
|
_h_file="${4}"
|
|
|
|
# Note: md5 is supported, but undocumented on purpose.
|
|
# Note: sha3 is not supported, since there is currently no implementation
|
|
# (the NIST has yet to publish the parameters).
|
|
case "${_h}" in
|
|
md5|sha1) ;;
|
|
sha224|sha256|sha384|sha512) ;;
|
|
*) # Unknown hash, exit with error
|
|
printf "ERROR: unknown hash '%s' for '%s'\n" \
|
|
"${_h}" "${base}" >&2
|
|
exit 4
|
|
;;
|
|
esac
|
|
|
|
# Do the hashes match?
|
|
_hash="$( "${_h}sum" "${_file}" |cut -d ' ' -f 1 )"
|
|
if [ "${_hash}" = "${_known}" ]; then
|
|
printf "%s: OK (%s: %s)\n" "${base}" "${_h}" "${_hash}"
|
|
return 0
|
|
fi
|
|
|
|
printf "ERROR: while checking hashes from %s\n" "${_h_file}" >&2
|
|
printf "ERROR: %s has wrong %s hash:\n" "${base}" "${_h}" >&2
|
|
printf "ERROR: expected: %s\n" "${_known}" >&2
|
|
printf "ERROR: got : %s\n" "${_hash}" >&2
|
|
printf "ERROR: Incomplete download, or man-in-the-middle (MITM) attack\n" >&2
|
|
|
|
exit 2
|
|
}
|
|
|
|
# Do we know one or more hashes for that file?
|
|
nb_h_files=0
|
|
nb_checks=0
|
|
for h_file in "${h_files[@]}"; do
|
|
[ -f "${h_file}" ] || continue
|
|
: $((nb_h_files++))
|
|
# shellcheck disable=SC2094 # we're really reading it only once
|
|
while read -r t h f; do
|
|
case "${t}" in
|
|
''|'#'*)
|
|
# Skip comments and empty lines
|
|
continue
|
|
;;
|
|
*)
|
|
if [ "${f}" = "${base}" ]; then
|
|
# shellcheck disable=SC2094 # we're only printing the h_file filename
|
|
check_one_hash "${t}" "${h}" "${file}" "${h_file}"
|
|
: $((nb_checks++))
|
|
fi
|
|
;;
|
|
esac
|
|
done <"${h_file}"
|
|
done
|
|
|
|
# shellcheck disable=SC2086 # nb_h_files is a non-empty int
|
|
if [ ${nb_h_files} -eq 0 ]; then
|
|
printf "WARNING: no hash file for %s\n" "${base}" >&2
|
|
exit 0
|
|
fi
|
|
|
|
# shellcheck disable=SC2086 # nb_checks is a non-empty int
|
|
if [ ${nb_checks} -eq 0 ]; then
|
|
case " ${BR_NO_CHECK_HASH_FOR} " in
|
|
*" ${base} "*)
|
|
# File explicitly has no hash
|
|
exit 0
|
|
;;
|
|
esac
|
|
printf "ERROR: No hash found for %s\n" "${base}" >&2
|
|
exit 3
|
|
fi
|