#!/usr/bin/env bash # # @license Apache-2.0 # # Copyright (c) 2017 The Stdlib Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Verify the checksum of one or more files. # # Usage: checksum ... # # Arguments: # # filepath File to verify. # hash Expected checksum. # # shellcheck disable=SC2181 # VARIABLES # # Checksum type: checksum_type='sha256' # Program used to compute a checksum: checksum_program= # Command to compute a checksum: cmd= # FUNCTIONS # # Prints usage information. usage() { echo '' >&2 echo 'Usage: checksum ...' >&2 echo '' >&2 } # Defines an error handler. # # $1 - error status on_error() { echo 'ERROR: An error was encountered during execution.' >&2 cleanup exit "$1" } # Runs clean-up tasks. cleanup() { echo '' >&2 } # Prints a success message. print_success() { echo 'Success.' >&2 } # Prints a checksum. # # $1 - checksum print_checksum() { local num_lines local width local lines local str local len local pos width=64 # characters len="${#1}" if [[ "${len}" -gt "${width}" ]]; then str="$1" num_lines=$((len / width)) # floored lines=$(seq 0 1 "${num_lines}") # total_lines = num_lines + 1 for i in ${lines}; do pos=$((i * width)) echo " ${str:${pos}:${width}}" done else echo " $1" >&2 fi } # Prints a checksum error. # # $1 - file # $2 - checksum type # $3 - checksum program # $4 - expected checksum # $5 - actual checksum print_checksum_error() { echo '' >&2 echo "ERROR: $2 checksum failure for $1. Expected:" >&2 echo '' >&2 print_checksum "$4" echo '' >&2 echo "But \`$3\` results in:" >&2 echo '' >&2 print_checksum "$5" echo '' >&2 echo "This may be due to bad downloads or network proxies. Check your network proxy/" >&2 echo "firewall settings and try downloading and verifying again." >&2 echo '' >&2 } # Verifies a checksum. # # $1 - file # $2 - expected checksum verify() { local curr_checksum curr_checksum=$(eval "${cmd} $1 | awk '{ print \$1; }'") if [[ "${curr_checksum}" != "$2" ]]; then print_checksum_error "$1" "${checksum_type}" "${checksum_program}" "$2" "${curr_checksum}" return 1 fi return 0 } # Main execution sequence. main() { local args local len args=("$@") len="${#args[@]}" for (( i=0; i<${len}; i+=2 )) ; do verify "${args[i]}" "${args[i+1]}" if [[ "$?" -ne 0 ]]; then on_error 1 fi done print_success cleanup exit 0 } # MAIN # # Handle arguments... if [[ "$#" -eq 0 ]]; then usage exit 0 elif [[ $(($#%2)) -eq 1 ]]; then echo 'ERROR: invalid arguments. Each file to verify must be followed by an expected checksum.' >&2 exit 1 fi # Find a program for computing a SHA256 checksum... if [[ -n "$(command -v sha256sum)" ]]; then checksum_program="sha256sum" cmd='sha256sum' elif [[ -n "$(command -v shasum)" ]]; then checksum_program="shasum" cmd='shasum -a 256' fi # Run main: main "$@"