reliant-system/tools/reliant-hash
Anderson Rosenberg 73363c8160
dev release
2025-08-26 17:25:16 -04:00

57 lines
1.9 KiB
Bash
Executable file

#!/usr/bin/sh
set -eu
. /usr/local/share/scripts/reliant-common.sh
reliant_print_help() {
echo "usage: $0 [DEVICE]"
echo
echo "Calculates the dense/sparse hash of a given device."
}
# Check the command-line arguments
if [ "$#" -ne 1 ]; then
reliant_fail "invalid number of arguments: expected 1, got $#"
fi
if [ -z "$1" ]; then
reliant_fail "empty device name given"
fi
if [ ! -b "$1" ]; then
reliant_fail "$1 is not a valid block device"
fi
# Gather data about the device
device=$1
size_bytes=$(blockdev --getsize64 "$device" 2>/dev/null || echo 0)
if [ "$size_bytes" -eq 0 ]; then
reliant_fail "cannot determine the size of $device"
fi
size_mb=$((size_bytes / 1048576))
# Devices under 1 GiB can be densely hashed
if [ "$size_mb" -le 1024 ]; then
# Sample whole device
hash=$(dd if="$device" bs=1M 2>/dev/null | md5sum | cut -d' ' -f1)
echo "${device}:${size_bytes}=dense:${hash}"
else
# Sparse hashing necessary for larger devices
# Sample start and end
start_hash=$(dd if="$device" bs=1M count=1024 2>/dev/null | md5sum | cut -d' ' -f1)
end_hash=$(dd if="$device" bs=1M count=1024 skip=$((size_mb - 1024)) 2>/dev/null | md5sum | cut -d' ' -f1)
# Sample at size-dependent interval
sample_hashes=""
sample_interval=$((size_mb / RELIANT_SPARSE_SAMPLES))
sample_offset=$sample_interval
while [ $sample_offset -lt $((size_mb - sample_interval)) ]; do
sample_hash=$(dd if="$device" bs=1M skip=$sample_offset count=1 2>/dev/null | md5sum | cut -d' ' -f1)
sample_hashes="${sample_hashes}${sample_offset}=${sample_hash} "
sample_offset=$((sample_offset + sample_interval))
done
# Combine hashes
hash_string="$start_hash;$sample_hashes;$end_hash"
hash=$(echo "$hash_string" | md5sum | cut -d' ' -f1)
# Done
echo "${device}:${size_bytes}=sparse${RELIANT_SPARSE_SAMPLES}:${hash}"
fi