#!/bin/bash # (c) 2015 Helge Jung # # This script is controlled by environment variables, # only the first being mandatory: # # CANDIDATE = directory in which to find the to-be-checked firmware images # REFERENCE = directory of your build firmware, defaults to './src/images' # MANIFEST = if given, use files referenced in Gluon manifest file # if left empty (unset), 'find' is used to examine all '.bin' files # VERBOSE = 0 (default) or 1, putting lots of debug output # MY_DIR=$(dirname $0) MY_DIR=$(readlink -f "$MY_DIR") pushd "$MY_DIR" > /dev/null . functions.sh # check for necessary tools for tool in bbe binwalk find gawk unsquashfs; do [ -x "$(which $tool)" ] || abort "Missing necessary tool '$tool'." done # check that CANDIDATE dir is given and existing [ "_$CANDIDATE" == "_" ] && abort "Please specify CANDIDATE environment variable point to the directory of to-be-checked firmware images." [ ! -d "$CANDIDATE" ] && abort "The directory indicated by CANDIDATE was not found." CANDIDATE=$(readlink -f $CANDIDATE) # set defaults for environment variables [ -n "${REFERENCE}" ] || REFERENCE="./src/images" if [ "_$VERBOSE" == "_1" ]; then VERBOSE=1; else VERBOSE=0; fi # assemble file list declare -a FILELIST if [ -n "$MANIFEST" ]; then progress "Assembling file list from manifest file ..." FILELIST=() else [ ! -d "$REFERENCE" ] && abort "The REFERENCE directory was not found. Have you built the firmware?" REFERENCE=$(readlink -f $REFERENCE) progress "Assembling file list ..." FILELIST=($(find "$REFERENCE" -type f -name "*.bin")) fi COUNT=${#FILELIST[*]} [ "$COUNT" = 0 ] && abort "No firmware files found. Please check that you built software in the REFERENCE dir." info "Need to check $COUNT files." # setup temp dir for checking TEMPDIR=$(mktemp -d) debug "Temporary dir = $TEMPDIR" # check each file IDX=0 declare -a ERRORS filter_timestamp() { file=$1 cp "$file" "$file.orig" egrep -ao '(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} UTC [0-9]{4}' "$file" | sort -u | while read ts; do debug "Normalizing timestamp: '$ts'" bbe -e "s/$ts/Abc Def 12 34:56:78 UTC 9010/" -o "${file}" "${file}.orig" done } for ref in ${FILELIST[*]}; do IDX=$(($IDX + 1)) NAME=`basename "$ref"` [ $VERBOSE -eq 1 ] && progress "[${IDX}/${COUNT}] $NAME" if [ ! -r "$ref" ]; then ERRORS=( "${ERRORS[@]}" "$NAME: missing reference file ($ref)" ) continue fi cand=$(readlink -f "${CANDIDATE}/${NAME}") if [ ! -r "$cand" ]; then ERRORS=( "${ERRORS[@]}" "$NAME: missing candidate file in $CANDIDATE" ) continue fi pushd "$TEMPDIR" > /dev/null rm -Rf candidate ; mkdir candidate rm -Rf reference ; mkdir reference # TODO: check output of binwalk that there are only the two expected parts cd candidate binwalk -qe "$cand" 2>/dev/null cd ../reference binwalk -qe "$ref" 2>/dev/null cd .. # check ROM part debug "Filtering timestamps in ROM part (uboot+kernel) ..." filter_timestamp candidate/200 filter_timestamp reference/200 hash_rom_cand=$(sha512sum candidate/200) hash_rom_ref=$(sha512sum reference/200) if [ "$hash_rom_cand" != "$hash_rom_ref" ]; then ERRORS=( "${ERRORS[@]}" "$NAME: ROM part mismatch" ) debug "Calling vbindiff for your visual pleasure." vbindiff reference/200 candidate/200 fi # extract root filesystem for dir in candidate reference; do cd $dir unsquashfs -n -f *.squashfs > /dev/null cd .. done fsdiff=$(diff -ur reference/squashfs-root candidate/squashfs-root 2>&1) # TODO: intelligent diff statt 'diff -r', Verhalten abhängig vom Dateinamen # squashfs-root/usr/lib/opkg/info/*.list: erst sortieren, dann diffen # squashfs-root/usr/lib/opkg/info/*.control: Unterschied in "Installed Size" ignorieren (kommt vermutlich durch unterschiedliche Reihenfolge und Block-Alignments?) # squashfs-root/usr/lib/opkg/status: Delta in "Installed-Time: " Zeilen ignorieren # squashfs-root/usr/lib/lua/luci/version.lua: neoraider/openwrt hauen, die Änderung im luciversion-String kommt durch manuelles git patching # else: binary file compare, sha512sum if [ "$?" -ne 0 ]; then ERRORS=( "${ERRORS[@]}" "$NAME: Filesystems do not match" ) echo $fsdiff | less fi popd > /dev/null done rm -R "$TEMPDIR" # check if everything was fine - if yes, exit clean+smooth if [ ${#ERRORS[*]} -eq 0 ]; then success "Everything OK, what a nice and lovely built firmware \o/" exit 0 fi # got some errors - output them for errmsg in "${ERRORS[@]}"; do echo $errmsg done abort "Firmware check failed, see above :("