check.sh 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #!/bin/bash
  2. # (c) 2015 Helge Jung <hej@c3pb.de>
  3. #
  4. # This script is controlled by environment variables,
  5. # only the first being mandatory:
  6. #
  7. # CANDIDATE = directory in which to find the to-be-checked firmware images
  8. # REFERENCE = directory of your build firmware, defaults to './src/images'
  9. # MANIFEST = if given, use files referenced in Gluon manifest file
  10. # if left empty (unset), 'find' is used to examine all '.bin' files
  11. # VERBOSE = 0 (default) or 1, putting lots of debug output
  12. #
  13. MY_DIR=$(dirname $0)
  14. MY_DIR=$(readlink -f "$MY_DIR")
  15. pushd "$MY_DIR" > /dev/null
  16. . functions.sh
  17. # check for necessary tools
  18. for tool in bbe binwalk find gawk unsquashfs; do
  19. [ -x "$(which $tool)" ] || abort "Missing necessary tool '$tool'."
  20. done
  21. # check that CANDIDATE dir is given and existing
  22. [ "_$CANDIDATE" == "_" ] && abort "Please specify CANDIDATE environment variable point to the directory of to-be-checked firmware images."
  23. [ ! -d "$CANDIDATE" ] && abort "The directory indicated by CANDIDATE was not found."
  24. CANDIDATE=$(readlink -f $CANDIDATE)
  25. # set defaults for environment variables
  26. [ -n "${REFERENCE}" ] || REFERENCE="./src/images"
  27. if [ "_$VERBOSE" == "_1" ]; then VERBOSE=1; else VERBOSE=0; fi
  28. # assemble file list
  29. declare -a FILELIST
  30. if [ -n "$MANIFEST" ]; then
  31. progress "Assembling file list from manifest file ..."
  32. FILELIST=()
  33. else
  34. [ ! -d "$REFERENCE" ] && abort "The REFERENCE directory was not found. Have you built the firmware?"
  35. REFERENCE=$(readlink -f $REFERENCE)
  36. progress "Assembling file list ..."
  37. FILELIST=($(find "$REFERENCE" -type f -name "*.bin"))
  38. fi
  39. COUNT=${#FILELIST[*]}
  40. [ "$COUNT" = 0 ] && abort "No firmware files found. Please check that you built software in the REFERENCE dir."
  41. info "Need to check $COUNT files."
  42. # setup temp dir for checking
  43. TEMPDIR=$(mktemp -d)
  44. debug "Temporary dir = $TEMPDIR"
  45. # check each file
  46. IDX=0
  47. declare -a ERRORS
  48. filter_timestamp() {
  49. file=$1
  50. cp "$file" "$file.orig"
  51. 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
  52. debug "Normalizing timestamp: '$ts'"
  53. bbe -e "s/$ts/Abc Def 12 34:56:78 UTC 9010/" -o "${file}" "${file}.orig"
  54. done
  55. }
  56. for ref in ${FILELIST[*]}; do
  57. IDX=$(($IDX + 1))
  58. NAME=`basename "$ref"`
  59. [ $VERBOSE -eq 1 ] && progress "[${IDX}/${COUNT}] $NAME"
  60. if [ ! -r "$ref" ]; then
  61. ERRORS=( "${ERRORS[@]}" "$NAME: missing reference file ($ref)" )
  62. continue
  63. fi
  64. cand=$(readlink -f "${CANDIDATE}/${NAME}")
  65. if [ ! -r "$cand" ]; then
  66. ERRORS=( "${ERRORS[@]}" "$NAME: missing candidate file in $CANDIDATE" )
  67. continue
  68. fi
  69. pushd "$TEMPDIR" > /dev/null
  70. rm -Rf candidate ; mkdir candidate
  71. rm -Rf reference ; mkdir reference
  72. # TODO: check output of binwalk that there are only the two expected parts
  73. cd candidate
  74. binwalk -qe "$cand" 2>/dev/null
  75. cd ../reference
  76. binwalk -qe "$ref" 2>/dev/null
  77. cd ..
  78. # check ROM part
  79. debug "Filtering timestamps in ROM part (uboot+kernel) ..."
  80. filter_timestamp candidate/200
  81. filter_timestamp reference/200
  82. hash_rom_cand=$(sha512sum candidate/200)
  83. hash_rom_ref=$(sha512sum reference/200)
  84. if [ "$hash_rom_cand" != "$hash_rom_ref" ]; then
  85. ERRORS=( "${ERRORS[@]}" "$NAME: ROM part mismatch" )
  86. debug "Calling vbindiff for your visual pleasure."
  87. vbindiff reference/200 candidate/200
  88. fi
  89. # extract root filesystem
  90. for dir in candidate reference; do
  91. cd $dir
  92. unsquashfs -n -f *.squashfs > /dev/null
  93. cd ..
  94. done
  95. fsdiff=$(diff -ur reference/squashfs-root candidate/squashfs-root 2>&1)
  96. # TODO: intelligent diff statt 'diff -r', Verhalten abhängig vom Dateinamen
  97. # squashfs-root/usr/lib/opkg/info/*.list: erst sortieren, dann diffen
  98. # squashfs-root/usr/lib/opkg/info/*.control: Unterschied in "Installed Size" ignorieren (kommt vermutlich durch unterschiedliche Reihenfolge und Block-Alignments?)
  99. # squashfs-root/usr/lib/opkg/status: Delta in "Installed-Time: " Zeilen ignorieren
  100. # squashfs-root/usr/lib/lua/luci/version.lua: neoraider/openwrt hauen, die Änderung im luciversion-String kommt durch manuelles git patching
  101. # else: binary file compare, sha512sum
  102. if [ "$?" -ne 0 ]; then
  103. ERRORS=( "${ERRORS[@]}" "$NAME: Filesystems do not match" )
  104. echo $fsdiff | less
  105. fi
  106. popd > /dev/null
  107. done
  108. rm -R "$TEMPDIR"
  109. # check if everything was fine - if yes, exit clean+smooth
  110. if [ ${#ERRORS[*]} -eq 0 ]; then
  111. success "Everything OK, what a nice and lovely built firmware \o/"
  112. exit 0
  113. fi
  114. # got some errors - output them
  115. for errmsg in "${ERRORS[@]}"; do
  116. echo $errmsg
  117. done
  118. abort "Firmware check failed, see above :("